more password reset stuff

This commit is contained in:
Cassie Tarakajian 2016-10-12 14:25:24 -04:00
parent 1610b0168d
commit ea6d30c430
10 changed files with 116 additions and 8 deletions

View File

@ -93,5 +93,7 @@ export const END_SKETCH_REFRESH = 'END_SKETCH_REFRESH';
export const DETECT_INFINITE_LOOPS = 'DETECT_INFINITE_LOOPS';
export const RESET_INFINITE_LOOPS = 'RESET_INFINITE_LOOPS';
export const RESET_PASSWORD_INITIATE = 'RESET_PASSWORD_INITIATE';
// eventually, handle errors more specifically and better
export const ERROR = 'ERROR';

View File

@ -18,9 +18,14 @@ class LoginView extends React.Component {
<LoginForm {...this.props} />
{/* <h2 className="login__divider">Or</h2>
<GithubButton buttonText="Login with Github" /> */}
<Link className="form__signup-button" to="/signup">Signup</Link>
Or
<Link className="form__reset-password-button" to="/reset-password">Reset your password</Link>
<p className="form__navigation-options">
Don't have an account?&nbsp;
<Link className="form__signup-button" to="/signup">Sign Up</Link>
</p>
<p className="form__navigation-options">
Forgot your password?&nbsp;
<Link className="form__reset-password-button" to="/reset-password">Reset your password</Link>
</p>
<Link className="form__cancel-button" to="/">Cancel</Link>
</div>
);
@ -42,7 +47,7 @@ function mapDispatchToProps() {
function validate(formProps) {
const errors = {};
if (!formProps.email) {
errors.email = 'Please enter a email';
errors.email = 'Please enter an email';
}
if (!formProps.password) {
errors.password = 'Please enter a password';

View File

@ -0,0 +1,32 @@
import React, { PropTypes } from 'react';
function ResetPasswordForm(props) {
const { fields: { email }, handleSubmit, submitting, invalid, pristine } = props;
return (
<form className="reset-password-form" onSubmit={handleSubmit(props.initiateResetPassword.bind(this))}>
<p className="reset-password-form__field">
<input
className="reset-password-form__email-input"
aria-label="email"
type="text"
placeholder="Email used for registration"
{...email}
/>
</p>
<input type="submit" disabled={submitting || invalid || pristine} value="Send email to reset password" aria-label="Send email to reset password" />
</form>
);
}
ResetPassword.propTypes = {
fields: PropTypes.shape({
email: PropTypes.object.isRequired
}).isRequired,
handleSubmit: PropTypes.func.isRequired,
initiateResetPassword: PropTypes.func.isRequired,
submitting: PropTypes.bool,
invalid: PropTypes.bool,
pristine: PropTypes.bool
}
export default ResetPasswordForm;

View File

@ -1,15 +1,20 @@
import React from 'react';
import { Link } from 'react-router';
import * as UserActions from '../../User/actions';
import { bindActionCreators } from 'redux';
import { reduxForm } from 'redux-form';
import ResetPasswordForm from './ResetPasswordForm';
class ResetPasswordView extends React.Component {
componentDidMount() {
this.refs.forgotPassword.focus();
this.refs.resetPassword.focus();
}
render() {
return (
<div className="forgot-password" ref="forgotPassword" tabIndex="0">
<h1>Forgot Password</h1>
<div className="reset-password" ref="resetPassword" tabIndex="0">
<h1>Reset Your Password</h1>
<ResetPasswordForm {...this.props} />
<Link className="form__login-button" to="/login">Login</Link>
or
<Link className="form__signup-button" to="/signup">Sign up</Link>
@ -17,4 +22,28 @@ class ResetPasswordView extends React.Component {
</div>
);
}
}
}
function mapStateToProps(state) {
return {
user: state.user
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(UserActions, dispatch);
}
function validate(formProps) {
const errors = {};
if (!formProps.email) {
errors.email = 'Please enter an email'
}
return errors;
}
export default reduxForm({
form: 'reset-password',
fields: 'email',
validate
}, mapStateToProps, mapDispatchToProps)(ResetPasswordView);

View File

@ -105,3 +105,15 @@ export function logoutUser() {
};
}
export function initiatePasswordReset(formValues) {
return (dispatch) => {
axios.post(`${ROOT_URL}/reset-password`, formValues, { withCredentials: true})
.then(response => {
dispatch({
type: ActionTypes.RESET_PASSWORD_INITIATE
});
})
.catch(response => dispatch({ActionTypes.ERROR}));
}
}

View File

@ -8,4 +8,10 @@
.form__cancel-button {
margin-top: #{10 / $base-font-size}rem;
font-size: #{12 / $base-font-size}rem;
}
.form__navigation-options {
margin-top: #{10 / $base-font-size}rem;
font-size: #{12 / $base-font-size}rem;
}

View File

@ -0,0 +1,9 @@
.reset-password {
@extend %modal;
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
padding: #{20 / $base-font-size}rem;
align-items: center;
}

View File

@ -20,6 +20,7 @@
@import 'components/preferences';
@import 'components/signup';
@import 'components/login';
@import 'components/reset-password';
@import 'components/sketch-list';
@import 'components/sidebar';
@import 'components/modal';

View File

@ -72,3 +72,13 @@ export function updatePreferences(req, res) {
});
})
}
export function resetPasswordInitiate(req, res) {
User.findOne({ email: req.body.email }, (err, user) => {
if (!user) {
return res.json({message: 'If the email is registered with the editor, an email has been sent.'});
}
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
});
}

View File

@ -8,4 +8,6 @@ router.route('/signup/duplicate_check').get(UserController.duplicateUserCheck);
router.route('/preferences').put(UserController.updatePreferences);
router.route('/reset-password').post(UserController.resetPasswordInitiate);
export default router;