mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-31 02:26:50 +10:00
Refactor PasswordChangeForm: use Form connector from Final Form
This commit is contained in:
parent
09dea3bdd1
commit
c415babb83
3 changed files with 200 additions and 159 deletions
|
|
@ -2,13 +2,13 @@ import React, { Component } from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import { compose } from 'redux';
|
||||
import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
|
||||
import { reduxForm, propTypes as formPropTypes } from 'redux-form';
|
||||
import { Form as FinalForm } from 'react-final-form';
|
||||
import classNames from 'classnames';
|
||||
import { propTypes } from '../../util/types';
|
||||
import * as validators from '../../util/validators';
|
||||
import { ensureCurrentUser } from '../../util/data';
|
||||
import { isChangePasswordWrongPassword } from '../../util/errors';
|
||||
import { Form, PrimaryButton, TextInputField } from '../../components';
|
||||
import { Form, PrimaryButton, FieldTextInput } from '../../components';
|
||||
|
||||
import css from './PasswordChangeForm.css';
|
||||
|
||||
|
|
@ -23,158 +23,173 @@ class PasswordChangeFormComponent extends Component {
|
|||
window.clearTimeout(this.resetTimeoutId);
|
||||
}
|
||||
render() {
|
||||
const {
|
||||
rootClassName,
|
||||
className,
|
||||
changePasswordError,
|
||||
currentUser,
|
||||
form,
|
||||
handleSubmit,
|
||||
submitting,
|
||||
inProgress,
|
||||
intl,
|
||||
invalid,
|
||||
pristine,
|
||||
ready,
|
||||
reset,
|
||||
} = this.props;
|
||||
|
||||
const user = ensureCurrentUser(currentUser);
|
||||
|
||||
if (!user.id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// New password
|
||||
const newPasswordLabel = intl.formatMessage({
|
||||
id: 'PasswordChangeForm.newPasswordLabel',
|
||||
});
|
||||
const newPasswordPlaceholder = intl.formatMessage({
|
||||
id: 'PasswordChangeForm.newPasswordPlaceholder',
|
||||
});
|
||||
const newPasswordRequiredMessage = intl.formatMessage({
|
||||
id: 'PasswordChangeForm.newPasswordRequired',
|
||||
});
|
||||
const newPasswordRequired = validators.requiredStringNoTrim(newPasswordRequiredMessage);
|
||||
|
||||
const passwordMinLengthMessage = intl.formatMessage(
|
||||
{
|
||||
id: 'PasswordChangeForm.passwordTooShort',
|
||||
},
|
||||
{
|
||||
minLength: validators.PASSWORD_MIN_LENGTH,
|
||||
}
|
||||
);
|
||||
const passwordMaxLengthMessage = intl.formatMessage(
|
||||
{
|
||||
id: 'PasswordChangeForm.passwordTooLong',
|
||||
},
|
||||
{
|
||||
maxLength: validators.PASSWORD_MAX_LENGTH,
|
||||
}
|
||||
);
|
||||
|
||||
const passwordMinLength = validators.minLength(
|
||||
passwordMinLengthMessage,
|
||||
validators.PASSWORD_MIN_LENGTH
|
||||
);
|
||||
const passwordMaxLength = validators.maxLength(
|
||||
passwordMaxLengthMessage,
|
||||
validators.PASSWORD_MAX_LENGTH
|
||||
);
|
||||
|
||||
// password
|
||||
const passwordLabel = intl.formatMessage({
|
||||
id: 'PasswordChangeForm.passwordLabel',
|
||||
});
|
||||
const passwordPlaceholder = intl.formatMessage({
|
||||
id: 'PasswordChangeForm.passwordPlaceholder',
|
||||
});
|
||||
const passwordRequiredMessage = intl.formatMessage({
|
||||
id: 'PasswordChangeForm.passwordRequired',
|
||||
});
|
||||
|
||||
const passwordRequired = validators.requiredStringNoTrim(passwordRequiredMessage);
|
||||
|
||||
const passwordFailedMessage = intl.formatMessage({
|
||||
id: 'PasswordChangeForm.passwordFailed',
|
||||
});
|
||||
const passwordErrorText = isChangePasswordWrongPassword(changePasswordError)
|
||||
? passwordFailedMessage
|
||||
: null;
|
||||
|
||||
const confirmClasses = classNames(css.confirmChangesSection, {
|
||||
[css.confirmChangesSectionVisible]: !pristine,
|
||||
});
|
||||
|
||||
const genericFailure =
|
||||
changePasswordError && !passwordErrorText ? (
|
||||
<span className={css.error}>
|
||||
<FormattedMessage id="PasswordChangeForm.genericFailure" />
|
||||
</span>
|
||||
) : null;
|
||||
|
||||
const classes = classNames(rootClassName || css.root, className);
|
||||
const submitDisabled = invalid || submitting || inProgress;
|
||||
|
||||
return (
|
||||
<Form
|
||||
className={classes}
|
||||
onSubmit={values => {
|
||||
handleSubmit(values)
|
||||
.then(() => {
|
||||
this.resetTimeoutId = window.setTimeout(reset, RESET_TIMEOUT);
|
||||
})
|
||||
.catch(() => {
|
||||
// Error is handled in duck file already.
|
||||
});
|
||||
<FinalForm
|
||||
{...this.props}
|
||||
render={fieldRenderProps => {
|
||||
const {
|
||||
rootClassName,
|
||||
className,
|
||||
formId,
|
||||
changePasswordError,
|
||||
currentUser,
|
||||
handleSubmit,
|
||||
submitting,
|
||||
inProgress,
|
||||
intl,
|
||||
invalid,
|
||||
pristine,
|
||||
ready,
|
||||
reset,
|
||||
} = fieldRenderProps;
|
||||
|
||||
const user = ensureCurrentUser(currentUser);
|
||||
|
||||
if (!user.id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// New password
|
||||
const newPasswordLabel = intl.formatMessage({
|
||||
id: 'PasswordChangeForm.newPasswordLabel',
|
||||
});
|
||||
const newPasswordPlaceholder = intl.formatMessage({
|
||||
id: 'PasswordChangeForm.newPasswordPlaceholder',
|
||||
});
|
||||
const newPasswordRequiredMessage = intl.formatMessage({
|
||||
id: 'PasswordChangeForm.newPasswordRequired',
|
||||
});
|
||||
const newPasswordRequired = validators.requiredStringNoTrim(newPasswordRequiredMessage);
|
||||
|
||||
const passwordMinLengthMessage = intl.formatMessage(
|
||||
{
|
||||
id: 'PasswordChangeForm.passwordTooShort',
|
||||
},
|
||||
{
|
||||
minLength: validators.PASSWORD_MIN_LENGTH,
|
||||
}
|
||||
);
|
||||
const passwordMaxLengthMessage = intl.formatMessage(
|
||||
{
|
||||
id: 'PasswordChangeForm.passwordTooLong',
|
||||
},
|
||||
{
|
||||
maxLength: validators.PASSWORD_MAX_LENGTH,
|
||||
}
|
||||
);
|
||||
|
||||
const passwordMinLength = validators.minLength(
|
||||
passwordMinLengthMessage,
|
||||
validators.PASSWORD_MIN_LENGTH
|
||||
);
|
||||
const passwordMaxLength = validators.maxLength(
|
||||
passwordMaxLengthMessage,
|
||||
validators.PASSWORD_MAX_LENGTH
|
||||
);
|
||||
|
||||
// password
|
||||
const passwordLabel = intl.formatMessage({
|
||||
id: 'PasswordChangeForm.passwordLabel',
|
||||
});
|
||||
const passwordPlaceholder = intl.formatMessage({
|
||||
id: 'PasswordChangeForm.passwordPlaceholder',
|
||||
});
|
||||
const passwordRequiredMessage = intl.formatMessage({
|
||||
id: 'PasswordChangeForm.passwordRequired',
|
||||
});
|
||||
|
||||
const passwordRequired = validators.requiredStringNoTrim(passwordRequiredMessage);
|
||||
|
||||
const passwordFailedMessage = intl.formatMessage({
|
||||
id: 'PasswordChangeForm.passwordFailed',
|
||||
});
|
||||
const passwordErrorText = isChangePasswordWrongPassword(changePasswordError)
|
||||
? passwordFailedMessage
|
||||
: null;
|
||||
|
||||
const confirmClasses = classNames(css.confirmChangesSection, {
|
||||
[css.confirmChangesSectionVisible]: !pristine,
|
||||
});
|
||||
|
||||
const genericFailure =
|
||||
changePasswordError && !passwordErrorText ? (
|
||||
<span className={css.error}>
|
||||
<FormattedMessage id="PasswordChangeForm.genericFailure" />
|
||||
</span>
|
||||
) : null;
|
||||
|
||||
const classes = classNames(rootClassName || css.root, className);
|
||||
const submitDisabled = invalid || submitting || inProgress;
|
||||
|
||||
return (
|
||||
<Form
|
||||
className={classes}
|
||||
onSubmit={values => {
|
||||
handleSubmit(values)
|
||||
.then(() => {
|
||||
this.resetTimeoutId = window.setTimeout(reset, RESET_TIMEOUT);
|
||||
})
|
||||
.catch(() => {
|
||||
// Error is handled in duck file already.
|
||||
});
|
||||
}}
|
||||
>
|
||||
<div className={css.newPasswordSection}>
|
||||
<FieldTextInput
|
||||
type="password"
|
||||
id={formId ? `${formId}.newPassword` : 'newPassword'}
|
||||
name="newPassword"
|
||||
autoComplete="new-password"
|
||||
label={newPasswordLabel}
|
||||
placeholder={newPasswordPlaceholder}
|
||||
validate={validators.composeValidators(
|
||||
newPasswordRequired,
|
||||
passwordMinLength,
|
||||
passwordMaxLength
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={confirmClasses}>
|
||||
<h3 className={css.confirmChangesTitle}>
|
||||
<FormattedMessage id="PasswordChangeForm.confirmChangesTitle" />
|
||||
</h3>
|
||||
<p className={css.confirmChangesInfo}>
|
||||
<FormattedMessage id="PasswordChangeForm.confirmChangesInfo" />
|
||||
</p>
|
||||
|
||||
<FieldTextInput
|
||||
className={css.password}
|
||||
type="password"
|
||||
id="currentPassword"
|
||||
name="currentPassword"
|
||||
autoComplete="current-password"
|
||||
label={passwordLabel}
|
||||
placeholder={passwordPlaceholder}
|
||||
validate={validators.composeValidators(
|
||||
passwordRequired,
|
||||
passwordMinLength,
|
||||
passwordMaxLength
|
||||
)}
|
||||
customErrorText={passwordErrorText}
|
||||
/>
|
||||
</div>
|
||||
<div className={css.bottomWrapper}>
|
||||
{genericFailure}
|
||||
<PrimaryButton
|
||||
className={css.submitButton}
|
||||
type="submit"
|
||||
inProgress={inProgress}
|
||||
ready={ready}
|
||||
disabled={submitDisabled}
|
||||
>
|
||||
<FormattedMessage id="PasswordChangeForm.saveChanges" />
|
||||
</PrimaryButton>
|
||||
</div>
|
||||
</Form>
|
||||
);
|
||||
}}
|
||||
>
|
||||
<div className={css.newPasswordSection}>
|
||||
<TextInputField
|
||||
type="password"
|
||||
name="newPassword"
|
||||
autoComplete="new-password"
|
||||
id={`${form}.newPassword`}
|
||||
label={newPasswordLabel}
|
||||
placeholder={newPasswordPlaceholder}
|
||||
validate={[newPasswordRequired, passwordMinLength, passwordMaxLength]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={confirmClasses}>
|
||||
<h3 className={css.confirmChangesTitle}>
|
||||
<FormattedMessage id="PasswordChangeForm.confirmChangesTitle" />
|
||||
</h3>
|
||||
<p className={css.confirmChangesInfo}>
|
||||
<FormattedMessage id="PasswordChangeForm.confirmChangesInfo" />
|
||||
</p>
|
||||
|
||||
<TextInputField
|
||||
className={css.password}
|
||||
type="password"
|
||||
name="currentPassword"
|
||||
autoComplete="current-password"
|
||||
id={`${form}.currentPassword`}
|
||||
label={passwordLabel}
|
||||
placeholder={passwordPlaceholder}
|
||||
validate={[passwordRequired, passwordMinLength, passwordMaxLength]}
|
||||
customErrorText={passwordErrorText}
|
||||
/>
|
||||
</div>
|
||||
<div className={css.bottomWrapper}>
|
||||
{genericFailure}
|
||||
<PrimaryButton
|
||||
className={css.submitButton}
|
||||
type="submit"
|
||||
inProgress={inProgress}
|
||||
ready={ready}
|
||||
disabled={submitDisabled}
|
||||
>
|
||||
<FormattedMessage id="PasswordChangeForm.saveChanges" />
|
||||
</PrimaryButton>
|
||||
</div>
|
||||
</Form>
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -184,24 +199,22 @@ PasswordChangeFormComponent.defaultProps = {
|
|||
className: null,
|
||||
changePasswordError: null,
|
||||
inProgress: false,
|
||||
formId: null,
|
||||
};
|
||||
|
||||
const { bool, string } = PropTypes;
|
||||
|
||||
PasswordChangeFormComponent.propTypes = {
|
||||
...formPropTypes,
|
||||
rootClassName: string,
|
||||
className: string,
|
||||
changePasswordError: propTypes.error,
|
||||
inProgress: bool,
|
||||
intl: intlShape.isRequired,
|
||||
ready: bool.isRequired,
|
||||
formId: string,
|
||||
};
|
||||
|
||||
const defaultFormName = 'PasswordChangeForm';
|
||||
|
||||
const PasswordChangeForm = compose(reduxForm({ form: defaultFormName }), injectIntl)(
|
||||
PasswordChangeFormComponent
|
||||
);
|
||||
const PasswordChangeForm = compose(injectIntl)(PasswordChangeFormComponent);
|
||||
PasswordChangeForm.displayName = 'PasswordChangeForm';
|
||||
|
||||
export default PasswordChangeForm;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import { renderShallow } from '../../util/test-helpers';
|
||||
import { fakeIntl } from '../../util/test-data';
|
||||
import { fakeIntl, createCurrentUser } from '../../util/test-data';
|
||||
import { PasswordChangePageComponent } from './PasswordChangePage';
|
||||
|
||||
const noop = () => null;
|
||||
|
|
@ -14,6 +14,7 @@ describe('PasswordChangePage', () => {
|
|||
location={{ search: '' }}
|
||||
scrollingDisabled={false}
|
||||
authInProgress={false}
|
||||
currentUser={createCurrentUser('user1')}
|
||||
currentUserHasListings={false}
|
||||
isAuthenticated={false}
|
||||
onChange={noop}
|
||||
|
|
|
|||
|
|
@ -72,6 +72,33 @@ exports[`PasswordChangePage matches snapshot 1`] = `
|
|||
values={Object {}}
|
||||
/>
|
||||
</h1>
|
||||
<PasswordChangeForm
|
||||
changePasswordError={null}
|
||||
currentUser={
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"banned": false,
|
||||
"email": "user1@example.com",
|
||||
"emailVerified": true,
|
||||
"profile": Object {
|
||||
"abbreviatedName": "user1 abbreviated name",
|
||||
"displayName": "user1 display name",
|
||||
"firstName": "user1 first name",
|
||||
"lastName": "user1 last name",
|
||||
},
|
||||
"stripeConnected": true,
|
||||
},
|
||||
"id": UUID {
|
||||
"uuid": "user1",
|
||||
},
|
||||
"type": "currentUser",
|
||||
}
|
||||
}
|
||||
inProgress={false}
|
||||
onChange={[Function]}
|
||||
onSubmit={[Function]}
|
||||
ready={false}
|
||||
/>
|
||||
</div>
|
||||
</LayoutWrapperMain>
|
||||
<LayoutWrapperFooter
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue