diff --git a/client/constants.js b/client/constants.js index da70c015..77b3ff51 100644 --- a/client/constants.js +++ b/client/constants.js @@ -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'; diff --git a/client/modules/IDE/components/LoginView.js b/client/modules/IDE/components/LoginView.js index 2ec78f04..393d1acf 100644 --- a/client/modules/IDE/components/LoginView.js +++ b/client/modules/IDE/components/LoginView.js @@ -18,9 +18,14 @@ class LoginView extends React.Component { {/*

Or

*/} - Signup - Or - Reset your password +

+ Don't have an account?  + Sign Up +

+

+ Forgot your password?  + Reset your password +

Cancel ); @@ -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'; diff --git a/client/modules/IDE/components/ResetPasswordForm.js b/client/modules/IDE/components/ResetPasswordForm.js new file mode 100644 index 00000000..d4c7d81a --- /dev/null +++ b/client/modules/IDE/components/ResetPasswordForm.js @@ -0,0 +1,32 @@ +import React, { PropTypes } from 'react'; + +function ResetPasswordForm(props) { + const { fields: { email }, handleSubmit, submitting, invalid, pristine } = props; + return ( +
+

+ +

+ +
+ ); +} + +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; diff --git a/client/modules/IDE/components/ResetPasswordView.js b/client/modules/IDE/components/ResetPasswordView.js index 9f18866c..18e5c3a7 100644 --- a/client/modules/IDE/components/ResetPasswordView.js +++ b/client/modules/IDE/components/ResetPasswordView.js @@ -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 ( -
-

Forgot Password

+
+

Reset Your Password

+ Login or Sign up @@ -17,4 +22,28 @@ class ResetPasswordView extends React.Component {
); } -} \ No newline at end of file +} + +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); diff --git a/client/modules/User/actions.js b/client/modules/User/actions.js index ecdfa3c5..2ab47918 100644 --- a/client/modules/User/actions.js +++ b/client/modules/User/actions.js @@ -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})); + } +} + diff --git a/client/styles/components/_forms.scss b/client/styles/components/_forms.scss index ed131ec1..9c6a5af5 100644 --- a/client/styles/components/_forms.scss +++ b/client/styles/components/_forms.scss @@ -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; } \ No newline at end of file diff --git a/client/styles/components/_reset-password.scss b/client/styles/components/_reset-password.scss new file mode 100644 index 00000000..5bd6d662 --- /dev/null +++ b/client/styles/components/_reset-password.scss @@ -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; +} \ No newline at end of file diff --git a/client/styles/main.scss b/client/styles/main.scss index e10c2b62..22a53443 100644 --- a/client/styles/main.scss +++ b/client/styles/main.scss @@ -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'; diff --git a/server/controllers/user.controller.js b/server/controllers/user.controller.js index e21b9d92..b3b93c69 100644 --- a/server/controllers/user.controller.js +++ b/server/controllers/user.controller.js @@ -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 + }); +} diff --git a/server/routes/user.routes.js b/server/routes/user.routes.js index c40f4924..9abf70af 100644 --- a/server/routes/user.routes.js +++ b/server/routes/user.routes.js @@ -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;