i am creating a mern app. i got stuck in forgot password. i'm able to send a mail for forgot password but when i try to set new password it is not changing password but in postman i was able to change the password but when it comes to react i was not. I know the problem is that i was not able to get token as params .
work in postman but not in when i try in react.
Resetpassword component
import React, { Fragment, useState } from 'react';
import { connect } from 'react-redux';
import { Link, Redirect } from 'react-router-dom';
import { setAlert } from '../../actions/alert';
import { reset } from '../../actions/auth';
import PropTypes from 'prop-types';
const Reset = ({ setAlert, reset }) => {
const [formData, setFormData] = useState({
password: '',
password2: ''
});
const { password, password2 } = formData;
const onChange = e =>
setFormData({ ...formData, [e.target.name]: e.target.value });
const onSubmit = async => {
const token = props.match.params.token;
console.log(token);
if (password !== password2) {
setAlert('password does not matched', 'danger');
} else {
reset({ password, token });
}
};
return (
<Fragment>
<section className='container'>
<h1 className='large text-primary'>RESET PASSWORD</h1>
<p className='lead'>
<i className='fas fa-user' /> Create Your NEW PASSWORD
</p>
<form
className='form'
onSubmit={e => onSubmit(e)}
action='create-profile.html'
>
<div className='form-group'>
<input
type='password'
placeholder='Password'
name='password'
value={password}
onChange={e => onChange(e)}
/>
</div>
<div className='form-group'>
<input
type='password'
placeholder='Confirm Password'
name='password2'
value={password2}
onChange={e => onChange(e)}
/>
</div>
<input type='submit' className='btn btn-primary' value='Register' />
</form>
<p className='my-1'>
Already have an account? <Link to='/login'>Sign In</Link>
</p>
</section>
</Fragment>
);
};
Reset.propTypes = {
setAlert: PropTypes.func.isRequired,
reset: PropTypes.func.isRequired
};
export default connect(
null,
{ setAlert, reset }
)(Reset);
resetaction.JS
export const reset = ({ password, token }) => async dispatch => {
const config = {
headers: {
'Content-Type': 'application/json'
}
};
const body = JSON.stringify({ password, token });
try {
const res = await axios.put(
`http://localhost:3000/api/auth/reset/${token}`,
body,
config
);
dispatch({
type: RESET_PASSWORD,
payload: res.data
});
} catch (err) {
const errors = err.response.data.errors;
if (errors) {
errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
}
}
};
By only seeing this snippet I assume your problems are following lines:
const Reset = ({ setAlert, reset }) => {
//...
const token = props.match.params.token;
You destructed the whole props argument (into { setAlert, reset }), so in your case props is undefined. You should adapt your code to this:
const Reset = ({ setAlert, reset, match }) => {
//...
const token = match.params.tok
Related
I'm trying to implement a firebase email verification process while signup using reactjs in my local. I have implemented the createUserWithEmailAndPassword default function along with the sendEmailVerification function. Once a new user is created, they are getting a confirmation email on their respective mail IDs but if the user tries to verify the email we are getting the below error as a response in signInWithEmailLink. We have tried with SSL in localhost 'https://localhost' but still the same issue.
Error
{code: 'auth/argument-error', message: 'Invalid email link!', a: null}
signin.js
import React, { useRef } from 'react'
import { auth } from '../firebase';
import './Signin.css'
const Signin = () => {
const emailRef = useRef(null);
const passwordRef = useRef(null);
const signUp = e => {
e.preventDefault();
auth.createUserWithEmailAndPassword(
emailRef.current.value,
passwordRef.current.value
).then(userCredential => {
userCredential.user.sendEmailVerification();
console.log(userCredential,'userCredential')
//auth.signOut();
return userCredential;
}).catch(err => {
console.log(err)
})
}
const signIn = e => {
e.preventDefault();
auth.signInWithEmailAndPassword(
emailRef.current.value,
passwordRef.current.value
).then(user => {
console.log(user)
}).catch(err => {
console.log(err)
})
}
const confirm = e =>{
const locationCode = window.location.href;
e.preventDefault();
auth.signInWithEmailLink(emailRef.current.value, locationCode)
.then((result) => {
console.log(result,'result')
})
.catch((err) => {
console.log(err,'err')
});
}
return (
<div className="signin">
<form action="">
<h1>Sign in</h1>
<input ref={emailRef} type="email" />
<input ref={passwordRef} type="password" />
<button onClick={signIn}>Sign in </button>
<button onClick={confirm}>confirm </button>
<h6>Not yet register? <span onClick={signUp} className="signin__link">Sign up</span></h6>
</form>
</div>
)
}
export default Signin
I am struggling with Login page.
This is the actions/login.js:
export const login = (username, password) => (dispatch) => {
return AuthService.login(username, password).then(
(data) => {
debugger;
dispatch({
type: LOGIN_SUCCESS,
payload: { user: data },
});
return Promise.resolve();
},
(error) => {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
dispatch({
type: LOGIN_FAIL,
});
dispatch({
type: SET_MESSAGE,
payload: message,
});
return Promise.reject();
}
);
};
This is my AuthService.js :
import {BASE_URL} from "../constants/globalConstants";
import axios from "axios";
export const USER_INFO = 'USER_INFO';
const loginEndpoint = BASE_URL + "authenticate";
class AuthService {
login(username, password) {
debugger;
return axios
.post(BASE_URL + "authenticate", { username, password })
.then((response) => {
if (response.data.jwtToken) {
localStorage.setItem(USER_INFO, JSON.stringify(response.data));
}
return response.data;
});
}
logout() {
localStorage.removeItem(USER_INFO);
}
register(username, email, password) {
return axios.post(BASE_URL + "register", {
username,
email,
password,
});
}
}
export default new AuthService();
And finally the Login.js:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Link } from "react-router-dom";
import { Container, Row, Col, Card, CardBody, FormGroup, Label, Input, Button } from "reactstrap";
import { AvForm, AvField } from "availity-reactstrap-validation";
import axios from 'axios'
import { bindActionCreators } from "redux";
import { selectedSidebarStyle } from "../../actions/sidebarStyleAction";
import { connect } from "react-redux";
import tokenIsValid from './authrorization/JwtAuthorization'
import './../../static/css/Auth.css'
import { BASE_URL } from "../../constants/globalConstants";
import AuthService from "../../services/AuthService";
import { login } from "../../actions/auth";
export const USER_NAME_SESSION_ATTRIBUTE_NAME = 'authenticatedUser';
export const JWT_AUTH_TOKEN = 'AUTH_TOKEN';
export const USER_INFO = 'USER_INFO';
const style = { border: '1px solid #FB3E3E' }
class Login extends Component {
constructor(props) {
super(props);
this.state = {
email: "",
password: "",
userAuth: false,
loading: false,
}
}
handleFieldChange = (event) => {
this.setState({
[event.target.name]: event.target.value
})
}
// this.props.history.push(`/welcome/${this.state.username}`)
requestLogin = () => {
const loginEndpoint = BASE_URL + "authenticate";
axios({
method: 'post',
url: loginEndpoint,
data: {
username: this.state.username,
password: this.state.password
}
}).then((response) => {
if (response.data !== null) {
sessionStorage.setItem(USER_INFO, JSON.stringify(response.data));
}
}, (error) => {
console.log("Unsuccessful login request")
})
}
authHeader() {
const user = JSON.parse(localStorage.getItem(USER_INFO));
if (user && user.jwtToken) {
return { Authorization: 'Bearer ' + user.jwtToken };
} else {
return {};
}
}
isUserLoggedIn() {
let user = window.sessionStorage.getItem(USER_INFO)
if (user === null) {
return false
}
return true;
}
getLoggedInUserName() {
let user = window.sessionStorage.getItem(USER_INFO)
if (user === null) {
return ''
}
return user
}
/*
* TODO: See where to use the logout and how to redirect the user to the login page in case JWT token is expired
* */
logout() {
sessionStorage.removeItem(USER_INFO);
}
handleSubmit = (e) => {
e.preventDefault();
const {dispatch} = this.props;
dispatch(login(this.state.username, this.state.password))
.then(() => {
window.location.reload();
})
.catch(() => {
this.setState({
loading: false
});
});
}
render() {
return (
<React.Fragment>
<div className="account-home-btn d-none d-sm-block">
<Link to="/" className="text-white"><i className="mdi mdi-home h1"></i></Link>
</div>
<section className="bg-account-pages height-100vh">
<img className={"hive-logo1"} src={require('./hive-logo.png')} alt="Logo" width="70px" height="60px" />
<div className="display-table">
<div className="display-table-cell">
<Container>
<Row className="justify-content-center">
<Col lg={5}>
<Card className="account-card">
<CardBody>
<div className="text-center mt-3">
<h3 className="font-weight-bold"><a href=""
className="text-dark text-uppercase account-pages-logo">Sign In</a>
</h3>
<u><p className="text-muted">Enter your credentials to continue to the platform.</p></u>
</div>
<div className="p-3">
<AvForm onSubmit={this.handleSubmit}>
<FormGroup>
<Label htmlFor="username">Email</Label>
<AvField type="text" name="username" value={this.state.email}
onChange={this.handleFieldChange} required className="form-control"
id="username"
placeholder="Enter email" />
</FormGroup>
<FormGroup>
<Label htmlFor="userpassword">Password</Label>
<AvField type="password" name="password" value={this.state.password}
onChange={this.handleFieldChange} required className="form-control"
id="userpassword" placeholder="Enter password" />
</FormGroup>
<div className="custom-control custom-checkbox">
<Input type="checkbox" className="custom-control-input" id="customControlInline" />
<Label className="custom-control-label" htmlFor="customControlInline">Remember
me</Label>
</div>
<div className="mt-3">
<Button color="none" type="submit" className="sign-in-button" >Sign In</Button>
</div>
<div className="mt-4 mb-0 text-center">
<Link to="password_forget" className="text-dark"><i className="mdi mdi-lock"></i> Forgot
your password?</Link>
</div>
</AvForm>
</div>
</CardBody>
</Card>
</Col>
</Row>
</Container>
</div>
</div>
</section>
</React.Fragment>
);
}
}
Login.PropTypes = {
dispatch: PropTypes.func,
login: PropTypes.func
};
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
login
}, dispatch)
};
}
const mapStateToProps = (state) => {
const { isLoggedIn } = state.auth;
const { message } = state.message;
return {
isLoggedIn,
message
};
}
export default connect(mapStateToProps, mapDispatchToProps)(Login);
And I made so many changes and I can't fix this:
enter image description here
I am trying to push the login details, fetched from the bckend to the Session Storage and push it to the Redux so I can fetch the data later after loging and keep the token, id, password and email for the user
Somewhere in the documentation I have read that if we use mapDispatchToProps function in the connect method then the component will not get dispatch function as props .I tried finding the document link but could not get it.
try debugging component props to see dispatch function is there or not
You are already binding login with the dispatch.
So to call that, you need to do this;
this.props.login(...)
instead of this;
dispatch(login(...))
Functions in mapDispatchToProps are added to dispatch and if you call them like this this.props.function_name(), they are dispatched too.
I am trying to submit a POST form with a simple html form and I also use redux with a userAction which allows to store the user and the token returned by the express js API, but the submission does not work, when I submit the form, nothing happens I can't even get into the fetch function of the action.
import '../styles/ConnexionModal.css';
import { userLogin } from '../redux/userActions';
import { useState } from 'react';
// import { useSelector } from 'react-redux';
const ConnexionModal = ({ showModal, hideModal }) => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
// const message = useSelector(state => state.userReducer.message);
// console.log(message);
const handleChangeEmail = (event) => {
setEmail(event.target.value);
}
const handleChangePassword = (event) => {
setPassword(event.target.value);
}
const handleSubmit = (e) => {
e.preventDefault();
userLogin(email, password);
}
return (
showModal && (
<div className="modalBg">
<div className="modalContainer">
<div className="modalHeader">
<h1 className="modalTitle">Connexion</h1>
</div>
<div className="modalBody">
<form method="POST" onSubmit={handleSubmit}>
<div className="formGroup">
<label htmlFor="email" className="info">Email</label>
<input className="field" name="email" id="email" type="email" value={email} onChange={handleChangeEmail} autoFocus required />
</div>
<div className="formGroup">
<label htmlFor="password" className="info">Mot de passe</label>
<input className="field" name="password" id="password" type="password" value={password} onChange={handleChangePassword} required />
</div>
<div className="formGroup">
<label htmlFor="connexion" className="submitButton">Se connecter</label>
<input className="field submit" id="connexion" name="submit" type="submit" />
</div>
</form>
</div>
<div className="close">
<button onClick={() => hideModal()} className="closeButton">Fermer</button>
</div>
</div>
</div>
)
)
}
export default ConnexionModal;
export const LOGIN = "LOGIN";
export const ERROR = "ERROR";
export const userLogin = (email, password) => {
return async dispatch => {
console.log('test');
fetch('http://192.168.1.36:4000/api/users/login', {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({
email: email,
password: password
})
})
.then((res) => res.json())
.then(async (res) => {
if(!res.error) {
localStorage.setItem('auth', res.token);
dispatch({ type: LOGIN, user: res.user, token: res.token });
} else {
dispatch({ type: ERROR, message: res.error });
}
})
}
}
The console.log ('test') does not display anything which means I am not even accessing the userLogin function in my component.
I assume you are also using redux-thunk.
You should always pass the action inside your container to a redux dispatch function. E.g.
import '../styles/ConnexionModal.css';
import { userLogin } from '../redux/userActions';
import { useState } from 'react';
import { useDispatch } from 'react-redux';
const ConnexionModal = ({ showModal, hideModal }) => {
const dispatch = useDispatch();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleChangeEmail = (event) => {
setEmail(event.target.value);
}
const handleChangePassword = (event) => {
setPassword(event.target.value);
}
const handleSubmit = (e) => {
e.preventDefault();
dispatch(userLogin(email, password));
}
...
i have created a login form where user need to input his email id and OTP. below is my code -
import { useState } from 'react';
import axios from '../api/axios';
const useLogin = () => {
const [user, setUser] = useState(false);
const auth = async (value, OTP) => {
let config = {
method: 'POST',
url: '/api/user/generateToken',
headers: {
Authorization: 'value'
},
data: {
username: value,
password: OTP
}
};
try {
const response = await axios(config);
if (response.data.Status === "Failure") {
throw response.data.Message;
} else {
setUser(true);
return { status: response.data.Status, isAuth: user }
}
} catch (err) {
setUser(false);
return { status: undefined, message: err, isAuth: user };
}
}
return { auth, user };
}
export default useLogin
Everything is working fine here only problem is when i'm calling this function in my component i'll receive isAuth always false. Below is my component code -
import React, { Fragment, useRef, useEffect, useState } from 'react';
import { useLocation, useHistory } from "react-router-dom";
import { css } from "#emotion/core";
import ScaleLoader from "react-spinners/ScaleLoader";
import '../css/login.css';
import '../css/common.css';
import logo from '../assets/engageLogo.png';
import * as Yup from 'yup';
import { useFormik } from 'formik';
import useLogin from './../hooks/useOTP';
const override = css`
display: block;
margin: 0 auto;
border-color: #fff;
`;
const OTP = () => {
const [loading, setLoading] = useState(false);
const [color] = useState("#ffffff");
const [APIResponse, setAPIResponse] = useState(false);
const [APIMessage, setAPIMessage] = useState('')
const login = useLogin();
const location = useLocation();
const history = useHistory();
const inputRef = useRef();
const readRef = useRef();
const buttonRef = useRef();
const schema = Yup.object({
otp: Yup.string().required("OTP is Required")
});
const handleChangeError = () => {
return setAPIResponse(false)
}
const {
handleSubmit,
handleChange,
handleBlur,
touched,
errors,
} = useFormik({
initialValues: {
otp: "",
},
validationSchema: schema,
onSubmit: (values) => {
console.log(JSON.stringify(values));
buttonRef.current.disabled = true;
setLoading(true);
const loginCall = login.auth(location.state.email, values.otp);
loginCall.then(response => {
if (response.status === undefined || response.status === null) {
setLoading(false);
buttonRef.current.disabled = false;
setAPIResponse(true)
setAPIMessage(response.message)
} else {
setLoading(false);
history.push({
pathname: '/dashboard',
state: { email: values.email }
});
}
})
},
});
useEffect(() => {
inputRef.current.focus();
readRef.current.value = location.state.email;
}, [location])
return <Fragment>
<div className="centered-form">
<div className="centered-form__box">
<div className="mb-3 text-center">
<img src={logo} className="img-fluid" width="150" alt="Logo" />
</div>
<form onSubmit={handleSubmit} noValidate>
<div className="mb-3">
<label htmlFor="readEmail" className="form-label">Email</label>
<input
type="text"
name="readEmail"
id="readEmail"
ref={readRef}
className="form-control" readOnly />
</div>
<div className="mb-3">
<label htmlFor="otp" className="form-label">OTP</label>
<input
type="text"
name="otp"
id="otp"
ref={inputRef}
onChange={(e) => { handleChange(e); handleChangeError(e) }}
onBlur={handleBlur}
className="form-control" placeholder="Enter OTP" required />
{touched.otp && errors.otp
? <div className="invalid-feedback">Please enter valid OTP</div>
: null}
{APIResponse
? <div className="invalid-feedback">{APIMessage}</div>
: null}
</div>
<div className="d-grid gap-2">
<button ref={buttonRef} className="btn btn-main">{loading ?
<ScaleLoader color={color} loading={loading} css={override} height={15} /> : <span>Login</span>}</button>
</div>
</form>
</div>
</div>
</Fragment>
}
export default OTP
in response of loginCall i'll always get isAuth: false.
I want to use isAuth for protecting my routes. Just to check whether user has logged in or not.
why setUser is not updating the value here.
thanks in advance...
That's because by the time you returning your isAuth value the new user value is not set yet. you need to know that React setState is asynchronous function.
just use the the boolean itself directly like this:
setUser(true);
return { status: response.data.Status, isAuth: true }
or in case of a rejection:
setUser(false);
return { status: undefined, message: err, isAuth: false };
I'm working on a login system. When user input email and password and click submit I'm calling my endpoint to verify the credentials with mapDispatchToProps, if login is correct I update the app state with token and auth:true, otherwise I need to publish the error. How can I read the response error message (that coming from api backend json response)?
I'm looking to read the response of the dispatched usersLogin() function.
import React, { Component } from "react";
import { connect } from "react-redux";
import { usersLogin } from "../../actions/index";
import { Link } from "react-router-dom";
import i18n from "../../i18n";
function mapDispatchToProps(dispatch) {
return {
usersLogin: login => dispatch(usersLogin(login))
};
}
class ConnectedLoginForm extends Component {
constructor() {
super();
this.state = {
email: "",
password: ""
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ [event.target.id]: event.target.value });
}
handleSubmit(event) {
event.preventDefault();
const { email } = this.state;
const { password } = this.state;
this.props.usersLogin({ email, password });
this.setState({ email: email, password: password });
}
render() {
const { email } = this.state;
const { password } = this.state;
console.log("this.props");
console.log(this.props.usersLogin);
return (
<form onSubmit={this.handleSubmit} className="login-form">
<div className="form-group">
<h2>{ i18n.t("Login") }</h2>
<input
type="text"
className="input-text"
id="email"
value={email}
onChange={this.handleChange}
placeholder="Email"
autoCorrect="off" autoCapitalize="none"
/>
<input
type="text"
className="input-text"
id="password"
value={password}
onChange={this.handleChange}
placeholder="Password"
autoCorrect="off" autoCapitalize="none"
/>
<button type="submit" className="button btn-primary">
Login
</button>
<div className="other-action">
<Link to="/logout">Registrati</Link>
<Link to="/logout">Password dimenticata</Link>
</div>
</div>
</form>
);
}
}
const Loginform = connect(null, mapDispatchToProps)(ConnectedLoginForm);
export default Loginform;
Sure, this is my login function, in a redux middleware:
const reqBody = { email: action.payload.email, password: action.payload.password };
const cfg = { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } };
axios.post(endpoint.users+'/login', qs.stringify(reqBody), cfg)
.then((result) => {
return dispatch({ type: "USERS_LOGIN_SUCCESS", payload : {token: result.data.token, auth: true } } );
})
.catch((err) => {
return dispatch({ type: "USERS_LOGIN_ERROR", payload : {token: '', auth: false } } );
})
Thank you everyone, I've changed my approach. I've installed react-toastify and I've putted the error notification in the catch block of the ajax call in the middleware.
.catch((err) => {
toast.error(i18n.t(err.response.data.errorMessage) );
return dispatch({ type: "USERS_LOGIN_ERROR", payload : { user : { token: '', auth: false } } } );
})
The solution seems to fit my need for now.