Commit f0c2280f authored by Matthew Taylor's avatar Matthew Taylor

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
parent 2407f1d6
var allCountries = require('react-telephone-input/lib/country_data').allCountries;
var classNames = require('classnames'); var classNames = require('classnames');
var React = require('react'); var ComponentMixin = require('formsy-react-components').ComponentMixin;
var FormsyMixin = require('formsy-react').Mixin; var FormsyMixin = require('formsy-react').Mixin;
var React = require('react');
var ReactPhoneInput = require('react-telephone-input/lib/withStyles'); 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 Row = require('formsy-react-components').Row;
var ComponentMixin = require('formsy-react-components').ComponentMixin;
var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC;
var inputHOC = require('./input-hoc.jsx'); 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;}); var allIso2 = allCountries.map(function (country) {return country.iso2;});
...@@ -23,7 +25,8 @@ var PhoneInput = React.createClass({ ...@@ -23,7 +25,8 @@ var PhoneInput = React.createClass({
getDefaultProps: function () { getDefaultProps: function () {
return { return {
validations: { validations: {
isPhone: true isPhone: true,
phoneLength: true
}, },
flagsImagePath: '/images/flags.png', flagsImagePath: '/images/flags.png',
defaultCountry: 'us' defaultCountry: 'us'
...@@ -62,7 +65,8 @@ var PhoneInput = React.createClass({ ...@@ -62,7 +65,8 @@ var PhoneInput = React.createClass({
}); });
var phoneValidationHOC = validationHOCFactory({ 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))); module.exports = inputHOC(defaultValidationHOC(phoneValidationHOC(PhoneInput)));
...@@ -21,6 +21,14 @@ module.exports.validations = { ...@@ -21,6 +21,14 @@ module.exports.validations = {
return false; return false;
} }
return phoneNumberUtil.isValidNumber(parsed); 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 = { ...@@ -82,38 +82,53 @@ module.exports = {
onChangeShowPassword: function (field, value) { onChangeShowPassword: function (field, value) {
this.setState({showPassword: value}); this.setState({showPassword: value});
}, },
onValidSubmit: function (formData, reset, invalidate) { validateUsername: function (username) {
this.setState({waiting: true});
api({ api({
host: '', host: '',
uri: '/accounts/check_username/' + formData.user.username + '/' uri: '/accounts/check_username/' + username + '/'
}, function (err, res) { }, function (err, res) {
var formatMessage = this.props.intl.formatMessage; var formatMessage = this.props.intl.formatMessage;
this.setState({waiting: false}); if (err) {
if (err) return invalidate({all: err}); this.refs.form.refs.formsy.updateInputsWithError({all: err});
return false;
}
res = res[0]; res = res[0];
switch (res.msg) { switch (res.msg) {
case 'valid username': case 'valid username':
this.setState({ this.setState({
validUsername: 'pass' validUsername: 'pass'
}); });
return this.props.onNextStep(formData); return true;
case 'username exists': case 'username exists':
return invalidate({ this.refs.form.refs.formsy.updateInputsWithError({
'user.username': formatMessage({id: 'registration.validationUsernameExists'}) 'user.username': formatMessage({id: 'registration.validationUsernameExists'})
}); });
return false;
case 'bad username': case 'bad username':
return invalidate({ this.refs.form.refs.formsy.updateInputsWithError({
'user.username': formatMessage({id: 'registration.validationUsernameVulgar'}) 'user.username': formatMessage({id: 'registration.validationUsernameVulgar'})
}); });
return false;
case 'invalid username': case 'invalid username':
default: default:
return invalidate({ this.refs.form.refs.formsy.updateInputsWithError({
'user.username': formatMessage({id: 'registration.validationUsernameInvalid'}) 'user.username': formatMessage({id: 'registration.validationUsernameInvalid'})
}); });
return false;
} }
}.bind(this)); }.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 () { render: function () {
var formatMessage = this.props.intl.formatMessage; var formatMessage = this.props.intl.formatMessage;
return ( return (
...@@ -139,7 +154,7 @@ module.exports = { ...@@ -139,7 +154,7 @@ module.exports = {
)} )}
</p> </p>
<Card> <Card>
<Form onValidSubmit={this.onValidSubmit}> <Form onValidSubmit={this.onValidSubmit} ref="form">
<div> <div>
<div className="username-label"> <div className="username-label">
<b>{formatMessage({id: 'registration.createUsername'})}</b> <b>{formatMessage({id: 'registration.createUsername'})}</b>
...@@ -152,6 +167,7 @@ module.exports = { ...@@ -152,6 +167,7 @@ module.exports = {
<Input className={this.state.validUsername} <Input className={this.state.validUsername}
type="text" type="text"
name="user.username" name="user.username"
onBlur={this.onUsernameBlur}
validations={{ validations={{
matchRegexp: /^[\w-]*$/, matchRegexp: /^[\w-]*$/,
minLength: 3, minLength: 3,
...@@ -473,8 +489,21 @@ module.exports = { ...@@ -473,8 +489,21 @@ module.exports = {
onChooseOrganization: function (name, values) { onChooseOrganization: function (name, values) {
this.setState({otherDisabled: values.indexOf(this.organizationL10nStems.indexOf('orgChoiceOther')) === -1}); this.setState({otherDisabled: values.indexOf(this.organizationL10nStems.indexOf('orgChoiceOther')) === -1});
}, },
onValidSubmit: function (formData, reset, invalidate) { validateOrganizationType: function (formData) {
if (formData.organization.type.length < 1) { 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({ return invalidate({
'organization.type': this.props.intl.formatMessage({id: 'teacherRegistration.validationRequired'}) 'organization.type': this.props.intl.formatMessage({id: 'teacherRegistration.validationRequired'})
}); });
...@@ -494,7 +523,7 @@ module.exports = { ...@@ -494,7 +523,7 @@ module.exports = {
tipContent={formatMessage({id: 'registration.nameStepTooltip'})} /> tipContent={formatMessage({id: 'registration.nameStepTooltip'})} />
</p> </p>
<Card> <Card>
<Form onValidSubmit={this.onValidSubmit}> <Form onValidSubmit={this.onValidSubmit} onSubmit={this.onSubmit}>
<Input label={formatMessage({id: 'teacherRegistration.organization'})} <Input label={formatMessage({id: 'teacherRegistration.organization'})}
type="text" type="text"
name="organization.name" name="organization.name"
...@@ -515,10 +544,11 @@ module.exports = { ...@@ -515,10 +544,11 @@ module.exports = {
required /> required />
</div> </div>
<div className="other-input"> <div className="other-input">
<Input type="text" <Input name="organization.other"
name="organization.other" type="text"
disabled={this.state.otherDisabled} disabled={this.state.otherDisabled}
required="isFalse" required={!this.state.otherDisabled}
help={null}
placeholder={formatMessage({id: 'general.other'})} /> placeholder={formatMessage({id: 'general.other'})} />
</div> </div>
<div className="url-input"> <div className="url-input">
...@@ -532,7 +562,7 @@ module.exports = { ...@@ -532,7 +562,7 @@ module.exports = {
placeholder={'http://'} /> placeholder={'http://'} />
</div> </div>
<NextStepButton waiting={this.props.waiting} <NextStepButton waiting={this.props.waiting}
text={<intl.FormattedMessage id="registration.nextStep" />} /> text={<intl.FormattedMessage id="registration.nextStep" />} />
</Form> </Form>
</Card> </Card>
<StepNavigation steps={this.props.totalSteps - 1} active={this.props.activeStep} /> <StepNavigation steps={this.props.totalSteps - 1} active={this.props.activeStep} />
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment