Check user name availability from firebase in react - javascript

I am currently stuck on checking unique username in the sign up(on firebase) in react. My goal is that
1. when the user input the username, the function checkNameAvalaible go to the firebase database and check if the name exists.
2.if the name exists set the state of usernameavalaible to false, and set it to true if name works
3.disable the submit button of the sign up if the usernameavalaible is false.
4.If the username is taken, use helper text in textfield to alert the current user.
I am stuck with the if statement, I tried a few times and it is not working here is my code
import React, { Component } from "react";
import { Link } from "react-router-dom";
import { auth } from "../firebase";
import { db} from "../firebase";
import "./auth.css";
import * as routes from "../constants/routes";
import { SignInLink } from "./SignIn";
import TextField from "#material-ui/core/TextField";
import Button from "#material-ui/core/Button";
const SignUpPage = ({ history }) => (
<div align="center" className="SignUpBox">
<h1>SignUp</h1>
<SignUpForm history={history} />
<SignInLink />
</div>
);
const INITIAL_STATE = {
username: "",
name: "",
email: "",
passwordOne: "",
passwordTwo: "",
error: null
};
const byPropKey = (propertyName, value) => () => ({
[propertyName]: value
});
class SignUpForm extends Component {
state = { ...INITIAL_STATE };
// checkPassword() {
// if(!this.state.passwordOne || this.state.passwordOne !== this.state.passwordTwo){
// this.setState({error:"passwords do not match"});
// }
// else {
// this.setState({error:null});
// }
// }
onSubmit = event => {
event.preventDefault();
const { email, passwordOne, name, username } = this.state;
auth
.doCreateUserWithEmailAndPassword(
email,
passwordOne,
name,
username
)
.then(authUser => {
this.setState(() => ({ ...INITIAL_STATE }));
this.props.history.push(routes.HOME);
})
.catch(error => {
this.setState(byPropKey("error", error));
});
};
render() {
var usernameAvalaible
const {
username,
name,
email,
passwordOne,
passwordTwo,
error
} = this.state;
checkNameAvalaible(){
if (db.doc(`/users/${username}`).get().exists){
this.setState{usernameAvalaible:false};
}
else{
this.setState{usernameAvalaible:true};
}
};
const isInvalid =
passwordOne !== passwordTwo ||
passwordOne === "" ||
email === "" ||
name === "" ||
username === ""|| usernameAvalaible===false;
return (
<form onSubmit={this.onSubmit}>
<TextField
name="Username"
id="standard-secondary"
label="User name"
color="primary"
value={username}
onChange={event =>
this.setState(byPropKey("username", event.target.value))
}
type="text"
/>
<TextField
name="name"
value={name}
id="standard-secondary"
label="Full name"
color="primary"
onChange={event =>
this.setState(byPropKey("name", event.target.value))
}
type="text"
/>
<TextField
name="email"
value={email}
id="standard-secondary"
label="Email Address"
color="primary"
onChange={event =>
this.setState(byPropKey("email", event.target.value))
}
type="email"
/>
<TextField
name="password"
value={passwordOne}
id="standard-secondary"
label="Password"
color="primary"
onChange={event =>
this.setState(byPropKey("passwordOne", event.target.value))
}
type="password"
/>
<TextField
name="ConfirmPassword"
value={passwordTwo}
id="standard-secondary"
label="Comfirm Password"
color="primary"
onChange={event =>
this.setState(byPropKey("passwordTwo", event.target.value))
}
type="password"
/>
<br />
<br />
<Button
type="submit"
disabled={isInvalid}
variant="contained"
color="primary"
>
Sign Up
</Button>
{error && <p style={{ color: "red" }}>{error.message}</p>}
</form>
);
}
}
const SignUpLink = () => (
<p>
Don't have an account? <Link to={routes.SIGN_UP}>Sign Up</Link>
</p>
);
export default SignUpPage;
export { SignUpForm, SignUpLink };

Related

TypeError: Converting circular structure to JSON when sending a post request through axios

