I have a registration view and I'm trying to check whether the email already exists, I've undone the react code so you can get a good idea of the structure.
The emails are set as unique in the schema.
AuthController
const { check, validationResult } = require("express-validator");
const jwt = require("jsonwebtoken");
const passport = require("passport");
require("../passport");
const Users = require("../models/user");
let validations = [
check("email")
.isEmail()
.withMessage("The email you have entered is not valid")
.contains("#")
.withMessage("The email you have entered does not contain an #"),
check("password")
.isLength({ min: 5 })
.withMessage("The password must have at least 5 characters")
];
// Throw error if the key doesn't exist
if (!process.env.JWT_SECRET) {
console.error("Cannot find JWT key");
}
function generateWebToken(user) {
return jwt.sign(user, process.env.JWT_SECRET, {
subject: user.email,
expiresIn: "7d",
algorithm: "HS256"
});
}
/* POST register a user if one doesn't already exist */
module.exports.register = [
...validations,
(req, res) => {
// Get validation errors from the request
const errors = validationResult(req);
// Return the errors
if (!errors.isEmpty()) {
return res.status(422).json({ error: errors.array() });
}
let hashedPassword = Users.hashPassword(req.body.password);
Users.findOne({ email: req.body.email })
.then(function(user) {
if (user) {
return res
.status(400)
.send(`An account with the email ${req.body.email} already exists`);
} else {
Users.create({
email: req.body.email,
password: hashedPassword
})
.then(function(user) {
res.status(201).json(user);
})
.catch(function(err) {
console.error(err);
res.status(500).send(`Error ${err}`);
});
}
})
.catch(function(err) {
console.error(err);
res.status(500).send(`Error ${err}`);
});
}
];
Register.js (react component)
import React, { Component } from "react";
const initalState = {
email: "",
password: "",
emailErr: "",
passwordErr: ""
};
class Register extends Component {
constructor(props) {
super(props);
this.state = {
initalState,
successMsg: ""
};
this.handleSubmit = this.handleSubmit.bind(this);
}
validate = () => {
let emailErr = "";
let passwordErr = "";
// Email validation
if (!this.state.email) {
emailErr = "Please enter an email";
}
// Password validation
if (!this.state.password) {
passwordErr = "Please enter your password";
}
if (emailErr || passwordErr) {
this.setState({ emailErr, passwordErr });
return false;
}
return true;
};
onEmailChange(event) {
this.setState({ email: event.target.value });
}
onPasswordChange(event) {
this.setState({ password: event.target.value });
}
handleSubmit(event) {
event.preventDefault();
const isValid = this.validate();
if (isValid) {
fetch("/api/auth/register", {
method: "POST",
body: JSON.stringify(this.state),
headers: {
Accept: "application/json",
"Content-Type": "application/json"
}
})
.then(res => res.json())
.then(this.setState({ successMsg: true }), this.setState(initalState));
}
}
render() {
return (
<>
<div className='block md:flex md:flex-column h-full'>
<div className='p-12 w-full text-center text-gray-800'>
<h1 className='title'>Register</h1>
{this.state.successMsg && (
<div
className='w-full m-auto max-w-lg mb-10 bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative'
role='alert'
>
<strong className='font-bold'>Holy smokes! </strong>
<span className='block sm:inline'>
Account has been created
</span>
</div>
)}
<form className='w-full m-auto max-w-lg'>
<div className='flex flex-wrap -mx-3'>
<div className='w-full px-3 mb-6'>
<label htmlFor='email'>Email Address</label>
<input
id='email'
type='text'
placeholder='johndoe#example.co.uk'
value={this.state.email || ""}
onChange={this.onEmailChange.bind(this)}
/>
<p className='my-2 text-red-500 text-xs'>
{this.state.emailErr}
</p>
</div>
</div>
<div className='flex flex-wrap -mx-3'>
<div className='w-full px-3 mb-6'>
<label htmlFor='password'>Password</label>
<input
id='password'
type='password'
placeholder='*********'
value={this.state.password || ""}
onChange={this.onPasswordChange.bind(this)}
/>
<p className='my-2 text-red-500 text-xs'>
{this.state.passwordErr}
</p>
</div>
</div>
<div className='flex'>
<button
className='btn'
type='button'
onClick={this.handleSubmit.bind(this)}
>
Send
</button>
</div>
</form>
</div>
</div>
</>
);
}
}
export default Register;
Not sure if it's possible just to pass the express validations or what the best solution for this is.
The code above looks fine as this line of code explicitly checks for email duplications in MongoDB
>if (user) {
> return res
> .status(400)
> .send(`An account with the email ${req.body.email} already exists`);
> } else {...
Here is a full solution to display errors from register api (both express-validations and user is already registered error)
I tried to mimic your api and react app, but heavily refactored:
1-) In api we need to convert express validation errors in a readable way:
Normally its validation errors are in an array like this:
{
"error": [
{
"value": "abcdef#net",
"msg": "The email you have entered is not valid",
"param": "email",
"location": "body"
},
{
"value": "12",
"msg": "The password must have at least 5 characters",
"param": "password",
"location": "body"
}
]
}
With the following code, I converted the error messages in this format to easily access in react app by field name:
{
"errors": {
"email": "The email you have entered is not valid",
"password": "The password must have at least 5 characters"
}
}
register route:
const { check, validationResult } = require("express-validator");
const bcrypt = require("bcryptjs");
const { User } = require("../models/user");
const express = require("express");
const router = express.Router();
let validations = [
check("email")
.isEmail()
.withMessage("The email you have entered is not valid"),
check("password")
.isLength({ min: 5 })
.withMessage("The password must have at least 5 characters")
];
router.post("/register", validations, async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
const err = {};
errors.array().forEach(error => {
err[error.param] = error.msg;
});
return res.status(422).json({ errors: err });
}
const { email, password } = req.body;
try {
let user = await User.findOne({ email });
if (user) return res.status(400).send("User already registered.");
user = new User({ email, password });
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(user.password, salt);
user = await user.save();
res.send(user);
} catch (err) {
console.log(err);
res.status(500).send("Something went wrong");
}
});
module.exports = router;
In the react side I used axios instead of fetch since the error handling is far easier with axios:
import React, { Component } from "react";
import axios from "axios";
class App extends Component {
state = {
email: "",
password: "",
fieldErrors: {},
registerError: null
};
handleSubmit = async e => {
e.preventDefault();
this.setState({
fieldErrors: {},
registerError: null
})
const { email, password } = this.state;
try {
const response = await axios.post(
"https://express-validator-auth.herokuapp.com/api/users/register",
{ email, password }
);
console.log(response.data);
alert("Registered");
} catch (error) {
if (error.response && error.response.data) {
if (error.response.data.errors) {
this.setState({
fieldErrors: error.response.data.errors
});
} else {
this.setState({
registerError: error.response.data
});
}
} else {
console.log(error);
}
}
};
handleChange = e => {
this.setState({
[e.target.name]: e.target.value
});
};
render() {
const { email, password, fieldErrors, registerError } = this.state;
return (
<div>
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label>Email</label>
<input
type="text"
className={
!fieldErrors.email ? "form-control" : "form-control is-invalid"
}
name="email"
value={email}
onChange={this.handleChange}
/>
{fieldErrors.email && (
<div className="invalid-feedback">{fieldErrors.email}</div>
)}
</div>
<div className="form-group">
<label>Password</label>
<input
type="password"
className={
!fieldErrors.password
? "form-control"
: "form-control is-invalid"
}
name="password"
value={password}
onChange={this.handleChange}
/>
{fieldErrors.password && (
<div className="invalid-feedback">{fieldErrors.password}</div>
)}
</div>
<button type="submit" className="btn btn-primary">
Submit
</button>
{registerError && (
<div className="alert alert-danger" role="alert">
{registerError}
</div>
)}
</form>
<br />
{JSON.stringify(this.state)}
</div>
);
}
}
export default App;
So when an validation error occurres form will look like this:
And when the "user is already registered error" occurres form validation will look like this:
The react app can be accessed from this codesandbox:
https://codesandbox.io/s/gracious-mccarthy-kluor
Related
I'm trying to return a value from my handleRegister function, but it gives me undefined, I checked before returning the value and it exists but as soon as I return, it's undefined. Can someone please help me? The object exists:
{
"signup": {
"name": "riced",
"id": 7135,
"email": "riced#gmail.com",
"password": "U24jg2xwSbF4R6k",
"error": null,
"__typename": "User"
}
}
The following part fails:
handleRegister(this.state).then(
(data) => {
console.log(data);
return;
});
import * as React from "react"
import { navigate } from "gatsby"
import {isLoggedIn } from "../services/auth"
import fetch from 'isomorphic-fetch';
import {ApolloClient, HttpLink, InMemoryCache, gql} from '#apollo/client';
const client = new ApolloClient({
cache: new InMemoryCache(),
link: new HttpLink({
uri: 'http://10.0.0.212:9000/',
fetch
})
});
export const REGISTER_USER = gql
mutation Mutation($signupInput: SignUpInput) {
signup(signupInput: $signupInput) {
name
id
email
password
error
}
}
;
export async function handleRegister ({ username, email, password }) {
/*
if (username === `john` && password === `pass`) {
return setUser({
username: `john`,
name: `Johnny`,
email: `johnny#example.org`,
})
*/
/*
client.query({ query: ALL_USERS }).then(result => console.log(result));
*/
//let [errors, setErrors] = React.useState([]);
var gottenToken = "";
//let gottenName;
await client.mutate({ mutation: REGISTER_USER, variables: {
"signupInput": {
"name": username,
"password": password,
"email": email,
}
} }).then(result => {
console.log(result);
console.log(result.data!.signup);
//let signup = JSON.stringify(result.data!.signup);
return result.data!.signup
//Promise.resolve(result.data!.signup);
}).catch(err => {
console.log(err);
//setUser({})
//React.useEffect(() => {
//localStorage.setItem('signupError', JSON.stringify(err));
//}, [errors]);
//return haveErrorOccured("Signing up error"); // send error to browser
});
//return haveErrorOccured("Signing up error"); // send error to browser
}
class Register extends React.Component {
state = {
username: ``,
email: ``,
password: ``,
}
handleUpdate = async event => {
await this.setState({
[event.target.name]: event.target.value,
})
}
handleSubmit = async event => {
event.preventDefault()
//handleRegister(this.state)
/*
handleRegister(this.state).then(r => {
console.log(r);
}).catch(err => {
console.log(err);
});
*/
handleRegister(this.state).then(
(data) =>{
console.log(data);
return;
//return 43;
});
//console.log("signed up: " + signup);
//console.table(signup);
}
render() {
if (isLoggedIn()) {
navigate(`/app/profile`)
}
//let errorSignup;
//if(window.localStorage.getItem("signupError")){
// errorSignup = JSON.stringify(JSON.parse(window.localStorage.getItem("signupError")));
//}
//navigate("/app/register?registered", { state: { foo: "bar" }});
//<p>{errorSignup}</p>
return (
<>
<h1>Register</h1>
<form
method="post"
onSubmit={event => {
this.handleSubmit(event);
}}
>
<label>
Username
<input type="text" name="username" onChange={this.handleUpdate} />
</label>
<label>
Email
<input type="text" name="email" onChange={this.handleUpdate} />
</label>
<label>
Password
<input
type="password"
name="password"
onChange={this.handleUpdate}
/>
</label>
<input type="submit" value="Log In" />
</form>
</>
)
}
}
export default Register
I want to create a login form with array data:
const users = [
{
username: 'admin1',
password: '12345678'
},
{
username:'admin2',
password:'012345678'
}
];
and Login.js looks something like this:
import React from 'react';
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
userName: "",
password: ""
};
}
changeInputValue(e) {
this.setState({
[e.target.name]: e.target.value
});
}
validationForm() {
let returnData = {
error : false,
msg: ''
}
const {password} = this.state
//Check password
if(password.length < 8) {
returnData = {
error: true,
msg: 'Password must be more than 8 characters'
}
}
return returnData;
}
submitForm(e) {
e.preventDefault();
const validation = this.validationForm()
var username = e.target.elements.username.value;
var password = e.target.elements.password.value;
if (validation.error) {
alert(validation.msg)
}else if(username === 'admin1' && password === '12345678') {
alert("Login successful");
}else {
alert("Wrong password or username");
}
}
render() {
return (
<div className="container" style={{ paddingTop: "5%" }}>
<form
onSubmit={e => {
this.submitForm(e);
}}
>
<div className="form-group">
<input
type="text"
className="form-control"
name="username"
placeholder="Username"
onChange={e => this.changeInputValue(e)}
/>
</div>
<div className="form-group">
<input
type="password"
className="form-control"
name="password"
placeholder="Password"
onChange={e => this.changeInputValue(e)}
/>
</div>
<button value="submit" className="btn btn-primary" onClick={this.postDetails}>
Submit
</button>
</form>
</div>
);
}
}
export default Login;
So the above code only check whether the username and password fields entered in the form match the name and password of single record in the array of objects of User.js the above code is working fine. I don't know how to check username and password from the passed array.
I want to use map () to check for username and password. Please show an instance of how it is done. Sorry, I'm new to ReactJS so I'm a bit confused, hope you can help. Thanks
You can use .some() method.
doc: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some
Something like this
var username = e.target.elements.username.value;
var password = e.target.elements.password.value;
if(users.some((elem) => elem.username === username && elem.password === password)) {
// when authentication is valid
} else {
// not a valid username / password
}
You can use find
const user = users.find(user => (user.username === username && user.password === password))
if(user){
//correct user
}
if(!user) {
//incorrect
}
I want to create a login form with array data in User.js file (without any backend)
My User.js file looks like this:
const users = [
{
username: 'admin1',
password: 'admin1#1'
},
{
username:'admin2',
password:'admin2#2'
}
];
and my Login.js looks something like this:
import React, { Component, Fragment } from 'react';
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
userName: "",
password: ""
};
}
changeInputValue(e) {
this.setState({
[e.target.name]: e.target.value
});
}
validationForm() {
let returnData = {
error : false,
msg: ''
}
const {password} = this.state
//Check password
if(password.length < 8) {
returnData = {
error: true,
msg: 'Password must be more than 8 characters'
}
}
return returnData;
}
submitForm(e) {
e.preventDefault();
const validation = this.validationForm()
var username = e.target.elements.username.value;
var password = e.target.elements.password.value;
if (validation.error) {
alert(validation.msg)
}else if(username === 'admin2' && password === 'admin1#1') {
alert("Login successful");
}else {
alert("Wrong password or username");
}
}
render() {
return (
<div className="container" style={{ paddingTop: "5%" }}>
<form
onSubmit={e => {
this.submitForm(e);
}}
>
<div className="form-group">
<input
type="text"
className="form-control"
name="username"
placeholder="Username"
onChange={e => this.changeInputValue(e)}
/>
</div>
<div className="form-group">
<input
type="password"
className="form-control"
name="password"
placeholder="Password"
onChange={e => this.changeInputValue(e)}
/>
</div>
<button value="submit" className="btn btn-primary" onClick={this.postDetails}>
Submit
</button>
</form>
</div>
);
}
}
export default Login;
Above, I don't know how to check username and password from the passed array. Please show an instance of how it is done. And after successful login, how do I switch to another page?Sorry, I'm new to ReactJS so I'm a bit confused, hope you can help.
Import the data from user.js after u exported it from there.
export const UsersData = [
{
username: 'admin1',
password: 'admin1#1'
},
{
username:'admin2',
password:'admin2#2'
}
];
//Login.js
import UsersData from './user.js'
Now do array operation on this array of objects. Now you can convert the data entered by the user to a similar format provided by User.js.
ie: If the user entered username = alphabeta, password = 1234
submitForm(e) {
e.preventDefault();
const validation = this.validationForm()
var inputData = {
username : e.target.elements.username.value,
password : e.target.elements.password.value
};
if (validation.error) {
alert(validation.msg)
}else if(UsersData.findIndex(inputData)!==-1) {
alert("Login successful");
}else {
alert("Wrong password or username");
}
}
Here we uses an array operation called findIndex which returns -1 if it doesn't find the object in the array else it returns the index.
To know more about Array Opreration in JS : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex
Not sure if I understand correstly your question but here is how you can check if the duo user and password are in your array :
import React, { Component } from 'react';
import { render } from 'react-dom';
import './style.css';
const App = () => {
const users = [
{
username: "admin1",
password: "admin1#1",
},
{
username: "admin2",
password: "admin2#2",
},
];
const handleSubmit = (e) => {
e.preventDefault();
const toCompare = {
username: e.target.elements.username.value,
password: e.target.elements.password.value,
};
// Or just compare properties
if (users.some(u => JSON.stringify(u) === JSON.stringify(toCompare))) {
console.log('User exists in array');
} else {
console.log('User does not exist in array');
}
};
return (
<form onSubmit={handleSubmit}>
<input type="text" placeholder="username" name="username" />
<input type="text" placeholder="password" name="password" />
<button type="submit">Send</button>
</form>
);
};
render(<App />, document.getElementById('root'));
And here is the repro on Stackblitz
I have an issue with the login authentication in my project. I connected my react front end with my express back end, but when I try to login with valid credentials, it gets stuck in an error seems like it can't read properly the value I'm passing in my form input.
Here's my LogIn page:
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { signin } from '../actions/authAction';
import { clearErrors } from '../actions/errAction';
import { Button, Form, FormGroup, Input, Alert } from 'reactstrap'
import TopCont from '../components/TopCont'
class Signin extends Component {
state = {
email: '',
password: '',
msg: null
};
static propTypes = {
isAuth: PropTypes.bool,
signin: PropTypes.func.isRequired,
err: PropTypes.object.isRequired,
clearErrors: PropTypes.object.isRequired
};
componentDidMount(){
this.props.clearErrors();
}
componentDidUpdate(prevProps){
const { err } = this.props;
if(err !== prevProps.err) {
if(err.id === 'LOGIN_FAIL'){
this.setState({ msg: err.msg.msg });
} else {
this.setState({ msg: null });
}
}
};
onChange = e => {
this.setState({
[e.target.email]: e.target.value,
[e.target.password]: e.target.value
});
};
onSubmit = e => {
e.preventDefault();
const { email, password } = this.state;
const user = {
email,
password
};
this.props.signin(user);
/* this.props.push('/dashboard'); */
};
render() {
return (
<>
<TopCont>
<div className="signin-cont">
<h1>Accedi</h1>
{this.state.msg ? <Alert color="danger">{this.state.msg}</Alert> : null }
<Form className="signin-form-cont" onSubmit={this.onSubmit}>
<FormGroup>
<Input className="signin-form" type="email" name="email" id="email" placeholder="mario.rossi#prova.it" onChange={this.onChange}/>
</FormGroup>
<FormGroup>
<Input className="signin-form" type="password" name="password" id="password" placeholder="Password" onChange={this.onChange}/>
</FormGroup>
<Button className="sign-btn">Accedi</Button>
</Form>
<p>Non hai ancora un account? <Link to="/signup">Registrati</Link></p>
</div>
</TopCont>
</>
)
}
}
const mapStateToProps = state => ({
isAuth: state.auth.isAuth,
err: state.err
});
export default connect(mapStateToProps, { signin, clearErrors })(Signin);
Here is my Action:
import axios from 'axios';
import { returnErrors } from './errAction';
import { AUTH_ERROR, LOGIN_FAIL } from '../actions/types';
export const signin = ({ email, password }) => dispatch => {
const config = {
headers: {
'Content-Type': 'application/json'
}
};
const body = JSON.stringify({ email, password });
axios.post('/api/auth', body, config)
.then(res => dispatch({
type: LOGIN_SUCCESS,
payload: res.data
}))
.catch(err => {
dispatch(returnErrors(err.response.data, err.response.status, 'LOGIN_FAIL'));
dispatch({
type: LOGIN_FAIL
});
});
};
And here is my Auth API:
const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const config = require('config');
const jwt = require('jsonwebtoken');
const auth = require('../../middleware/auth');
const User = require('../../models/User');
//#action POST api/auth
//#descr auth user
//#access Public
router.post('/', (req, res) => {
const { email, password } = req.body
if( !email || !password ) {
return res.status(400).json({ msg: "Enter all fields."});
}
User.findOne({ email })
.then(user => {
if(!user) return res.status(400).json({ msg: "Nessun profilo trovato con questa email"});
bcrypt.compare( password, user.password )
.then(isMatch => {
if(!isMatch) return res.status(400).json({ msg: "Password errata!"});
jwt.sign(
{ id: user.id },
config.get('jwtSecret'),
{ expiresIn: 10800 },
(err, token) => {
if(err) throw err;
res.json({
token,
user: {
id: user.id,
name: user.name,
surname: user.surname,
email: user.email,
userPlus: user.userPlus
}
})
}
)
})
})
});
//#action GET api/auth/user
//#descr GET user data
//#access Private
router.get('/user', auth, (req, res) => {
User.findById(req.user.id)
.select('-password')
.then(user => res.json(user));
});
module.exports = router;
If I try to get rid of all the errors controls my server return this error:
TypeError: Cannot read property 'password' of null
The strange thing is that if I try to register a new user (with an almost identical component and server-side method) there are no problems and it authenticates too with no problems.
Someone knows how can I fix this issue?
Change your onChange Function from this:
onChange = e => {
this.setState({
[e.target.email]: e.target.value,
[e.target.password]: e.target.value
});
};
to this:
onChange = e => this.setState(prevState => ({
...prevState,
[e.target.name]: e.target.value,
}));
As the title says, I have a check in RegistrationForm for checking if user email exists in the database. The prop is userExists. Now, if it's true, that means User email exists, so the user should be shown a message that says- "User already exists." Now, if it's false, he should be successfully registered and redirected to login.
But right now, I cannot even register with any email. In the network tab, it returns a 200 and gives
the response:
{"message":"User with this email does not exist"}
Can someone show me the proper way to do it? I mean the check, and the message from the backend, through redux, and back to the component.
My code is jibberish.
RegistrationForm Component
import React, { Component } from "react";
import { registerUser, checkValidUser } from "../../actions/userActions";
import { connect } from "react-redux";
import validator from "validator";
import { Link } from "react-router-dom";
import { toastError } from "../../../utils/toastify";
class RegistrationForm extends Component {
constructor(props) {
super(props);
this.state = {
username: "",
email: "",
password: "",
};
}
handleChange = (event) => {
const { name, value } = event.target;
this.setState({
[name]: value,
});
};
handleSubmit = async (event) => {
event.preventDefault();
const { username, email, password } = this.state;
const registrationData = {
username: this.state.username,
email: this.state.email,
password: this.state.password,
};
if (!username || !email || !password) {
return toastError("Credentials should not be empty");
}
if (username.length < 6) {
return toastError("Username should be greater than 6 characters.");
}
if (!validator.isEmail(email)) {
return toastError("Invalid email.");
}
if (password.length < 6) {
return toastError("Password must contain 6 characters.");
}
await this.props.dispatch(checkUserExists(email));
const userExists = this.props.userExists;
if (!userExists) {
this.props.dispatch(
registerUser(registrationData, () => {
this.props.history.push("/login");
})
);
} else {
toastError("User with this email already exisits"); // I'm not sure how to show the message if the user email already exists. I want to show the message from backend, but currently I'm just doing it manually
}
};
render() {
const isRegistrationInProgress = this.props.isRegistrationInProgress;
return (
<div>
<div className="field">
<p className="control has-icons-left has-icons-right">
<input
onChange={this.handleChange}
name="username"
value={this.state.username}
className="input"
type="text"
placeholder="Username"
/>
<span className="icon is-small is-left">
<i className="fas fa-user"></i>
</span>
</p>
</div>
<div className="field">
<p className="control has-icons-left has-icons-right">
<input
onChange={this.handleChange}
name="email"
value={this.state.email}
className="input"
type="email"
placeholder="Email"
/>
<span className="icon is-small is-left">
<i className="fas fa-envelope"></i>
</span>
</p>
</div>
<div className="field">
<p className="control has-icons-left">
<input
onChange={this.handleChange}
name="password"
value={this.state.password}
className="input"
type="password"
placeholder="Password"
/>
<span className="icon is-small is-left">
<i className="fas fa-lock"></i>
</span>
</p>
</div>
<div className="field">
<div className="control">
{isRegistrationInProgress ? (
<button className="button is-success is-loading">Sign Up</button>
) : (
<button onClick={this.handleSubmit} className="button is-success">
Sign up console.log("registrationData", registrationData)
</button>
)}
<Link to="/login">
<p className="has-text-danger">
Already have an account? Sign In
</p>
</Link>
</div>
</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
isRegistrationInProgress: state.registration.isRegistrationInProgress,
userExists: state.registration.userExists,
};
};
export default connect(mapStateToProps)(RegistrationForm);
checkUserExists action
export const checkUserExists = (email) => {
return async (dispatch) => {
try {
const res = await axios.get(`${baseUrl}/users/checkUserExists/${email}`)
console.log("res=>", res)
if (res.data.message = "User with this email already exists") {
dispatch({
type: "CHECK_USER_EXISTS_SUCCESS",
})
}
} catch (err) {
console.log("error=>", err)
}
}
}
checkUserExists controller function
checkUserExists: async (req, res, next) => {
const { email } = req.params
try {
const user = await User.findOne({ email })
if (user) {
return res.status(200).json({ message: "User with this email already exists" })
} else {
return res.json({ message: "User with this email does not exist" })
}
} catch (error) {
return next(error)
}
}
registerUser action
export const registerUser = (registrationData, redirect) => {
return async (dispatch) => {
dispatch({ type: "REGISTRATION_STARTS" })
try {
const res = await axios.post(
`${baseUrl}/users/register`,
registrationData
)
dispatch({
type: "REGISTRATION_SUCCESS",
data: { user: res.data.user },
})
toastSuccess("Successfully registered")
redirect()
} catch (err) {
dispatch({
type: "REGISTRATION_ERROR",
data: { error: err },
})
}
}
}
registration reducer
const initialState = () => ({
isRegistrationInProgress: false,
isRegistered: false,
registrationError: null,
user: {},
userExists: false,
error: null,
});
const registration = (state = initialState, action) => {
switch (action.type) {
case "REGISTRATION_STARTS":
return {
...state,
isRegistrationInProgress: true,
registrationError: null,
};
case "REGISTRATION_SUCCESS":
return {
...state,
isRegistrationInProgress: false,
registrationError: null,
isRegistered: true,
user: action.data,
};
case "REGISTRATION_ERROR":
return {
...state,
isRegistrationInProgress: false,
registrationError: action.data.error,
isRegistered: false,
user: {},
};
case "CHECK_USER_EXISTS_SUCCESS":
return {
...state,
userExists: true,
error: null
};
default:
return state;
}
};
export default registration;