From 0a51cce555c69a24c0daa7f8be2ccd078e9c5f79 Mon Sep 17 00:00:00 2001 From: Bogdan Cochior <bogdan.cochior@thinslices.com> Date: Wed, 11 Jul 2018 15:45:30 +0300 Subject: [PATCH] feat(change-password): implement change password UI form --- .../components/UserProfile/AccountDetails.js | 3 +- .../UserProfile/AccountDetailsCard.js | 5 +- .../UserProfile/ChangePasswordPage.js | 98 +++++++++++++++++++ .../components/UserProfile/UserProfilePage.js | 2 +- .../src/components/index.js | 1 + .../src/components/utils.js | 23 +++++ packages/xpub-faraday/app/routes.js | 10 +- 7 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 packages/components-faraday/src/components/UserProfile/ChangePasswordPage.js diff --git a/packages/components-faraday/src/components/UserProfile/AccountDetails.js b/packages/components-faraday/src/components/UserProfile/AccountDetails.js index 5932cb212..768c8a46e 100644 --- a/packages/components-faraday/src/components/UserProfile/AccountDetails.js +++ b/packages/components-faraday/src/components/UserProfile/AccountDetails.js @@ -6,7 +6,7 @@ import { compose, withHandlers, withState } from 'recompose' import AccountDetailsCard from './AccountDetailsCard' import AccountDetailsEdit from './AccountDetailsEdit' -const AccountDetails = ({ user, isEdit, setEditMode, journal }) => ( +const AccountDetails = ({ user, isEdit, setEditMode, journal, history }) => ( <Root> {isEdit ? ( <AccountDetailsEdit @@ -16,6 +16,7 @@ const AccountDetails = ({ user, isEdit, setEditMode, journal }) => ( /> ) : ( <AccountDetailsCard + history={history} journal={journal} setEditMode={setEditMode} user={user} diff --git a/packages/components-faraday/src/components/UserProfile/AccountDetailsCard.js b/packages/components-faraday/src/components/UserProfile/AccountDetailsCard.js index db9172efa..22dadc2aa 100644 --- a/packages/components-faraday/src/components/UserProfile/AccountDetailsCard.js +++ b/packages/components-faraday/src/components/UserProfile/AccountDetailsCard.js @@ -13,6 +13,7 @@ import { getUserTitle } from '../utils' const AccountDetailsCard = ({ user: { firstName = '', lastName = '', affiliation = '-', title = '' }, journal, + history, setEditMode, }) => ( <Fragment> @@ -48,7 +49,9 @@ const AccountDetailsCard = ({ <Row noMargin> <RowItem> <LinkText onClick={() => setEditMode(true)}>Edit details</LinkText> - <LinkText>Change Password</LinkText> + <LinkText onClick={() => history.push('/profile/change-password')}> + Change Password + </LinkText> </RowItem> </Row> </Fragment> diff --git a/packages/components-faraday/src/components/UserProfile/ChangePasswordPage.js b/packages/components-faraday/src/components/UserProfile/ChangePasswordPage.js new file mode 100644 index 000000000..8405473a8 --- /dev/null +++ b/packages/components-faraday/src/components/UserProfile/ChangePasswordPage.js @@ -0,0 +1,98 @@ +import React from 'react' +import { compose } from 'recompose' +import { connect } from 'react-redux' +import { reduxForm } from 'redux-form' +import styled from 'styled-components' +import { required } from 'xpub-validators' +import { selectCurrentUser } from 'xpub-selectors' +import { Button, th, TextField, ValidatedField } from '@pubsweet/ui' +import { + onSubmitChangePassword as onSubmit, + changePasswordValidator, +} from '../utils' + +import { Row, RowItem, Label, Title, Err } from '../UIComponents/FormItems' + +const PasswordField = input => <TextField {...input} type="password" /> + +const ChangePassword = ({ history, handleSubmit, error }) => ( + <Root> + <Form onSubmit={handleSubmit}> + <Row> + <RowItem vertical> + <Title>Change Password</Title> + </RowItem> + </Row> + <Row> + <RowItem vertical> + <Label>Current Password *</Label> + <ValidatedField + component={PasswordField} + name="password" + validate={[required]} + /> + </RowItem> + </Row> + <Row> + <RowItem vertical> + <Label>New Password *</Label> + <ValidatedField + component={PasswordField} + name="newPassword" + validate={[required]} + /> + </RowItem> + </Row> + <Row> + <RowItem vertical> + <Label>Re-type password *</Label> + <ValidatedField + component={PasswordField} + name="confirmNewPassword" + validate={[required]} + /> + </RowItem> + </Row> + {error && ( + <Row> + <RowItem> + <Err>{error}</Err> + </RowItem> + </Row> + )} + <Row /> + <Row> + <Button onClick={history.goBack}>Cancel</Button> + <Button primary type="submit"> + Update + </Button> + </Row> + </Form> + </Root> +) + +export default compose( + connect(state => ({ + user: selectCurrentUser(state), + })), + reduxForm({ + form: 'changePassword', + onSubmit, + validate: changePasswordValidator, + }), +)(ChangePassword) + +// #region styles +const Root = styled.div` + display: flex; + flex-direction: column; + max-width: 30em; + margin: 0 auto; +` +const Form = styled.form` + background-color: ${th('colorBackground')}; + padding: ${th('gridUnit')}; + border: ${th('borderDefault')}; +` + +// #endregion diff --git a/packages/components-faraday/src/components/UserProfile/UserProfilePage.js b/packages/components-faraday/src/components/UserProfile/UserProfilePage.js index 75f207cfb..64dd9d28e 100644 --- a/packages/components-faraday/src/components/UserProfile/UserProfilePage.js +++ b/packages/components-faraday/src/components/UserProfile/UserProfilePage.js @@ -19,7 +19,7 @@ const UserProfilePage = ({ history, user }) => ( title="Account Settings" underlined /> - <AccountDetails user={user} /> + <AccountDetails history={history} user={user} /> <EmailNotifications subscribed={get(user, 'subscription')} /> <LinkOrcID orcid={get(user, 'orcid')} /> </Root> diff --git a/packages/components-faraday/src/components/index.js b/packages/components-faraday/src/components/index.js index 54fdcb573..ddc29a62c 100644 --- a/packages/components-faraday/src/components/index.js +++ b/packages/components-faraday/src/components/index.js @@ -9,6 +9,7 @@ export { default as AuthorList } from './AuthorList/AuthorList' export { default as withVersion } from './Dashboard/withVersion.js' export { default as SortableList } from './SortableList/SortableList' export { default as UserProfilePage } from './UserProfile/UserProfilePage' +export { default as ChangePasswordPage } from './UserProfile/ChangePasswordPage' export { Decision } export { Components } diff --git a/packages/components-faraday/src/components/utils.js b/packages/components-faraday/src/components/utils.js index e6dbf37df..e791983b4 100644 --- a/packages/components-faraday/src/components/utils.js +++ b/packages/components-faraday/src/components/utils.js @@ -98,6 +98,20 @@ export const passwordValidator = values => { return errors } +export const changePasswordValidator = values => { + const errors = {} + if (!values.password) { + errors.password = 'Required' + } + if (!values.newPassword) { + errors.newPassword = 'Required' + } else if (values.newPassword !== values.confirmNewPassword) { + errors.confirmNewPassword = 'Password mismatched' + } + + return errors +} + export const parseSearchParams = url => { const params = new URLSearchParams(url) const parsedObject = {} @@ -124,6 +138,7 @@ export const parseUpdateUser = values => { return pick(values, valuesToSave) } +// TODO: move to a dataservice export const onSubmitUser = (values, dispatch, { setEditMode }) => update(`/users/${values.id}`, parseUpdateUser(values)) .then(user => { @@ -131,3 +146,11 @@ export const onSubmitUser = (values, dispatch, { setEditMode }) => dispatch(actions.getCurrentUser()) }) .catch(handleFormError) + +// Temporary till API implementation +export const onSubmitChangePassword = (values, dispatch, { history, user }) => + update(`/users/${values.id}`, parseUpdateUser(values)) + .then(() => { + history.goBack() + }) + .catch(handleFormError) diff --git a/packages/xpub-faraday/app/routes.js b/packages/xpub-faraday/app/routes.js index 77dff3d32..826ed981b 100644 --- a/packages/xpub-faraday/app/routes.js +++ b/packages/xpub-faraday/app/routes.js @@ -3,7 +3,10 @@ import { Route, Switch } from 'react-router-dom' import { AuthenticatedComponent } from 'pubsweet-client' import { Wizard } from 'pubsweet-component-wizard/src/components' -import { UserProfilePage } from 'pubsweet-components-faraday/src/components' +import { + UserProfilePage, + ChangePasswordPage, +} from 'pubsweet-components-faraday/src/components' import { ManuscriptPage } from 'pubsweet-component-manuscript/src/components' import DashboardPage from 'pubsweet-components-faraday/src/components/Dashboard' import LoginPage from 'pubsweet-components-faraday/src/components/Login/LoginPage' @@ -83,6 +86,11 @@ const Routes = () => ( <Route component={ConfirmAccount} exact path="/confirm-signup" /> <PrivateRoute component={DashboardPage} exact path="/" /> <PrivateRoute component={UserProfilePage} exact path="/profile" /> + <PrivateRoute + component={ChangePasswordPage} + exact + path="/profile/change-password" + /> <PrivateRoute component={ConfirmationPage} exact -- GitLab