Im getting this error when I send a post request to the server when the role for the user is seller for which there are 2 extra properties for the JSON : resName and resAddress. I am also using placeautocomplete (from google) to get the address of the restaurant (the name of it can be anything for the time being).
Register.js:
import logo from './logo.svg';
import './App.css';
import React, { Component, useEffect } from 'react';
import { useState } from 'react';
import axios from 'axios';
import LocationSearchInput from './placeComplete';
function Register() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [role, setRole] = useState("seller");
const [resName, setResName] = useState("");
const [resAddress, setResAddress] = useState(React.createRef());
async function registerUser(e){
e.preventDefault();
if (role === 'seller'){
const restaurantAddress = resAddress.current
console.log(restaurantAddress.state.address, resName)
}
const response = await axios.post('/api/users/register',
{
name,
email,
password,
resName,
resAddress,
role
}
).then(
res => {
console.log(res.data)
}
)
}
function registerRestaurant(){
if (role === 'seller'){
return(
<div>
<h4>Restaurant Name:</h4> <br />
<input type='text'
placeholder='Restaurant Name'
value={resName}
onChange={(e) => setResName(e.target.value)}
/>
<br />
<LocationSearchInput ref={resAddress} />
</div>
);
}
}
return (
<div>
<form onSubmit={registerUser}>
<input type="name" placeholder="Name"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<br />
<input type="email" placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<br />
<input type="password" placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<br />
<input type='radio' value='customer'
checked={role === 'customer'}
onChange={(e) => {
setRole(e.target.value)
}}
/>
customer
<br />
<input type='radio' value='seller'
checked={role === 'seller'}
onChange={(e) => {
setRole(e.target.value)
}}
/>
seller
<br />
{registerRestaurant()}
<input type='submit' value='Register' />
</form>
</div>
);
}
export default Register;
placeComplete.js:
import React from 'react';
import PlacesAutocomplete, {
geocodeByAddress,
getLatLng,
} from 'react-places-autocomplete';
class LocationSearchInput extends React.Component {
constructor(props) {
super(props);
this.state = { address: '' };
}
handleChange = address => {
this.setState({ address });
};
handleSelect = address => {
geocodeByAddress(address)
.then(results => getLatLng(results[0]))
.then(latLng => console.log('Success', latLng))
.then(this.setState({address: address}))
.catch(error => console.error('Error', error));
};
render() {
return (
<PlacesAutocomplete
value={this.state.address}
onChange={this.handleChange}
onSelect={this.handleSelect}
>
{({ getInputProps, suggestions, getSuggestionItemProps, loading }) => (
<div>
<input
{...getInputProps({
placeholder: 'Search Places ...',
className: 'location-search-input',
})}
/>
<div className="autocomplete-dropdown-container">
{loading && <div>Loading...</div>}
{suggestions.map(suggestion => {
const className = suggestion.active
? 'suggestion-item--active'
: 'suggestion-item';
// inline style for demonstration purpose
const style = suggestion.active
? { backgroundColor: '#fafafa', cursor: 'pointer' }
: { backgroundColor: '#ffffff', cursor: 'pointer' };
return (
<div
{...getSuggestionItemProps(suggestion, {
className,
style,
})}
>
<span>{suggestion.description}</span>
</div>
);
})}
</div>
</div>
)}
</PlacesAutocomplete>
);
}
}
export default LocationSearchInput;
I am also getting the following warning when I start typing in resAddress:
react_devtools_backend.js:4026 Warning: Each child in a list should have a unique "key" prop. Check the render method of `PlacesAutocomplete`. See https://reactjs.org/link/warning-keys for more information.
Mind you the server is accepting requests through postman.
This error usually gets thrown if you're not sending proper JSON. Your problem seems to happen here:
const response = await axios.post('/api/users/register',
{
name,
email,
password,
resName,
resAddress,
role
}
).then(
res => {
console.log(res.data)
}
)
Since resAddress is a ref (not proper JSON):
const [resAddress, setResAddress] = useState(React.createRef());
Change to something like this and you should be fine:
{
/* ... */
resAddress: resAddress.current.state.address
/* ... */
}

