Track per-field validity with new-style validation
This updates the registration form to include the new-style validation state when deciding whether the entire form is valid overall. In addition, this tweaks the validation helper to take functions instead of strings for translated text. This allows the validation helper to be create once per component instead of once every render, which improves performance.
This commit is contained in:
parent
37e09b5569
commit
62a01e7a37
2 changed files with 64 additions and 36 deletions
|
@ -68,7 +68,9 @@ module.exports = React.createClass({
|
|||
getInitialState: function() {
|
||||
return {
|
||||
// Field error codes by field ID
|
||||
// TODO: Remove `fieldErrors` once converted to new-style validation
|
||||
fieldErrors: {},
|
||||
fieldValid: {},
|
||||
// The ISO2 country code selected in the phone number entry
|
||||
phoneCountry: this.props.defaultPhoneCountry,
|
||||
username: "",
|
||||
|
@ -140,12 +142,19 @@ 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.fieldErrors);
|
||||
// TODO: Remove `fieldErrors` here when all fields converted
|
||||
let keys = Object.keys(this.state.fieldErrors);
|
||||
for (let i = 0; i < keys.length; ++i) {
|
||||
if (this.state.fieldErrors[keys[i]]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
keys = Object.keys(this.state.fieldValid);
|
||||
for (let i = 0; i < keys.length; ++i) {
|
||||
if (!this.state.fieldValid[keys[i]]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
|
@ -161,57 +170,57 @@ module.exports = React.createClass({
|
|||
const email = this.state.email;
|
||||
const emailValid = email === '' || Email.looksValid(email);
|
||||
if (this._authStepIsRequired('m.login.email.identity') && (!emailValid || email === '')) {
|
||||
this.markFieldValid(fieldID, false, "RegistrationForm.ERR_MISSING_EMAIL");
|
||||
} else this.markFieldValid(fieldID, emailValid, "RegistrationForm.ERR_EMAIL_INVALID");
|
||||
this.markFieldError(fieldID, false, "RegistrationForm.ERR_MISSING_EMAIL");
|
||||
} else this.markFieldError(fieldID, emailValid, "RegistrationForm.ERR_EMAIL_INVALID");
|
||||
break;
|
||||
}
|
||||
case FIELD_PHONE_NUMBER: {
|
||||
const phoneNumber = this.state.phoneNumber;
|
||||
const phoneNumberValid = phoneNumber === '' || phoneNumberLooksValid(phoneNumber);
|
||||
if (this._authStepIsRequired('m.login.msisdn') && (!phoneNumberValid || phoneNumber === '')) {
|
||||
this.markFieldValid(fieldID, false, "RegistrationForm.ERR_MISSING_PHONE_NUMBER");
|
||||
} else this.markFieldValid(fieldID, phoneNumberValid, "RegistrationForm.ERR_PHONE_NUMBER_INVALID");
|
||||
this.markFieldError(fieldID, false, "RegistrationForm.ERR_MISSING_PHONE_NUMBER");
|
||||
} else this.markFieldError(fieldID, phoneNumberValid, "RegistrationForm.ERR_PHONE_NUMBER_INVALID");
|
||||
break;
|
||||
}
|
||||
case FIELD_USERNAME: {
|
||||
const username = this.state.username;
|
||||
if (allowEmpty && username === '') {
|
||||
this.markFieldValid(fieldID, true);
|
||||
this.markFieldError(fieldID, true);
|
||||
} else if (username == '') {
|
||||
this.markFieldValid(
|
||||
this.markFieldError(
|
||||
fieldID,
|
||||
false,
|
||||
"RegistrationForm.ERR_USERNAME_BLANK",
|
||||
);
|
||||
} else {
|
||||
this.markFieldValid(fieldID, true);
|
||||
this.markFieldError(fieldID, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FIELD_PASSWORD:
|
||||
if (allowEmpty && pwd1 === "") {
|
||||
this.markFieldValid(fieldID, true);
|
||||
this.markFieldError(fieldID, true);
|
||||
} else if (pwd1 == '') {
|
||||
this.markFieldValid(
|
||||
this.markFieldError(
|
||||
fieldID,
|
||||
false,
|
||||
"RegistrationForm.ERR_PASSWORD_MISSING",
|
||||
);
|
||||
} else if (pwd1.length < this.props.minPasswordLength) {
|
||||
this.markFieldValid(
|
||||
this.markFieldError(
|
||||
fieldID,
|
||||
false,
|
||||
"RegistrationForm.ERR_PASSWORD_LENGTH",
|
||||
);
|
||||
} else {
|
||||
this.markFieldValid(fieldID, true);
|
||||
this.markFieldError(fieldID, true);
|
||||
}
|
||||
break;
|
||||
case FIELD_PASSWORD_CONFIRM:
|
||||
if (allowEmpty && pwd2 === "") {
|
||||
this.markFieldValid(fieldID, true);
|
||||
this.markFieldError(fieldID, true);
|
||||
} else {
|
||||
this.markFieldValid(
|
||||
this.markFieldError(
|
||||
fieldID, pwd1 == pwd2,
|
||||
"RegistrationForm.ERR_PASSWORD_MISMATCH",
|
||||
);
|
||||
|
@ -220,7 +229,8 @@ module.exports = React.createClass({
|
|||
}
|
||||
},
|
||||
|
||||
markFieldValid: function(fieldID, valid, errorCode) {
|
||||
markFieldError: function(fieldID, valid, errorCode) {
|
||||
// TODO: Remove this function once all fields converted to new-style validation.
|
||||
const { fieldErrors } = this.state;
|
||||
if (valid) {
|
||||
fieldErrors[fieldID] = null;
|
||||
|
@ -235,6 +245,14 @@ module.exports = React.createClass({
|
|||
this.props.onValidationChange(fieldErrors);
|
||||
},
|
||||
|
||||
markFieldValid: function(fieldID, valid) {
|
||||
const { fieldValid } = this.state;
|
||||
fieldValid[fieldID] = valid;
|
||||
this.setState({
|
||||
fieldValid,
|
||||
});
|
||||
},
|
||||
|
||||
_classForField: function(fieldID, ...baseClasses) {
|
||||
let cls = baseClasses.join(' ');
|
||||
// TODO: Remove this from fields as they are converted to new-style validation.
|
||||
|
@ -298,6 +316,23 @@ module.exports = React.createClass({
|
|||
});
|
||||
},
|
||||
|
||||
onUsernameValidate(fieldState) {
|
||||
const result = this.validateUsernameRules(fieldState);
|
||||
this.markFieldValid(FIELD_USERNAME, result.valid);
|
||||
return result;
|
||||
},
|
||||
|
||||
validateUsernameRules: withValidation({
|
||||
description: () => _t("Use letters, numbers, dashes and underscores only"),
|
||||
rules: [
|
||||
{
|
||||
key: "safeLocalpart",
|
||||
regex: SAFE_LOCALPART_REGEX,
|
||||
invalid: () => _t("Some characters not allowed"),
|
||||
},
|
||||
],
|
||||
}),
|
||||
|
||||
/**
|
||||
* A step is required if all flows include that step.
|
||||
*
|
||||
|
@ -324,18 +359,6 @@ module.exports = React.createClass({
|
|||
|
||||
renderUsername() {
|
||||
const Field = sdk.getComponent('elements.Field');
|
||||
|
||||
const onValidate = withValidation({
|
||||
description: _t("Use letters, numbers, dashes and underscores only"),
|
||||
rules: [
|
||||
{
|
||||
key: "safeLocalpart",
|
||||
regex: SAFE_LOCALPART_REGEX,
|
||||
invalid: _t("Some characters not allowed"),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
return <Field
|
||||
className={this._classForField(FIELD_USERNAME)}
|
||||
id="mx_RegistrationForm_username"
|
||||
|
@ -345,7 +368,7 @@ module.exports = React.createClass({
|
|||
defaultValue={this.props.defaultUsername}
|
||||
value={this.state.username}
|
||||
onChange={this.onUsernameChange}
|
||||
onValidate={onValidate}
|
||||
onValidate={this.onUsernameValidate}
|
||||
/>;
|
||||
},
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue