From 9d2d63e40e8d4e27b06bd6ebefc5b02812b9e141 Mon Sep 17 00:00:00 2001 From: Alexandru Munteanu <alexandru.munt@gmail.com> Date: Thu, 5 Jul 2018 15:51:07 +0300 Subject: [PATCH] feat(reset-password): implement the reset password flow --- .../components/SignUp/SignUpInvitationPage.js | 44 ++++++++- .../src/components/SignUp/SignUpStep1.js | 93 +++++++++++++++---- packages/xpub-faraday/app/routes.js | 28 +++++- 3 files changed, 140 insertions(+), 25 deletions(-) diff --git a/packages/components-faraday/src/components/SignUp/SignUpInvitationPage.js b/packages/components-faraday/src/components/SignUp/SignUpInvitationPage.js index dccbba131..b0f56d4f1 100644 --- a/packages/components-faraday/src/components/SignUp/SignUpInvitationPage.js +++ b/packages/components-faraday/src/components/SignUp/SignUpInvitationPage.js @@ -41,9 +41,30 @@ const signUpUser = history => (values, dispatch) => }) .catch(handleFormError) +const resetUserPassword = history => ({ email }, dispatch) => + create(`/users/forgot-password`, { email }) + .then(r => { + // go to dedicated route + history.push('/') + }) + .catch(handleFormError) + +const setNewPassword = history => ({ email, token, password }, dispatch) => + create(`/users/reset-password`, { email, token, password }) + .then(() => { + login(dispatch, { username: email, password }, history).then(() => + history.push('/'), + ) + }) + .catch(handleFormError) + export default compose( withJournal, - withState('step', 'changeStep', 0), + withState( + 'step', + 'changeStep', + ({ type }) => (type === 'forgotPassword' || type === 'setPassword' ? 1 : 0), + ), withProps(({ location }) => { const params = new URLSearchParams(location.search) const email = params.get('email') || '' @@ -67,13 +88,26 @@ export default compose( withHandlers({ nextStep: ({ changeStep }) => () => changeStep(step => step + 1), prevStep: ({ changeStep }) => () => changeStep(step => step - 1), - submitConfirmation: ({ + confirmInvitation: ({ initialValues: { email = '', token = '' }, history, }) => confirmUser(email, token, history), signUp: ({ history }) => signUpUser(history), + forgotPassword: ({ history }) => resetUserPassword(history), + setNewPassword: ({ history }) => setNewPassword(history), }), - withProps(({ type, signUp, submitConfirmation }) => ({ - onSubmit: type === 'signup' ? signUp : submitConfirmation, - })), + withProps( + ({ type, signUp, confirmInvitation, forgotPassword, setNewPassword }) => { + switch (type) { + case 'forgotPassword': + return { onSubmit: forgotPassword } + case 'signup': + return { onSubmit: signUp } + case 'setPassword': + return { onSubmit: setNewPassword } + default: + return { onSubmit: confirmInvitation } + } + }, + ), )(SignUpInvitation) diff --git a/packages/components-faraday/src/components/SignUp/SignUpStep1.js b/packages/components-faraday/src/components/SignUp/SignUpStep1.js index 062cfadd9..f221cccae 100644 --- a/packages/components-faraday/src/components/SignUp/SignUpStep1.js +++ b/packages/components-faraday/src/components/SignUp/SignUpStep1.js @@ -1,4 +1,4 @@ -import React from 'react' +import React, { Fragment } from 'react' import { reduxForm } from 'redux-form' import { required } from 'xpub-validators' import { Button, ValidatedField, TextField } from '@pubsweet/ui' @@ -11,20 +11,43 @@ const { Row, Err, Label, RowItem, FormContainer } = FormItems const PasswordField = input => <TextField {...input} type="password" /> const EmailField = input => <TextField {...input} type="email" /> -const Step1 = ({ handleSubmit, error, type, prevStep, submitting }) => ( - <FormContainer onSubmit={handleSubmit}> - {type === 'signup' && ( - <Row> - <RowItem vertical> - <Label>Email</Label> - <ValidatedField - component={EmailField} - name="email" - validate={[required, emailValidator]} - /> - </RowItem> - </Row> - )} +const SignUpForm = () => ( + <Fragment> + <Row> + <RowItem vertical> + <Label>Email</Label> + <ValidatedField + component={EmailField} + name="email" + validate={[required, emailValidator]} + /> + </RowItem> + </Row> + <Row> + <RowItem vertical> + <Label>Password</Label> + <ValidatedField + component={PasswordField} + name="password" + validate={[required]} + /> + </RowItem> + </Row> + <Row> + <RowItem vertical> + <Label>Confirm password</Label> + <ValidatedField + component={PasswordField} + name="confirmPassword" + validate={[required]} + /> + </RowItem> + </Row> + </Fragment> +) + +const InviteForm = () => ( + <Fragment> <Row> <RowItem vertical> <Label>Password</Label> @@ -45,6 +68,37 @@ const Step1 = ({ handleSubmit, error, type, prevStep, submitting }) => ( /> </RowItem> </Row> + </Fragment> +) + +const ForgotEmailForm = () => ( + <Fragment> + <Row> + <RowItem vertical> + <Label>Email</Label> + <ValidatedField + component={EmailField} + name="email" + validate={[required, emailValidator]} + /> + </RowItem> + </Row> + </Fragment> +) + +const withoutBack = ['forgotPassword', 'setPassword'] +const Step1 = ({ + error, + prevStep, + submitting, + handleSubmit, + type = 'invite', +}) => ( + <FormContainer onSubmit={handleSubmit}> + {type === 'signup' && <SignUpForm />} + {type === 'setPassword' && <InviteForm />} + {type === 'forgotPassword' && <ForgotEmailForm />} + {type === 'invite' && <InviteForm />} {error && ( <Row> <RowItem> @@ -53,10 +107,13 @@ const Step1 = ({ handleSubmit, error, type, prevStep, submitting }) => ( </Row> )} <Row /> + <Row> - <Button onClick={prevStep} type="button"> - BACK - </Button> + {!withoutBack.includes(type) && ( + <Button onClick={prevStep} type="button"> + BACK + </Button> + )} <Button disabled={submitting} primary type="submit"> CONFIRM </Button> diff --git a/packages/xpub-faraday/app/routes.js b/packages/xpub-faraday/app/routes.js index 4de1459d8..04c38a85b 100644 --- a/packages/xpub-faraday/app/routes.js +++ b/packages/xpub-faraday/app/routes.js @@ -26,7 +26,7 @@ import { import FaradayApp from './FaradayApp' -const LoginPage = withProps({ passwordReset: false })(Login) +const LoginPage = withProps({ passwordReset: true })(Login) const PrivateRoute = ({ component: Component, ...rest }) => ( <Route @@ -43,6 +43,7 @@ const Routes = () => ( <FaradayApp> <Switch> <Route component={LoginPage} exact path="/login" /> + <Route component={SignUpInvitationPage} exact path="/invite" /> <Route component={routeParams => ( <SignUpInvitationPage @@ -55,6 +56,30 @@ const Routes = () => ( exact path="/signup" /> + <Route + component={routeParams => ( + <SignUpInvitationPage + subtitle={null} + title="Reset password" + type="forgotPassword" + {...routeParams} + /> + )} + exact + path="/password-reset" + /> + <Route + component={routeParams => ( + <SignUpInvitationPage + subtitle={null} + title="Set new password" + type="setPassword" + {...routeParams} + /> + )} + exact + path="/forgot-password" + /> <Route component={ConfirmAccount} exact path="/confirm-signup" /> <PrivateRoute component={DashboardPage} exact path="/" /> <PrivateRoute @@ -75,7 +100,6 @@ const Routes = () => ( exact path="/projects/:project/versions/:version/submit" /> - <Route component={SignUpInvitationPage} exact path="/invite" /> <Route component={ReviewerSignUp} exact path="/invite-reviewer" /> <PrivateRoute component={ManuscriptPage} -- GitLab