Not getting pre-filled state value from redux when user try to edit the form?

I am trying to get the state from redux store and trying to fill the input field from state. If user in edit mode. In edit mode, we normally show the prefilled value in input field. But what is wrong with the below approach?
I am able to store single user successfully in reducer but in component i am not getting. Sometimes i get the value. Overall, it's very inconsistent.
import React, { useState, useEffect } from "react";
import { makeStyles } from "#material-ui/core/styles";
import TextField from "#material-ui/core/TextField";
import Button from "#material-ui/core/Button";
import { useSelector, useDispatch } from "react-redux";
import { useHistory, useParams } from "react-router-dom";
import { addUser, getSingleUser, updateUser } from "../redux/actions";
const useStyles = makeStyles((theme) => ({
root: {
marginTop: 100,
"& > *": {
margin: theme.spacing(1),
width: "45ch",
},
},
}));
const initialState = {
name: "",
address: "",
contact: "",
email: "",
};
const EditUser = () => {
let { id } = useParams();
const { user } = useSelector((state) => state.users);
console.log("user", user);
const [state, setState] = useState(user);
const [error, setError] = useState("");
const { name, address, email, contact } = state;
const classes = useStyles();
const history = useHistory();
let dispatch = useDispatch();
const onInputChange = (e) => {
let { name, value } = e.target;
setState({ ...state, [name]: value });
};
useEffect(() => {
dispatch(getSingleUser(id));
}, []);
const handlSubmit = (e) => {
e.preventDefault();
console.log("name", name);
if (!name || !email || !address || !contact) {
setError("Please fill all Input Field");
} else {
dispatch(updateUser(state, id));
setError("");
history.push("/");
}
};
return (
<>
<Button
style={{ width: "100px", marginTop: "20px" }}
variant="contained"
type="submit"
color="secondary"
onClick={() => history.push("/")}
>
Go Back
</Button>
<h2>Edit user</h2>
{error && <h3 style={{ color: "red" }}>{error}</h3>}
<form
className={classes.root}
noValidate
autoComplete="off"
onSubmit={handlSubmit}
>
<TextField
id="standard-basic"
label="Name"
value={name}
name="name"
onChange={onInputChange}
type="text"
/>
<br />
<TextField
id="standard-basic"
value={email}
name="email"
label="Email"
type="email"
onChange={onInputChange}
/>
<br />
<TextField
id="standard-basic"
value={contact}
name="contact"
label="Contact"
type="number"
onChange={onInputChange}
/>
<br />
<TextField
id="standard-basic"
label="Address"
value={address}
name="address"
type="text "
onChange={onInputChange}
/>
<br />
<Button
style={{ width: "100px" }}
variant="contained"
type="submit"
color="primary"
>
Update
</Button>
</form>
</>
);
};
export default EditUser;
Below is redux actions logic to get the single user and dispatching an action to store single user value in reducer.
export const getSingleUser = (id) => {
return function (dispatch) {
axios
.get(`${process.env.REACT_APP_API}/${id}`)
.then((resp) => {
console.log("resp", resp);
dispatch(singleUser(resp.data));
})
.catch((error) => console.log(error));
};
};

handleSubmit with Formik using TypeScript

