diff --git a/src/components/formik-forms/formik-input.jsx b/src/components/formik-forms/formik-input.jsx index 3937a0bd5..26bff6a82 100644 --- a/src/components/formik-forms/formik-input.jsx +++ b/src/components/formik-forms/formik-input.jsx @@ -5,9 +5,8 @@ import {Field} from 'formik'; const ValidationMessage = require('../forms/validation-message.jsx'); -require('./input.scss'); -require('../forms/input.scss'); require('../forms/row.scss'); +require('./formik-input.scss'); const FormikInput = ({ className, @@ -27,6 +26,7 @@ const FormikInput = ({ { - if (remoteResult.valid) return null; + return validate.validateUsernameRemotely(username).then( + remoteResult => { + // there may be multiple validation errors. Prioritize vulgarity, then + // length, then having invalid chars, then all other remote reports + if (remoteResult.valid === false && remoteResult.errMsgId === 'registration.validationUsernameVulgar') { + return this.props.intl.formatMessage({id: remoteResult.errMsgId}); + } else if (localResult.valid === false) { + return this.props.intl.formatMessage({id: localResult.errMsgId}); + } else if (remoteResult.valid === false) { return this.props.intl.formatMessage({id: remoteResult.errMsgId}); } - ); - } - return this.props.intl.formatMessage({id: localResult.errMsgId}); + return null; + } + ); } - validatePasswordIfPresent (password) { + validatePasswordIfPresent (password, username) { if (!password) return null; // skip validation if password is blank; null indicates valid - const localResult = validate.validatePassword(password); + const localResult = validate.validatePassword(password, username); if (localResult.valid) return null; return this.props.intl.formatMessage({id: localResult.errMsgId}); } @@ -69,13 +75,10 @@ class UsernameStep extends React.Component { if (!usernameResult.valid) { errors.username = this.props.intl.formatMessage({id: usernameResult.errMsgId}); } - const passwordResult = validate.validatePassword(values.password); + const passwordResult = validate.validatePassword(values.password, values.username); if (!passwordResult.valid) { errors.password = this.props.intl.formatMessage({id: passwordResult.errMsgId}); } - if (values.password === values.username) { - errors.password = this.props.intl.formatMessage({id: 'registration.validationPasswordNotUsername'}); - } const passwordConfirmResult = validate.validatePasswordConfirm(values.password, values.passwordConfirm); if (!passwordConfirmResult.valid) { errors.passwordConfirm = this.props.intl.formatMessage({id: passwordConfirmResult.errMsgId}); @@ -105,6 +108,8 @@ class UsernameStep extends React.Component { errors, handleSubmit, isSubmitting, + setFieldError, + setFieldValue, validateField, values } = props; @@ -123,15 +128,20 @@ class UsernameStep extends React.Component { validateField('username')} // eslint-disable-line react/jsx-no-bind + /* eslint-disable react/jsx-no-bind */ + onBlur={() => validateField('username')} + onChange={e => { + setFieldValue('username', e.target.value); + setFieldError('username', null); + }} + /* eslint-enable react/jsx-no-bind */ />
@@ -139,23 +149,25 @@ class UsernameStep extends React.Component {
this.validatePasswordIfPresent(password, values.username)} + validationClassName="validation-full-width-input" onBlur={() => validateField('password')} + onChange={e => { + setFieldValue('password', e.target.value); + setFieldError('password', null); + }} /* eslint-enable react/jsx-no-bind */ /> validateField('passwordConfirm') } + onChange={e => { + setFieldValue('passwordConfirm', e.target.value); + setFieldError('passwordConfirm', null); + }} /* eslint-enable react/jsx-no-bind */ />
diff --git a/src/lib/validate.js b/src/lib/validate.js index 6112b95db..85fe64944 100644 --- a/src/lib/validate.js +++ b/src/lib/validate.js @@ -40,13 +40,21 @@ module.exports.validateUsernameRemotely = username => ( }) ); -module.exports.validatePassword = password => { +/** + * Validate password value, optionally also considering username value + * @param {string} password password value to validate + * @param {string} username username value to compare + * @return {object} {valid: boolean, errMsgId: string} + */ +module.exports.validatePassword = (password, username) => { if (!password) { return {valid: false, errMsgId: 'general.required'}; } else if (password.length < 6) { return {valid: false, errMsgId: 'registration.validationPasswordLength'}; } else if (password === 'password') { return {valid: false, errMsgId: 'registration.validationPasswordNotEquals'}; + } else if (username && password === username) { + return {valid: false, errMsgId: 'registration.validationPasswordNotUsername'}; } return {valid: true}; }; diff --git a/test/unit/lib/validate.test.js b/test/unit/lib/validate.test.js index a4aa9c232..03922882f 100644 --- a/test/unit/lib/validate.test.js +++ b/test/unit/lib/validate.test.js @@ -39,6 +39,10 @@ describe('unit test lib/validate.js', () => { expect(response).toEqual({valid: false, errMsgId: 'registration.validationPasswordLength'}); response = validate.validatePassword('password'); expect(response).toEqual({valid: false, errMsgId: 'registration.validationPasswordNotEquals'}); + response = validate.validatePassword('abcdefg', 'abcdefg'); + expect(response).toEqual({valid: false, errMsgId: 'registration.validationPasswordNotUsername'}); + response = validate.validatePassword('abcdefg', 'abcdefG'); + expect(response).toEqual({valid: true}); }); test('validate password confirm', () => {