From 109046eef82a3556d02def1da3976d381afb337a Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 8 Nov 2021 15:57:37 -0600 Subject: [PATCH] RegistrationForm: validate password mismatch --- .../components/registration_form.js | 59 +++++++++++++++++-- app/soapbox/features/forms/index.js | 7 ++- app/styles/forms.scss | 12 ++-- 3 files changed, 66 insertions(+), 12 deletions(-) diff --git a/app/soapbox/features/auth_login/components/registration_form.js b/app/soapbox/features/auth_login/components/registration_form.js index f8da31be1..86e5812ff 100644 --- a/app/soapbox/features/auth_login/components/registration_form.js +++ b/app/soapbox/features/auth_login/components/registration_form.js @@ -63,6 +63,8 @@ class RegistrationForm extends ImmutablePureComponent { submissionLoading: false, params: ImmutableMap(), captchaIdempotencyKey: uuidv4(), + passwordConfirmation: '', + passwordMismatch: false, } setParams = map => { @@ -77,6 +79,30 @@ class RegistrationForm extends ImmutablePureComponent { this.setParams({ [e.target.name]: e.target.checked }); } + onPasswordChange = e => { + const password = e.target.value; + const { passwordConfirmation } = this.state; + this.onInputChange(e); + + if (password === passwordConfirmation) { + this.setState({ passwordMismatch: false }); + } + } + + onPasswordConfirmChange = e => { + const password = this.state.params.get('password'); + const passwordConfirmation = e.target.value; + this.setState({ passwordConfirmation }); + + if (password === passwordConfirmation) { + this.setState({ passwordMismatch: false }); + } + } + + onPasswordConfirmBlur = e => { + this.setState({ passwordMismatch: !this.passwordsMatch() }); + } + launchModal = () => { const { dispatch, intl, needsConfirmation, needsApproval } = this.props; @@ -113,9 +139,19 @@ class RegistrationForm extends ImmutablePureComponent { } } + passwordsMatch = () => { + const { params, passwordConfirmation } = this.state; + return params.get('password', '') === passwordConfirmation; + } + onSubmit = e => { const { dispatch, inviteToken } = this.props; + if (!this.passwordsMatch()) { + this.setState({ passwordMismatch: true }); + return; + } + const params = this.state.params.withMutations(params => { // Locale for confirmation email params.set('locale', this.props.locale); @@ -159,7 +195,7 @@ class RegistrationForm extends ImmutablePureComponent { render() { const { instance, intl, supportsEmailList } = this.props; - const { params } = this.state; + const { params, passwordConfirmation, passwordMismatch } = this.state; const isLoading = this.state.captchaLoading || this.state.submissionLoading; return ( @@ -176,6 +212,7 @@ class RegistrationForm extends ImmutablePureComponent { autoCapitalize='off' pattern='^[a-zA-Z\d_-]+' onChange={this.onInputChange} + value={params.get('username', '')} required /> + {passwordMismatch && ( +
+ +
+ )} {instance.get('approval_required') && @@ -215,6 +263,7 @@ class RegistrationForm extends ImmutablePureComponent { name='reason' maxLength={500} onChange={this.onInputChange} + value={params.get('reason', '')} required />} @@ -232,12 +281,14 @@ class RegistrationForm extends ImmutablePureComponent { label={intl.formatMessage(messages.agreement, { tos: {intl.formatMessage(messages.tos)} })} name='agreement' onChange={this.onCheckboxChange} + checked={params.get('agreement', false)} required /> {supportsEmailList && }
diff --git a/app/soapbox/features/forms/index.js b/app/soapbox/features/forms/index.js index 3273a0d4e..816a5e61a 100644 --- a/app/soapbox/features/forms/index.js +++ b/app/soapbox/features/forms/index.js @@ -18,6 +18,7 @@ export const InputContainer = (props) => { 'with_label': props.label, 'required': props.required, 'boolean': props.type === 'checkbox', + 'field_with_errors': props.error, }, props.extraClass); return ( @@ -35,6 +36,7 @@ InputContainer.propTypes = { type: PropTypes.string, children: PropTypes.node, extraClass: PropTypes.string, + error: PropTypes.bool, }; export const LabelInputContainer = ({ label, hint, children, ...props }) => { @@ -87,10 +89,11 @@ export class SimpleInput extends ImmutablePureComponent { static propTypes = { label: FormPropTypes.label, hint: PropTypes.node, + error: PropTypes.bool, } render() { - const { hint, ...props } = this.props; + const { hint, error, ...props } = this.props; const Input = this.props.label ? LabelInput : 'input'; return ( @@ -164,7 +167,7 @@ FieldsGroup.propTypes = { }; export const Checkbox = props => ( - + ); export class RadioGroup extends ImmutablePureComponent { diff --git a/app/styles/forms.scss b/app/styles/forms.scss index 05bcbc0a4..b28676a32 100644 --- a/app/styles/forms.scss +++ b/app/styles/forms.scss @@ -371,13 +371,13 @@ code { select { border-color: lighten($error-red, 12%); } + } - .error { - display: block; - font-weight: 500; - color: lighten($error-red, 12%); - margin-top: 4px; - } + .error { + display: block; + font-weight: 500; + color: lighten($error-red, 12%); + margin-top: 4px; } .input.disabled {