I have successfully written a Login component in React using plain Javascript. I would now like to convert this component to TypeScript. I have defined some types and also threw in some "any" just to initially compile. Unfortunately, the onClick parameter in my submit button throws the following error:
TS2322: Type '(e?: FormEvent | undefined) => void' is not assignable to type '(event: MouseEvent<HTMLElement, MouseEvent>)
=> void'.
Here is the relevant code:
class Login extends React.Component<LoginProps, LoginState> {
constructor(props) {
super(props);
this.login = this.login.bind(this);
}
async login(values) {
const user = {
email: values.email,
password: values.password,
};
const query = `mutation userLogin(
$user: UserLoginInputs!
) {
userLogin(
user: $user
) {
token
}
}`;
const data: any = await graphQLFetch(query, { user });
if (data && data.userLogin.token) {
const decoded: any = jwt.decode(data.userLogin.token);
const { onUserChange } = this.props;
onUserChange({ loggedIn: true, givenName: decoded.givenName });
const { history } = this.props;
history.push('/');
}
}
render() {
return (
<Formik
onSubmit={this.login}
validationSchema={loginSchema}
initialValues={{
email: '',
password: '',
}}
>
{({
handleSubmit,
handleChange,
values,
}) => (
<Card>
<Card.Body>
<Form>
<Form.Group>
<Form.Label>E-mail</Form.Label>
<Form.Control
name="email"
value={values.email}
onChange={handleChange}
/>
</Form.Group>
<Form.Group>
<Form.Label>Password</Form.Label>
<Form.Control
name="password"
value={values.password}
onChange={handleChange}
/>
</Form.Group>
</Form>
<Button
type="button"
variant="primary"
onClick={handleSubmit}
>
Submit
</Button>
</Card.Body>
</Card>
)}
</Formik>
);
}
}
I'm new to TypeScript and don't fully understand why an error occurs regarding e versus event when the login function does not explicitly reference either of those. Can someone please help me assign types to my handleSubmit function (aka login)?
I hope that example could help you to resolve your issue
import { Field, Form, Formik } from 'formik';
import * as React from 'react';
import './style.css';
interface MyFormValues {
firstName: string;
}
export default function App() {
const initialValues: MyFormValues = { firstName: '' };
const getSubmitHandler =
() =>
(values, formik) => {
console.log({ values, formik });
alert(JSON.stringify(values, null, 2));
formik.setSubmitting(false);
};
return (
<div>
<Formik
initialValues={initialValues}
onSubmit={getSubmitHandler()}
>
{(formik) => (
<Form>
<label htmlFor="firstName">First Name</label>
<Field id="firstName" name="firstName" placeholder="First Name" />
<button
type="button"
onClick={(event) =>
getSubmitHandler()(formik.values, formik)
}
>
Submit
</button>
</Form>
)}
</Formik>
</div>
);
}

React Bootstrap can't validate forms

I am trying to add some validation to my React + Bootstrap project but I am not able to achieve this. According to Bootstrap Form validation documentation I have to provide a Form.Control.Feedback component to the Form Group component.
But is not showing the errors but check marks like everything is fine. I created this Code Sandbox yo demostrate what I need to achieve and what is showing me:
And just in case, this is the code if you don't need the sandbox to see the error:
import React, { useState } from "react";
import "./styles.css";
import { Container, Form, Button } from "react-bootstrap";
import validator from "validator";
import empty from "is-empty";
export default function App() {
const [validated, setValidated] = useState(false);
const [errors, setErrors] = useState({});
const [phone, setPhone] = useState("");
const [email, setEmail] = useState("");
const handleSubmit = async e => {
e.preventDefault();
const errors = {};
// validation
if (!validator.isMobilePhone(phone, ["es-UY"])) {
errors.phone = "Invalid phone number";
}
if (!validator.isEmail(email)) {
errors.email = "Invalid email address";
}
if (!empty(errors)) {
setErrors(errors);
}
setValidated(true);
};
return (
<Container>
<Form validated={validated} onSubmit={handleSubmit}>
<h1>Test form</h1>
<Form.Group controlId="phone">
<Form.Label>Phone number</Form.Label>
<Form.Control
type="tel"
value={phone}
onChange={e => setPhone(e.target.value)}
/>
<Form.Control.Feedback type="invalid">Error</Form.Control.Feedback>
{errors.phone && (
<Form.Control.Feedback type="invalid">
{errors.phone}
</Form.Control.Feedback>
)}
</Form.Group>
<Form.Group controlId="email">
<Form.Label>Email address</Form.Label>
<Form.Control
type="email"
value={email}
onChange={e => setEmail(e.target.value)}
feedback="Error"
/>
{errors.email && (
<Form.Control.Feedback type="invalid">
{errors.email}
</Form.Control.Feedback>
)}
</Form.Group>
<Form.Group controld="submit">
<Button type="submit" variant="primary">
Submit
</Button>
<Button
type="reset"
variant="info"
style={{ marginLeft: 10 }}
onClick={() => {
setErrors({});
setValidated(false);
}}
>
Reset
</Button>
</Form.Group>
</Form>
</Container>
);
}
So, what am I doing wrong?
Make sure you've set setValidated as false for the errors
const handleSubmit = async e => {
e.preventDefault();
const allErrors = {}; // <--- changed this as well
// validation
if (!validator.isMobilePhone(phone, ["es-UY"])) {
allErrors.phone = "Invalid phone number";
}
if (!validator.isEmail(email)) {
allErrors.email = "Invalid email address";
}
if (!empty(allErrors)) {
setErrors(allErrors);
setValidated(false);
}
else {
setValidated(true);
}
};
In your field add isInvalid as props:
<Form.Control
type="tel"
value={phone}
isInvalid={!!errors.phone} <------
onChange={e => setPhone(e.target.value)}
/>
<Form.Control
type="text"
value={email}
isInvalid={!!errors.email} <-----
onChange={e => setEmail(e.target.value)}
feedback="Error"
/>

