Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Report validity state of all registration fields on any change #2672

Merged
merged 5 commits into from
Feb 26, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions res/css/views/auth/_AuthBody.scss
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ limitations under the License.
background-color: $authpage-body-bg-color;
}

.mx_AuthBody input.error {
color: $warning-color;
}

.mx_AuthBody_editServerDetails {
padding-left: 1em;
font-size: 12px;
Expand Down
13 changes: 11 additions & 2 deletions src/components/structures/auth/Registration.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ooi why not [0]?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There can be null values for fields without errors, so we need the first non-null one. Maybe !!value or a comment would make it clearer...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

js is also weird and doesn't break on [0] fwiw

> const testArray = [];
undefined
> testArray[0]
undefined

Copy link
Collaborator Author

@jryans jryans Feb 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, but it's not about the values array being empty, but instead the elements in it. For example, the values array might be [null, "bob", null], and we want "bob" here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see. Yup, that makes sense. A comment would be great :)

if (!errCode) {
this.setState({
errorText: null,
});
return;
}

let errMsg;
switch (errCode) {
case "RegistrationForm.ERR_PASSWORD_MISSING":
Expand Down Expand Up @@ -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}
Expand Down
49 changes: 28 additions & 21 deletions src/components/views/auth/RegistrationForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
};
Expand All @@ -81,12 +80,12 @@ 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);
this.validateField(FIELD_PASSWORD, ev.type);
this.validateField(FIELD_USERNAME, ev.type);
this.validateField(FIELD_PHONE_NUMBER, ev.type);
this.validateField(FIELD_EMAIL, ev.type);

const self = this;
if (this.allFieldsValid()) {
Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -206,21 +205,29 @@ module.exports = React.createClass({
}
break;
case FIELD_PASSWORD_CONFIRM:
this.markFieldValid(
fieldID, pwd1 == pwd2,
"RegistrationForm.ERR_PASSWORD_MISMATCH",
);
if (allowEmpty && pwd2 === "") {
this.markFieldValid(fieldID, true);
} else {
this.markFieldValid(
fieldID, pwd1 == pwd2,
"RegistrationForm.ERR_PASSWORD_MISMATCH",
);
}
break;
}
},

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) {
Expand All @@ -240,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';
}
Expand Down