Merge pull request #2672 from jryans/password-validation

Report validity state of all registration fields on any change
pull/21833/head
J. Ryan Stinnett 2019-02-26 18:20:38 +00:00 committed by GitHub
commit 426bdafe22
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 46 additions and 23 deletions

View File

@ -58,6 +58,10 @@ limitations under the License.
background-color: $authpage-body-bg-color; background-color: $authpage-body-bg-color;
} }
.mx_AuthBody input.error {
color: $warning-color;
}
.mx_AuthBody_editServerDetails { .mx_AuthBody_editServerDetails {
padding-left: 1em; padding-left: 1em;
font-size: 12px; font-size: 12px;

View File

@ -308,7 +308,19 @@ module.exports = React.createClass({
}); });
}, },
onFormValidationFailed: function(errCode) { onFormValidationChange: function(fieldErrors) {
// `fieldErrors` is an object mapping field IDs to error codes when there is an
// error or `null` for no error, so the values array will be something like:
// `[ null, "RegistrationForm.ERR_PASSWORD_MISSING", null]`
// Find the first non-null error code and show that.
const errCode = Object.values(fieldErrors).find(value => !!value);
if (!errCode) {
this.setState({
errorText: null,
});
return;
}
let errMsg; let errMsg;
switch (errCode) { switch (errCode) {
case "RegistrationForm.ERR_PASSWORD_MISSING": case "RegistrationForm.ERR_PASSWORD_MISSING":
@ -510,7 +522,7 @@ module.exports = React.createClass({
defaultPhoneNumber={this.state.formVals.phoneNumber} defaultPhoneNumber={this.state.formVals.phoneNumber}
defaultPassword={this.state.formVals.password} defaultPassword={this.state.formVals.password}
minPasswordLength={MIN_PASSWORD_LENGTH} minPasswordLength={MIN_PASSWORD_LENGTH}
onError={this.onFormValidationFailed} onValidationChange={this.onFormValidationChange}
onRegisterClick={this.onFormSubmit} onRegisterClick={this.onFormSubmit}
onEditServerDetailsClick={onEditServerDetailsClick} onEditServerDetailsClick={onEditServerDetailsClick}
flows={this.state.flows} flows={this.state.flows}

View File

@ -46,7 +46,7 @@ module.exports = React.createClass({
defaultUsername: PropTypes.string, defaultUsername: PropTypes.string,
defaultPassword: PropTypes.string, defaultPassword: PropTypes.string,
minPasswordLength: PropTypes.number, minPasswordLength: PropTypes.number,
onError: PropTypes.func, onValidationChange: PropTypes.func,
onRegisterClick: PropTypes.func.isRequired, // onRegisterClick(Object) => ?Promise onRegisterClick: PropTypes.func.isRequired, // onRegisterClick(Object) => ?Promise
onEditServerDetailsClick: PropTypes.func, onEditServerDetailsClick: PropTypes.func,
flows: PropTypes.arrayOf(PropTypes.object).isRequired, flows: PropTypes.arrayOf(PropTypes.object).isRequired,
@ -60,15 +60,14 @@ module.exports = React.createClass({
getDefaultProps: function() { getDefaultProps: function() {
return { return {
minPasswordLength: 6, minPasswordLength: 6,
onError: function(e) { onValidationChange: console.error,
console.error(e);
},
}; };
}, },
getInitialState: function() { getInitialState: function() {
return { return {
fieldValid: {}, // Field error codes by field ID
fieldErrors: {},
// The ISO2 country code selected in the phone number entry // The ISO2 country code selected in the phone number entry
phoneCountry: this.props.defaultPhoneCountry, phoneCountry: this.props.defaultPhoneCountry,
}; };
@ -81,12 +80,12 @@ module.exports = React.createClass({
// the error that ends up being displayed // the error that ends up being displayed
// is the one from the first invalid field. // is the one from the first invalid field.
// It's not super ideal that this just calls // 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); this.validateField(FIELD_PASSWORD_CONFIRM, ev.type);
this.validateField(FIELD_PASSWORD, ev.type); this.validateField(FIELD_PASSWORD, ev.type);
this.validateField(FIELD_USERNAME, ev.type); this.validateField(FIELD_USERNAME, ev.type);
this.validateField(FIELD_PHONE_NUMBER, ev.type);
this.validateField(FIELD_EMAIL, ev.type);
const self = this; const self = this;
if (this.allFieldsValid()) { if (this.allFieldsValid()) {
@ -134,9 +133,9 @@ module.exports = React.createClass({
* @returns {boolean} true if all fields were valid last time they were validated. * @returns {boolean} true if all fields were valid last time they were validated.
*/ */
allFieldsValid: function() { allFieldsValid: function() {
const keys = Object.keys(this.state.fieldValid); const keys = Object.keys(this.state.fieldErrors);
for (let i = 0; i < keys.length; ++i) { for (let i = 0; i < keys.length; ++i) {
if (this.state.fieldValid[keys[i]] == false) { if (this.state.fieldErrors[keys[i]]) {
return false; return false;
} }
} }
@ -206,21 +205,29 @@ module.exports = React.createClass({
} }
break; break;
case FIELD_PASSWORD_CONFIRM: case FIELD_PASSWORD_CONFIRM:
this.markFieldValid( if (allowEmpty && pwd2 === "") {
fieldID, pwd1 == pwd2, this.markFieldValid(fieldID, true);
"RegistrationForm.ERR_PASSWORD_MISMATCH", } else {
); this.markFieldValid(
fieldID, pwd1 == pwd2,
"RegistrationForm.ERR_PASSWORD_MISMATCH",
);
}
break; break;
} }
}, },
markFieldValid: function(fieldID, val, errorCode) { markFieldValid: function(fieldID, valid, errorCode) {
const fieldValid = this.state.fieldValid; const { fieldErrors } = this.state;
fieldValid[fieldID] = val; if (valid) {
this.setState({fieldValid: fieldValid}); fieldErrors[fieldID] = null;
if (!val) { } else {
this.props.onError(errorCode); fieldErrors[fieldID] = errorCode;
} }
this.setState({
fieldErrors,
});
this.props.onValidationChange(fieldErrors);
}, },
fieldElementById(fieldID) { fieldElementById(fieldID) {
@ -240,7 +247,7 @@ module.exports = React.createClass({
_classForField: function(fieldID, ...baseClasses) { _classForField: function(fieldID, ...baseClasses) {
let cls = baseClasses.join(' '); let cls = baseClasses.join(' ');
if (this.state.fieldValid[fieldID] === false) { if (this.state.fieldErrors[fieldID]) {
if (cls) cls += ' '; if (cls) cls += ' ';
cls += 'error'; cls += 'error';
} }