Add a react-bootstrap alert to handleSubmit in Formik

I'm trying to add a react-bootstrap alert to my Formik form so that the handleSubmit includes an alert to the user that the form has submitted.
I have used the react-bootstrap documented form of Alert, however I had to change the last line because that seems not to work (the error says that I haven't exported anything if I use the react-bootstrap documented form of alert.
My alert is:
import React from 'react';
import {
Alert,
Button,
} from "react-bootstrap";
class AlertDismissible extends React.Component {
constructor(props) {
super(props);
this.state = { show: true };
}
render() {
const handleHide = () => this.setState({ show: false });
const handleShow = () => this.setState({ show: true });
return (
<>
<Alert show={this.state.show} variant="light">
<Alert.Heading>Thanks for your interest </Alert.Heading>
<p>
We'll be in touch with login details shortly.
</p>
<hr />
<div className="d-flex justify-content-end">
<Button onClick={handleHide} variant="outline-success">
Close
</Button>
</div>
</Alert>
{!this.state.show && <Button onClick={handleShow}>Show Alert</Button>}
</>
);
}
}
export default AlertDismissible;
The documentation shows a final line as:
render(<AlertDismissible />);
If I try to use that, an error message saying that render is not defined, and that nothing has been exported appears. So - I replaced that line with my final line.
Then, in my form I have:
handleSubmit = (formState, { resetForm }) => {
// Now, you're getting form state here!
const payload = {
...formState,
role: formState.role.value,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
}
console.log("formvalues", payload);
fsDB
.collection("register")
.add(payload)
.then(docRef => {
resetForm(initialValues);
})
.then => {<AlertDismissible />}
.catch(error => {
console.error("Error adding document: ", error);
});
}
I don't actually know how to get the alert to work (the then statement above is a guess - I can't find any examples. This guess gives an error that says:
Parsing error: Unexpected token, expected ";"
I've tried adding ";" in every place I can think to put one, but it keeps generating errors.
If I try it like this:
.then(<AlertDismissible />)
I get no errors and the form submits, but the alert is not displayed.
Does anyone know how to call a react-bootstrap alert in the handle submit function?
Submit button has:
<Button
variant="outline-primary"
type="submit"
style={style3}
id="submitRegistration"
onClick={handleSubmit}
disabled={!dirty || isSubmitting}>
Register
</Button>
The onSubmit has:
onSubmit={
this.handleSubmit
}
My entire form looks like this:
import React from 'react';
import { Link } from "react-router-dom";
import { Formik, Form, Field, ErrorMessage, withFormik } from "formik";
import * as Yup from "yup";
import Select from "react-select";
import { fsDB, firebase, settings } from "../../firebase";
import Temporarynav from '../navigation/Temporarynav.jsx';
import Demo from '../landing/Demo.jsx';
import Footer from '../footer/Footer.jsx';
import "./preregister/Form.css";
import AlertDismissible from '../auth/preregister/Alert';
import {
Badge,
Button,
Col,
ComponentClass,
Feedback,
FormControl,
FormGroup,
Table,
Row,
Container
} from "react-bootstrap";
import Alert from 'react-bootstrap/Alert';
const style1 = {
width: "60%",
margin: "auto"
};
const style2 = {
paddingTop: "2em"
};
const style3 = {
marginRight: "2em"
};
const initialValues = {
firstName: "",
lastName: "",
email: "",
role: "",
consent: false,
createdAt: ''
}
class PreregForm extends React.Component {
// constructor(props) {
// super(props);
// // the flag isFormDone will control where you will show the Alert component
// this.state = {
// isFormDone: false
// };
// }
handleSubmit = (formState, { resetForm }) => {
// Now, you're getting form state here!
const payload = {
...formState,
role: formState.role.value,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
}
console.log("formvalues", payload);
fsDB
.collection("preregistrations")
.add(payload)
.then(docRef => {
resetForm(initialValues);
})
.then(() => {
// Here is where you flag your form completion and allow the alert to be shown.
// this.setState((prevState) => {...prevState, isFormDone: true});
.catch(error => {
console.error("Error adding document: ", error);
});
}
render() {
const options = [
{ value: "academic", label: "Academic Researcher" },
{ value: "student", label: "Student (inc PhD)" },
]
// const {isFormDone} = this.state;
return(
<Formik
initialValues={initialValues}
validationSchema={Yup.object().shape({
firstName: Yup.string().required("First Name is required"),
lastName: Yup.string().required("Last Name is required"),
email: Yup.string()
.email("Email is invalid")
.required("Email is required"),
role: Yup.string().nullable().required(
"It will help us get started if we know a little about your background"
),
consent: Yup.boolean().oneOf(
[true],
"You must accept the Terms of Use and Privacy Policy"
)
})}
onSubmit={
this.handleSubmit
}
render={({
errors,
status,
touched,
setFieldValue,
setFieldTouched,
handleSubmit,
isSubmitting,
dirty,
values
}) => {
return (
<div>
<Temporarynav />
<Form style={style1}>
<h1 style={style2}>Get Started</h1>
<p>
We're almost ready to open this up to the research community. By
registering now, you'll be first in line when the doors open.
</p>
<div className="form-group">
<label htmlFor="firstName">First Name</label>
<Field
name="firstName"
type="text"
className={
"form-control" +
(errors.firstName && touched.firstName ? " is-invalid" : "")
}
/>
<ErrorMessage
name="firstName"
component="div"
className="invalid-feedback"
/>
</div>
<div className="form-group">
<label htmlFor="lastName">Last Name</label>
<Field
name="lastName"
type="text"
className={
"form-control" +
(errors.lastName && touched.lastName ? " is-invalid" : "")
}
/>
<ErrorMessage
name="lastName"
component="div"
className="invalid-feedback"
/>
</div>
<div className="form-group">
<label htmlFor="email">Email</label>
<Field
name="email"
type="text"
placeholder="Please use your work email address"
className={
"form-control" +
(errors.email && touched.email ? " is-invalid" : "")
}
/>
<ErrorMessage
name="email"
component="div"
className="invalid-feedback"
/>
</div>
<div className="form-group">
<label htmlFor="role">
Which role best describes yours?
</label>
<Select
key={`my_unique_select_keyrole`}
name="role"
className={
"react-select-container" +
(errors.role && touched.role ? " is-invalid" : "")
}
classNamePrefix="react-select"
value={values.role}
onChange={selectedOptions => {
// Setting field value - name of the field and values chosen.
setFieldValue("role", selectedOptions)}
}
onBlur={setFieldTouched}
options={options}
/>
{errors.role && touched.role &&
<ErrorMessage
name="role"
component="div"
className="invalid-feedback d-block"
/>}
</div>
<div className="form-group">
<div className="checkbox-wrapper">
<Field
name="consent"
type="checkbox"
checked={values.consent}
className={
"checkbox" +
(errors.consent && touched.consent ? " is-invalid" : "")
}
/>
<label htmlFor="consent" className="checkbox_label_wrapper">
You must accept the{" "}
<Link className="links" to={"/Terms"}>
Terms of Use
</Link>{" "}
and{" "}
<Link className="links" to={"/Privacy"}>
Privacy Policy
</Link>
</label>
</div>
{errors.consent && touched.consent &&
<ErrorMessage
name="consent"
component="div"
className="invalid-feedback d-block"
/>
}
</div>
<div className="form-group">
<Button
variant="outline-primary"
type="submit"
style={style3}
id="submitRegistration"
onClick={handleSubmit}
disabled={!dirty || isSubmitting}
>
Register
</Button>
</div>
</Form>
<Demo />
<Footer />
</div>
);
}
}
/>
)
}
}
export default PreregForm;
Next attempt
When I try Julius solution, the alert appears, but as a footer beneath the form - not as a popup alert.
Use state and conditional rendering. Instead of returning a component set state to a variable, in your render use conditional rendering to check if the value is true.
handleSubmit = (formState, { resetForm }) => {
// Now, you're getting form state here!
const payload = {
...formState,
role: formState.role.value,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
};
console.log('formvalues', payload);
fsDB
.collection('register')
.add(payload)
.then(docRef => {
resetForm(initialValues);
})
.then(e => this.setState({ alert: true }))
.catch(error => {
console.error('Error adding document: ', error);
});
};
In your render
render() {
...
return(
....
{this.state.alert && <AlertDismissible />}
...
)
}
Example Demo
Complete form
import React from 'react';
import { Link } from 'react-router-dom';
import { Formik, Form, Field, ErrorMessage, withFormik } from 'formik';
import * as Yup from 'yup';
import Select from 'react-select';
import { fsDB, firebase, settings } from '../../firebase';
import Temporarynav from '../navigation/Temporarynav.jsx';
import Demo from '../landing/Demo.jsx';
import Footer from '../footer/Footer.jsx';
import './preregister/Form.css';
import AlertDismissible from '../auth/preregister/Alert';
import {
Badge,
Button,
Col,
ComponentClass,
Feedback,
FormControl,
FormGroup,
Table,
Row,
Container
} from 'react-bootstrap';
import Alert from 'react-bootstrap/Alert';
const style1 = {
width: '60%',
margin: 'auto'
};
const style2 = {
paddingTop: '2em'
};
const style3 = {
marginRight: '2em'
};
const initialValues = {
firstName: '',
lastName: '',
email: '',
role: '',
consent: false,
createdAt: ''
};
class PreregForm extends React.Component {
constructor(props) {
super(props);
// the flag isFormDone will control where you will show the Alert component
this.state = {
showAlert: false
};
}
handleSubmit = (formState, { resetForm }) => {
// Now, you're getting form state here!
const payload = {
...formState,
role: formState.role.value,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
};
console.log('formvalues', payload);
fsDB
.collection('preregistrations')
.add(payload)
.then(docRef => {
resetForm(initialValues);
})
.then(e => this.setState({ showAlert: true }))
.catch(error => {
console.error('Error adding document: ', error);
});
};
render() {
const options = [
{ value: 'academic', label: 'Academic Researcher' },
{ value: 'student', label: 'Student (inc PhD)' }
];
// const {isFormDone} = this.state;
return (
<div>
{!this.state.showAlert ? (
<div>
<Formik
initialValues={initialValues}
validationSchema={Yup.object().shape({
firstName: Yup.string().required('First Name is required'),
lastName: Yup.string().required('Last Name is required'),
email: Yup.string()
.email('Email is invalid')
.required('Email is required'),
role: Yup.string()
.nullable()
.required(
'It will help us get started if we know a little about your background'
),
consent: Yup.boolean().oneOf(
[true],
'You must accept the Terms of Use and Privacy Policy'
)
})}
onSubmit={this.handleSubmit}
render={({
errors,
status,
touched,
setFieldValue,
setFieldTouched,
handleSubmit,
isSubmitting,
dirty,
values
}) => {
return (
<div>
<Temporarynav />
<Form style={style1}>
<h1 style={style2}>Get Started</h1>
<p>
We're almost ready to open this up to the research
community. By registering now, you'll be first in line
when the doors open.
</p>
<div className="form-group">
<label htmlFor="firstName">First Name</label>
<Field
name="firstName"
type="text"
className={
'form-control' +
(errors.firstName && touched.firstName
? ' is-invalid'
: '')
}
/>
<ErrorMessage
name="firstName"
component="div"
className="invalid-feedback"
/>
</div>
<div className="form-group">
<label htmlFor="lastName">Last Name</label>
<Field
name="lastName"
type="text"
className={
'form-control' +
(errors.lastName && touched.lastName
? ' is-invalid'
: '')
}
/>
<ErrorMessage
name="lastName"
component="div"
className="invalid-feedback"
/>
</div>
<div className="form-group">
<label htmlFor="email">Email</label>
<Field
name="email"
type="text"
placeholder="Please use your work email address"
className={
'form-control' +
(errors.email && touched.email ? ' is-invalid' : '')
}
/>
<ErrorMessage
name="email"
component="div"
className="invalid-feedback"
/>
</div>
<div className="form-group">
<label htmlFor="role">
Which role best describes yours?
</label>
<Select
key={`my_unique_select_keyrole`}
name="role"
className={
'react-select-container' +
(errors.role && touched.role ? ' is-invalid' : '')
}
classNamePrefix="react-select"
value={values.role}
onChange={selectedOptions => {
// Setting field value - name of the field and values chosen.
setFieldValue('role', selectedOptions);
}}
onBlur={setFieldTouched}
options={options}
/>
{errors.role && touched.role && (
<ErrorMessage
name="role"
component="div"
className="invalid-feedback d-block"
/>
)}
</div>
<div className="form-group">
<div className="checkbox-wrapper">
<Field
name="consent"
type="checkbox"
checked={values.consent}
className={
'checkbox' +
(errors.consent && touched.consent
? ' is-invalid'
: '')
}
/>
<label
htmlFor="consent"
className="checkbox_label_wrapper"
>
You must accept the{' '}
<Link className="links" to={'/Terms'}>
Terms of Use
</Link>{' '}
and{' '}
<Link className="links" to={'/Privacy'}>
Privacy Policy
</Link>
</label>
</div>
{errors.consent && touched.consent && (
<ErrorMessage
name="consent"
component="div"
className="invalid-feedback d-block"
/>
)}
</div>
<div className="form-group">
<Button
variant="outline-primary"
type="submit"
style={style3}
id="submitRegistration"
onClick={handleSubmit}
disabled={!dirty || isSubmitting}
>
Register
</Button>
</div>
</Form>
<Demo />
<Footer />
</div>
);
}}
/>
</div>
) : (
<AlertDismissible />
)}
</div>
);
}
}
export default PreregForm;
You can't return a component like that within the then function.
You should manage a state flag that shows the alert based on the form completion.
Maybe you could share your whole component where you are handling the submit shown here so we can give you more help (will update the answer if you update the question).
But I think it would be something along the following lines:
class MyFormComponent extends React.Component {
constructor(props) {
super(props);
// the flag isFormDone will control where you will show the Alert component
this.state = {
isFormDone: false
};
}
/** Here your form handling as you posted */
handleSubmit = (formState, { resetForm }) => {
const payload = {
...formState,
role: formState.role.value,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
}
console.log("formvalues", payload);
fsDB
.collection("register")
.add(payload)
.then(docRef => {
resetForm(initialValues);
})
.then(() => {
// Here is where you flag your form completion and allow the alert to be shown.
this.setState((prevState) => ({...prevState, isFormDone: true}));
})
.catch(error => {
console.error("Error adding document: ", error);
});
}
render() {
const {isFormDone} = this.state;
// this will only render the Alert when you complete your form submission
const alert = isFormDone ? <AlertDismissible/> : null;
return(
{/* syntax sugar for React Fragment */}
<>
{/* if it is null, it won't render anything */}
{alert}
{/* Your Form here with your handler */}
{/* ... */}
</>
);
}
}

Categories

Resources