mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2024-11-23 07:38:07 -05:00
Updates to registration UX for teachers
1. Phone too long validation occurs before submit now. 2. Organization “other” type is now being required 3. Organization type required now shows up at the same time as other organization validation errors 4. Username check now occurs earlier, on blur rather than on submit
This commit is contained in:
parent
2407f1d6e4
commit
f0c2280fde
3 changed files with 67 additions and 25 deletions
|
@ -1,13 +1,15 @@
|
|||
var classNames = require('classnames');
|
||||
var React = require('react');
|
||||
var FormsyMixin = require('formsy-react').Mixin;
|
||||
var ReactPhoneInput = require('react-telephone-input/lib/withStyles');
|
||||
var allCountries = require('react-telephone-input/lib/country_data').allCountries;
|
||||
var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC;
|
||||
var validationHOCFactory = require('./validations.jsx').validationHOCFactory;
|
||||
var Row = require('formsy-react-components').Row;
|
||||
var classNames = require('classnames');
|
||||
var ComponentMixin = require('formsy-react-components').ComponentMixin;
|
||||
var FormsyMixin = require('formsy-react').Mixin;
|
||||
var React = require('react');
|
||||
var ReactPhoneInput = require('react-telephone-input/lib/withStyles');
|
||||
var Row = require('formsy-react-components').Row;
|
||||
|
||||
var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC;
|
||||
var inputHOC = require('./input-hoc.jsx');
|
||||
var intl = require('../../lib/intl.jsx');
|
||||
var validationHOCFactory = require('./validations.jsx').validationHOCFactory;
|
||||
|
||||
var allIso2 = allCountries.map(function (country) {return country.iso2;});
|
||||
|
||||
|
@ -23,7 +25,8 @@ var PhoneInput = React.createClass({
|
|||
getDefaultProps: function () {
|
||||
return {
|
||||
validations: {
|
||||
isPhone: true
|
||||
isPhone: true,
|
||||
phoneLength: true
|
||||
},
|
||||
flagsImagePath: '/images/flags.png',
|
||||
defaultCountry: 'us'
|
||||
|
@ -62,7 +65,8 @@ var PhoneInput = React.createClass({
|
|||
});
|
||||
|
||||
var phoneValidationHOC = validationHOCFactory({
|
||||
isPhone: 'Please enter a valid phone number'
|
||||
isPhone: <intl.FormattedMessage id="teacherRegistration.validationPhoneNumber" />,
|
||||
phoneLength: <intl.FormattedMessage id="teacherRegistration.validationPhoneNumber" />
|
||||
});
|
||||
|
||||
module.exports = inputHOC(defaultValidationHOC(phoneValidationHOC(PhoneInput)));
|
||||
|
|
|
@ -21,6 +21,14 @@ module.exports.validations = {
|
|||
return false;
|
||||
}
|
||||
return phoneNumberUtil.isValidNumber(parsed);
|
||||
},
|
||||
phoneLength: function (values, value) {
|
||||
if (typeof value === 'undefined') return true;
|
||||
if (value && value.national_number === '+') return true;
|
||||
if (value && value.national_number.length === value.country_code.format.length) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -82,38 +82,53 @@ module.exports = {
|
|||
onChangeShowPassword: function (field, value) {
|
||||
this.setState({showPassword: value});
|
||||
},
|
||||
onValidSubmit: function (formData, reset, invalidate) {
|
||||
this.setState({waiting: true});
|
||||
validateUsername: function (username) {
|
||||
api({
|
||||
host: '',
|
||||
uri: '/accounts/check_username/' + formData.user.username + '/'
|
||||
uri: '/accounts/check_username/' + username + '/'
|
||||
}, function (err, res) {
|
||||
var formatMessage = this.props.intl.formatMessage;
|
||||
this.setState({waiting: false});
|
||||
if (err) return invalidate({all: err});
|
||||
if (err) {
|
||||
this.refs.form.refs.formsy.updateInputsWithError({all: err});
|
||||
return false;
|
||||
}
|
||||
res = res[0];
|
||||
switch (res.msg) {
|
||||
case 'valid username':
|
||||
this.setState({
|
||||
validUsername: 'pass'
|
||||
});
|
||||
return this.props.onNextStep(formData);
|
||||
return true;
|
||||
case 'username exists':
|
||||
return invalidate({
|
||||
this.refs.form.refs.formsy.updateInputsWithError({
|
||||
'user.username': formatMessage({id: 'registration.validationUsernameExists'})
|
||||
});
|
||||
return false;
|
||||
case 'bad username':
|
||||
return invalidate({
|
||||
this.refs.form.refs.formsy.updateInputsWithError({
|
||||
'user.username': formatMessage({id: 'registration.validationUsernameVulgar'})
|
||||
});
|
||||
return false;
|
||||
case 'invalid username':
|
||||
default:
|
||||
return invalidate({
|
||||
this.refs.form.refs.formsy.updateInputsWithError({
|
||||
'user.username': formatMessage({id: 'registration.validationUsernameInvalid'})
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
onUsernameBlur: function (event) {
|
||||
this.validateUsername(event.currentTarget.value);
|
||||
},
|
||||
onValidSubmit: function (formData) {
|
||||
this.setState({waiting: true});
|
||||
this.validateUsername(formData.user.username);
|
||||
this.setState({waiting: false});
|
||||
if (this.state.validUsername === 'pass') {
|
||||
this.props.onNextStep(formData);
|
||||
}
|
||||
},
|
||||
render: function () {
|
||||
var formatMessage = this.props.intl.formatMessage;
|
||||
return (
|
||||
|
@ -139,7 +154,7 @@ module.exports = {
|
|||
)}
|
||||
</p>
|
||||
<Card>
|
||||
<Form onValidSubmit={this.onValidSubmit}>
|
||||
<Form onValidSubmit={this.onValidSubmit} ref="form">
|
||||
<div>
|
||||
<div className="username-label">
|
||||
<b>{formatMessage({id: 'registration.createUsername'})}</b>
|
||||
|
@ -152,6 +167,7 @@ module.exports = {
|
|||
<Input className={this.state.validUsername}
|
||||
type="text"
|
||||
name="user.username"
|
||||
onBlur={this.onUsernameBlur}
|
||||
validations={{
|
||||
matchRegexp: /^[\w-]*$/,
|
||||
minLength: 3,
|
||||
|
@ -473,8 +489,21 @@ module.exports = {
|
|||
onChooseOrganization: function (name, values) {
|
||||
this.setState({otherDisabled: values.indexOf(this.organizationL10nStems.indexOf('orgChoiceOther')) === -1});
|
||||
},
|
||||
onValidSubmit: function (formData, reset, invalidate) {
|
||||
validateOrganizationType: function (formData) {
|
||||
if (formData.organization.type.length < 1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
onSubmit: function (formData, reset, invalidate) {
|
||||
if (!this.validateOrganizationType(formData)) {
|
||||
return invalidate({
|
||||
'organization.type': this.props.intl.formatMessage({id: 'teacherRegistration.validationRequired'})
|
||||
});
|
||||
}
|
||||
},
|
||||
onValidSubmit: function (formData, reset, invalidate) {
|
||||
if (!this.validateOrganizationType(formData)) {
|
||||
return invalidate({
|
||||
'organization.type': this.props.intl.formatMessage({id: 'teacherRegistration.validationRequired'})
|
||||
});
|
||||
|
@ -494,7 +523,7 @@ module.exports = {
|
|||
tipContent={formatMessage({id: 'registration.nameStepTooltip'})} />
|
||||
</p>
|
||||
<Card>
|
||||
<Form onValidSubmit={this.onValidSubmit}>
|
||||
<Form onValidSubmit={this.onValidSubmit} onSubmit={this.onSubmit}>
|
||||
<Input label={formatMessage({id: 'teacherRegistration.organization'})}
|
||||
type="text"
|
||||
name="organization.name"
|
||||
|
@ -515,10 +544,11 @@ module.exports = {
|
|||
required />
|
||||
</div>
|
||||
<div className="other-input">
|
||||
<Input type="text"
|
||||
name="organization.other"
|
||||
<Input name="organization.other"
|
||||
type="text"
|
||||
disabled={this.state.otherDisabled}
|
||||
required="isFalse"
|
||||
required={!this.state.otherDisabled}
|
||||
help={null}
|
||||
placeholder={formatMessage({id: 'general.other'})} />
|
||||
</div>
|
||||
<div className="url-input">
|
||||
|
@ -532,7 +562,7 @@ module.exports = {
|
|||
placeholder={'http://'} />
|
||||
</div>
|
||||
<NextStepButton waiting={this.props.waiting}
|
||||
text={<intl.FormattedMessage id="registration.nextStep" />} />
|
||||
text={<intl.FormattedMessage id="registration.nextStep" />} />
|
||||
</Form>
|
||||
</Card>
|
||||
<StepNavigation steps={this.props.totalSteps - 1} active={this.props.activeStep} />
|
||||
|
|
Loading…
Reference in a new issue