From 86a375c7dacd1d02e7a363e49e4054cb23e04627 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Thu, 21 Feb 2019 14:31:11 +0000 Subject: [PATCH] Report validity state of all registration fields on any change This passes the validity state of all fields to the consumer of `RegistrationForm` via the `onValdiationChange` callback, instead of just the most recent error. In addition, we notify the consumer for any validation change, whether success or failure. This allows old validation messages to be properly cleared. It also allows the consumer to be aware of multiple validation errors and display the next one after you have fixed the first. Fixes https://github.com/vector-im/riot-web/issues/8769 --- .../structures/auth/Registration.js | 13 ++++++-- src/components/views/auth/RegistrationForm.js | 33 ++++++++++--------- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/components/structures/auth/Registration.js b/src/components/structures/auth/Registration.js index 30b553a5b1..b00c0c193f 100644 --- a/src/components/structures/auth/Registration.js +++ b/src/components/structures/auth/Registration.js @@ -288,7 +288,16 @@ module.exports = React.createClass({ }); }, - onFormValidationFailed: function(errCode) { + onFormValidationChange: function(fieldErrors) { + // Find the first error and show that. + const errCode = Object.values(fieldErrors).find(value => value); + if (!errCode) { + this.setState({ + errorText: null, + }); + return; + } + let errMsg; switch (errCode) { case "RegistrationForm.ERR_PASSWORD_MISSING": @@ -490,7 +499,7 @@ module.exports = React.createClass({ defaultPhoneNumber={this.state.formVals.phoneNumber} defaultPassword={this.state.formVals.password} minPasswordLength={MIN_PASSWORD_LENGTH} - onError={this.onFormValidationFailed} + onValidationChange={this.onFormValidationChange} onRegisterClick={this.onFormSubmit} onEditServerDetailsClick={onEditServerDetailsClick} flows={this.state.flows} diff --git a/src/components/views/auth/RegistrationForm.js b/src/components/views/auth/RegistrationForm.js index bd597de66a..d031dc7bdd 100644 --- a/src/components/views/auth/RegistrationForm.js +++ b/src/components/views/auth/RegistrationForm.js @@ -46,7 +46,7 @@ module.exports = React.createClass({ defaultUsername: PropTypes.string, defaultPassword: PropTypes.string, minPasswordLength: PropTypes.number, - onError: PropTypes.func, + onValidationChange: PropTypes.func, onRegisterClick: PropTypes.func.isRequired, // onRegisterClick(Object) => ?Promise onEditServerDetailsClick: PropTypes.func, flows: PropTypes.arrayOf(PropTypes.object).isRequired, @@ -60,15 +60,14 @@ module.exports = React.createClass({ getDefaultProps: function() { return { minPasswordLength: 6, - onError: function(e) { - console.error(e); - }, + onValidationChange: console.error, }; }, getInitialState: function() { return { - fieldValid: {}, + // Field error codes by field ID + fieldErrors: {}, // The ISO2 country code selected in the phone number entry phoneCountry: this.props.defaultPhoneCountry, }; @@ -81,7 +80,7 @@ module.exports = React.createClass({ // the error that ends up being displayed // is the one from the first invalid field. // It's not super ideal that this just calls - // onError once for each invalid field. + // onValidationChange once for each invalid field. this.validateField(FIELD_PHONE_NUMBER, ev.type); this.validateField(FIELD_EMAIL, ev.type); this.validateField(FIELD_PASSWORD_CONFIRM, ev.type); @@ -134,9 +133,9 @@ module.exports = React.createClass({ * @returns {boolean} true if all fields were valid last time they were validated. */ allFieldsValid: function() { - const keys = Object.keys(this.state.fieldValid); + const keys = Object.keys(this.state.fieldErrors); for (let i = 0; i < keys.length; ++i) { - if (this.state.fieldValid[keys[i]] == false) { + if (this.state.fieldErrors[keys[i]]) { return false; } } @@ -218,13 +217,17 @@ module.exports = React.createClass({ } }, - markFieldValid: function(fieldID, val, errorCode) { - const fieldValid = this.state.fieldValid; - fieldValid[fieldID] = val; - this.setState({fieldValid: fieldValid}); - if (!val) { - this.props.onError(errorCode); + markFieldValid: function(fieldID, valid, errorCode) { + const { fieldErrors } = this.state; + if (valid) { + fieldErrors[fieldID] = null; + } else { + fieldErrors[fieldID] = errorCode; } + this.setState({ + fieldErrors, + }); + this.props.onValidationChange(fieldErrors); }, fieldElementById(fieldID) { @@ -244,7 +247,7 @@ module.exports = React.createClass({ _classForField: function(fieldID, ...baseClasses) { let cls = baseClasses.join(' '); - if (this.state.fieldValid[fieldID] === false) { + if (this.state.fieldErrors[fieldID]) { if (cls) cls += ' '; cls += 'error'; }