diff --git a/src/components/structures/auth/Registration.js b/src/components/structures/auth/Registration.js index b19be60fbe..22dd8c0ea9 100644 --- a/src/components/structures/auth/Registration.js +++ b/src/components/structures/auth/Registration.js @@ -332,15 +332,9 @@ module.exports = React.createClass({ case "RegistrationForm.ERR_PASSWORD_LENGTH": errMsg = _t('Password too short (min %(MIN_PASSWORD_LENGTH)s).', {MIN_PASSWORD_LENGTH}); break; - case "RegistrationForm.ERR_EMAIL_INVALID": - errMsg = _t('This doesn\'t look like a valid email address.'); - break; case "RegistrationForm.ERR_PHONE_NUMBER_INVALID": errMsg = _t('This doesn\'t look like a valid phone number.'); break; - case "RegistrationForm.ERR_MISSING_EMAIL": - errMsg = _t('An email address is required to register on this homeserver.'); - break; case "RegistrationForm.ERR_MISSING_PHONE_NUMBER": errMsg = _t('A phone number is required to register on this homeserver.'); break; diff --git a/src/components/views/auth/RegistrationForm.js b/src/components/views/auth/RegistrationForm.js index 1f30af3710..5f2a9a8dcc 100644 --- a/src/components/views/auth/RegistrationForm.js +++ b/src/components/views/auth/RegistrationForm.js @@ -91,7 +91,6 @@ module.exports = React.createClass({ // onValidationChange once for each invalid field. // TODO: Remove these calls once converted to new-style validation. 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); @@ -213,14 +212,6 @@ module.exports = React.createClass({ // TODO: Remove rules here as they are converted to new-style validation switch (fieldID) { - case FIELD_EMAIL: { - const email = this.state.email; - const emailValid = email === '' || Email.looksValid(email); - if (this._authStepIsRequired('m.login.email.identity') && (!emailValid || email === '')) { - 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); @@ -295,16 +286,36 @@ module.exports = React.createClass({ return cls; }, - onEmailBlur(ev) { - this.validateField(FIELD_EMAIL, ev.type); - }, - onEmailChange(ev) { this.setState({ email: ev.target.value, }); }, + onEmailValidate(fieldState) { + const result = this.validateEmailRules(fieldState); + this.markFieldValid(FIELD_EMAIL, result.valid); + return result; + }, + + validateEmailRules: withValidation({ + description: () => _t("Use an email address to recover your account"), + rules: [ + { + key: "required", + test: function({ value, allowEmpty }) { + return allowEmpty || !this._authStepIsRequired('m.login.email.identity') || !!value; + }, + invalid: () => _t("Enter email address (required on this homeserver)"), + }, + { + key: "email", + test: ({ value }) => !value || Email.looksValid(value), + invalid: () => _t("Doesn't look like a valid email address"), + }, + ], + }), + onPasswordBlur(ev) { this.validateField(FIELD_PASSWORD, ev.type); }, @@ -394,6 +405,26 @@ module.exports = React.createClass({ }); }, + renderEmail() { + if (!this._authStepIsUsed('m.login.email.identity')) { + return null; + } + const Field = sdk.getComponent('elements.Field'); + const emailPlaceholder = this._authStepIsRequired('m.login.email.identity') ? + _t("Email") : + _t("Email (optional)"); + return this[FIELD_EMAIL] = field} + type="text" + label={emailPlaceholder} + defaultValue={this.props.defaultEmail} + value={this.state.email} + onChange={this.onEmailChange} + onValidate={this.onEmailValidate} + />; + }, + renderUsername() { const Field = sdk.getComponent('elements.Field'); return ; } - let emailSection; - if (this._authStepIsUsed('m.login.email.identity')) { - const emailPlaceholder = this._authStepIsRequired('m.login.email.identity') ? - _t("Email") : - _t("Email (optional)"); - - emailSection = ( - - ); - } - const threePidLogin = !SdkConfig.get().disable_3pid_login; const CountryDropdown = sdk.getComponent('views.auth.CountryDropdown'); let phoneSection; @@ -521,13 +532,11 @@ module.exports = React.createClass({ />
- { emailSection } + {this.renderEmail()} { phoneSection }
- {_t( - "Use an email address to recover your account. Other users " + - "can invite you to rooms using your contact details.", - )} + {_t("Use an email address to recover your account.") + " "} + {_t("Other users can invite you to rooms using your contact details.")} { registerButton } diff --git a/src/components/views/elements/Validation.js b/src/components/views/elements/Validation.js index 8142dfcd65..458d000e0e 100644 --- a/src/components/views/elements/Validation.js +++ b/src/components/views/elements/Validation.js @@ -50,7 +50,10 @@ export default function withValidation({ description, rules }) { if (!rule.key || !rule.test) { continue; } - const ruleValid = rule.test({ value, allowEmpty }); + // We're setting `this` to whichever component hold the validation + // function. That allows rules to access the state of the component. + // eslint-disable-next-line babel/no-invalid-this + const ruleValid = rule.test.call(this, { value, allowEmpty }); valid = valid && ruleValid; if (ruleValid && rule.valid) { // If the rule's result is valid and has text to show for @@ -101,10 +104,13 @@ export default function withValidation({ description, rules }) { summary =
{description()}
; } - const feedback =
- {summary} - {details} -
; + let feedback; + if (summary || details) { + feedback =
+ {summary} + {details} +
; + } return { valid, diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index bafb516af7..d219b3a19a 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1322,15 +1322,19 @@ "Change": "Change", "Sign in with": "Sign in with", "If you don't specify an email address, you won't be able to reset your password. Are you sure?": "If you don't specify an email address, you won't be able to reset your password. Are you sure?", + "Use an email address to recover your account": "Use an email address to recover your account", + "Enter email address (required on this homeserver)": "Enter email address (required on this homeserver)", + "Doesn't look like a valid email address": "Doesn't look like a valid email address", "Use letters, numbers, dashes and underscores only": "Use letters, numbers, dashes and underscores only", - "Some characters not allowed": "Some characters not allowed", "Enter username": "Enter username", + "Some characters not allowed": "Some characters not allowed", + "Email (optional)": "Email (optional)", "Create your Matrix account": "Create your Matrix account", "Create your Matrix account on %(serverName)s": "Create your Matrix account on %(serverName)s", - "Email (optional)": "Email (optional)", "Phone (optional)": "Phone (optional)", "Confirm": "Confirm", - "Use an email address to recover your account. Other users can invite you to rooms using your contact details.": "Use an email address to recover your account. Other users can invite you to rooms using your contact details.", + "Use an email address to recover your account.": "Use an email address to recover your account.", + "Other users can invite you to rooms using your contact details.": "Other users can invite you to rooms using your contact details.", "Other servers": "Other servers", "Enter custom server URLs What does this mean?": "Enter custom server URLs What does this mean?", "Homeserver URL": "Homeserver URL", @@ -1521,9 +1525,7 @@ "Missing password.": "Missing password.", "Passwords don't match.": "Passwords don't match.", "Password too short (min %(MIN_PASSWORD_LENGTH)s).": "Password too short (min %(MIN_PASSWORD_LENGTH)s).", - "This doesn't look like a valid email address.": "This doesn't look like a valid email address.", "This doesn't look like a valid phone number.": "This doesn't look like a valid phone number.", - "An email address is required to register on this homeserver.": "An email address is required to register on this homeserver.", "A phone number is required to register on this homeserver.": "A phone number is required to register on this homeserver.", "An unknown error occurred.": "An unknown error occurred.", "Create your account": "Create your account",