mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-29 21:21:19 +10:00
Add email not found handling
This commit is contained in:
parent
82fe1ce490
commit
13f4d81648
7 changed files with 40 additions and 6 deletions
|
|
@ -17,6 +17,7 @@ class TextInputFieldComponent extends Component {
|
|||
rootClassName,
|
||||
className,
|
||||
clearOnUnmount,
|
||||
customErrorText,
|
||||
id,
|
||||
label,
|
||||
type,
|
||||
|
|
@ -33,9 +34,13 @@ class TextInputFieldComponent extends Component {
|
|||
const { valid, invalid, touched, error } = meta;
|
||||
const isTextarea = type === 'textarea';
|
||||
|
||||
const errorText = customErrorText || error;
|
||||
|
||||
// Error message and input error styles are only shown if the
|
||||
// field has been touched and the validation has failed.
|
||||
const hasError = touched && invalid && error;
|
||||
const hasError = touched && invalid && errorText;
|
||||
|
||||
const fieldMeta = { touched, error: errorText };
|
||||
|
||||
const inputClasses = classNames(css.input, {
|
||||
[css.inputSuccess]: valid,
|
||||
|
|
@ -50,7 +55,7 @@ class TextInputFieldComponent extends Component {
|
|||
<div className={classes}>
|
||||
{label ? <label htmlFor={id}>{label}</label> : null}
|
||||
{isTextarea ? <ExpandingTextarea {...inputProps} /> : <input {...inputProps} />}
|
||||
<ValidationError fieldMeta={meta} />
|
||||
<ValidationError fieldMeta={fieldMeta} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -60,6 +65,7 @@ TextInputFieldComponent.defaultProps = {
|
|||
rootClassName: null,
|
||||
className: null,
|
||||
clearOnUnmount: false,
|
||||
customErrorText: null,
|
||||
id: null,
|
||||
label: null,
|
||||
};
|
||||
|
|
@ -72,6 +78,10 @@ TextInputFieldComponent.propTypes = {
|
|||
|
||||
clearOnUnmount: bool,
|
||||
|
||||
// Error message that can be manually passed to input field,
|
||||
// overrides default validation message
|
||||
customErrorText: string,
|
||||
|
||||
// Label is optional, but if it is given, an id is also required so
|
||||
// the label can reference the input in the `for` attribute
|
||||
id: string,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import * as validators from '../../util/validators';
|
|||
|
||||
import css from './PasswordRecoveryForm.css';
|
||||
|
||||
const isNotFoundError = (error) => error && error.status === 404;
|
||||
|
||||
const PasswordRecoveryFormComponent = props => {
|
||||
const {
|
||||
rootClassName,
|
||||
|
|
@ -18,6 +20,7 @@ const PasswordRecoveryFormComponent = props => {
|
|||
form,
|
||||
initialValues,
|
||||
intl,
|
||||
recoveryError,
|
||||
} = props;
|
||||
|
||||
// email
|
||||
|
|
@ -30,8 +33,12 @@ const PasswordRecoveryFormComponent = props => {
|
|||
const emailRequiredMessage = intl.formatMessage({
|
||||
id: 'PasswordRecoveryForm.emailRequired',
|
||||
});
|
||||
const emailRequired = validators.required(emailRequiredMessage);
|
||||
const emailNotFoundMessage = intl.formatMessage({
|
||||
id: 'PasswordRecoveryForm.emailNotFound',
|
||||
});
|
||||
|
||||
const emailRequired = validators.required(emailRequiredMessage);
|
||||
const customErrorText = isNotFoundError(recoveryError) ? emailNotFoundMessage : null;
|
||||
const initialEmail = initialValues ? initialValues.email : null;
|
||||
const buttonDisabled = (pristine && !initialEmail) || submitting;
|
||||
const classes = classNames(rootClassName || css.root, className);
|
||||
|
|
@ -41,6 +48,7 @@ const PasswordRecoveryFormComponent = props => {
|
|||
<FormattedMessage id="PasswordRecoveryForm.goToLoginHelp" />
|
||||
</span>
|
||||
);
|
||||
|
||||
return (
|
||||
<form className={classes} onSubmit={handleSubmit}>
|
||||
<TextInputField
|
||||
|
|
@ -51,6 +59,7 @@ const PasswordRecoveryFormComponent = props => {
|
|||
label={emailLabel}
|
||||
placeholder={emailPlaceholder}
|
||||
validate={emailRequired}
|
||||
customErrorText={customErrorText}
|
||||
/>
|
||||
<p className={css.bottomWrapper}>
|
||||
<NamedLink name="LoginPage" className={css.goToLoginLink}>
|
||||
|
|
@ -67,14 +76,16 @@ const PasswordRecoveryFormComponent = props => {
|
|||
PasswordRecoveryFormComponent.defaultProps = {
|
||||
rootClassName: null,
|
||||
className: null,
|
||||
recoveryError: null,
|
||||
};
|
||||
|
||||
const { string } = PropTypes;
|
||||
const { instanceOf, string } = PropTypes;
|
||||
|
||||
PasswordRecoveryFormComponent.propTypes = {
|
||||
...formPropTypes,
|
||||
rootClassName: string,
|
||||
className: string,
|
||||
recoveryError: instanceOf(Error),
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
}
|
||||
|
||||
.title {
|
||||
@apply --marketplaceH1FontStyles;
|
||||
@apply --marketplaceModalTitle;
|
||||
}
|
||||
|
||||
.submittedEmail {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ export const RECOVERY_REQUEST = 'app/PasswordRecoveryPage/RECOVERY_REQUEST';
|
|||
export const RECOVERY_SUCCESS = 'app/PasswordRecoveryPage/RECOVERY_SUCCESS';
|
||||
export const RECOVERY_ERROR = 'app/PasswordRecoveryPage/RECOVERY_ERROR';
|
||||
export const RETYPE_EMAIL = 'app/PasswordRecoveryPage/RETYPE_EMAIL';
|
||||
export const CLEAR_RECOVERY_ERROR = 'app/PasswordRecoveryPage/CLEAR_RECOVERY_ERROR';
|
||||
|
||||
// ================ Reducer ================ //
|
||||
|
||||
|
|
@ -31,6 +32,8 @@ export default function reducer(state = initialState, action = {}) {
|
|||
return { ...state, recoveryInProgress: false, recoveryError: payload };
|
||||
case RETYPE_EMAIL:
|
||||
return { ...state, submittedEmail: null, initialEmail: state.submittedEmail };
|
||||
case CLEAR_RECOVERY_ERROR:
|
||||
return { ...state, recoveryError: null };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
@ -46,6 +49,7 @@ export const recoveryError = error => ({
|
|||
error: true,
|
||||
});
|
||||
export const retypeEmail = () => ({ type: RETYPE_EMAIL });
|
||||
export const clearRecoveryError = () => ({ type: CLEAR_RECOVERY_ERROR });
|
||||
|
||||
// ================ Thunks ================ //
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import * as propTypes from '../../util/propTypes';
|
|||
import { sendVerificationEmail } from '../../ducks/user.duck';
|
||||
import { logout, authenticationInProgress } from '../../ducks/Auth.duck';
|
||||
import { manageDisableScrolling, isScrollingDisabled } from '../../ducks/UI.duck';
|
||||
import { recoverPassword, retypeEmail } from './PasswordRecoveryPage.duck';
|
||||
import { recoverPassword, retypeEmail, clearRecoveryError } from './PasswordRecoveryPage.duck';
|
||||
import { PageLayout, Topbar, InlineTextButton, KeysIcon } from '../../components';
|
||||
import { PasswordRecoveryForm } from '../../containers';
|
||||
|
||||
|
|
@ -41,6 +41,8 @@ export const PasswordRecoveryPageComponent = props => {
|
|||
onResendVerificationEmail,
|
||||
initialEmail,
|
||||
submittedEmail,
|
||||
recoveryError,
|
||||
onChange,
|
||||
onSubmitEmail,
|
||||
onRetypeEmail,
|
||||
} = props;
|
||||
|
|
@ -109,8 +111,10 @@ export const PasswordRecoveryPageComponent = props => {
|
|||
{submittedEmail
|
||||
? emailSubmittedLinks
|
||||
: <PasswordRecoveryForm
|
||||
onChange={onChange}
|
||||
onSubmit={values => onSubmitEmail(values.email)}
|
||||
initialValues={{ email: initialEmail }}
|
||||
recoveryError={recoveryError}
|
||||
/>}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -128,6 +132,7 @@ PasswordRecoveryPageComponent.defaultProps = {
|
|||
sendVerificationEmailError: null,
|
||||
initialEmail: null,
|
||||
submittedEmail: null,
|
||||
recoveryError: null,
|
||||
};
|
||||
|
||||
const { bool, func, instanceOf, number, object, shape, string } = PropTypes;
|
||||
|
|
@ -148,6 +153,8 @@ PasswordRecoveryPageComponent.propTypes = {
|
|||
onResendVerificationEmail: func.isRequired,
|
||||
initialEmail: string,
|
||||
submittedEmail: string,
|
||||
recoveryError: instanceOf(Error),
|
||||
onChange: func.isRequired,
|
||||
onSubmitEmail: func.isRequired,
|
||||
onRetypeEmail: func.isRequired,
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ describe('ContactDetailsPage', () => {
|
|||
sendVerificationEmailInProgress={false}
|
||||
onResendVerificationEmail={noop}
|
||||
recoveryInProgress={false}
|
||||
onChange={noop}
|
||||
onSubmitEmail={noop}
|
||||
onRetypeEmail={noop}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -226,6 +226,7 @@
|
|||
"PasswordResetPage.resetFailed": "Reset failed. Please try again.",
|
||||
"PasswordResetPage.title": "Reset password",
|
||||
"PasswordRecoveryForm.emailLabel": "Email",
|
||||
"PasswordRecoveryForm.emailNotFound": "Hmm. We didn't find an account with that email. Please double-check your email and try again.",
|
||||
"PasswordRecoveryForm.emailPlaceholder": "john.doe@example.com",
|
||||
"PasswordRecoveryForm.emailRequired": "This field is required",
|
||||
"PasswordRecoveryForm.goToLogin": "{goToLoginHelp} Go to log in.",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue