Merge pull request #803 from mewtaylor/issue/gh-683

Fix GH-[683,705,712,797]: Updates to registration UX for teachers
This commit is contained in:
Matthew Taylor 2016-08-08 08:10:24 -04:00 committed by GitHub
commit 606e3600ba
4 changed files with 67 additions and 35 deletions

View file

@ -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)));

View file

@ -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;
}
};

View file

@ -82,38 +82,55 @@ module.exports = {
onChangeShowPassword: function (field, value) {
this.setState({showPassword: value});
},
onValidSubmit: function (formData, reset, invalidate) {
this.setState({waiting: true});
validateUsername: function (username, callback) {
callback = callback || function () {};
api({
host: '',
uri: '/accounts/check_username/' + formData.user.username + '/'
}, function (err, res) {
uri: '/accounts/check_username/' + username + '/'
}, function (err, body, res) {
var formatMessage = this.props.intl.formatMessage;
this.setState({waiting: false});
if (err) return invalidate({all: err});
res = res[0];
switch (res.msg) {
if (err || res.statusCode !== 200) {
err = err || formatMessage({id: 'general.error'});
this.refs.form.refs.formsy.updateInputsWithError({all: err});
return callback(false);
}
body = body[0];
switch (body.msg) {
case 'valid username':
this.setState({
validUsername: 'pass'
});
return this.props.onNextStep(formData);
return callback(true);
case 'username exists':
return invalidate({
this.refs.form.refs.formsy.updateInputsWithError({
'user.username': formatMessage({id: 'registration.validationUsernameExists'})
});
return callback(false);
case 'bad username':
return invalidate({
this.refs.form.refs.formsy.updateInputsWithError({
'user.username': formatMessage({id: 'registration.validationUsernameVulgar'})
});
return callback(false);
case 'invalid username':
default:
return invalidate({
this.refs.form.refs.formsy.updateInputsWithError({
'user.username': formatMessage({id: 'registration.validationUsernameInvalid'})
});
return callback(false);
}
}.bind(this));
},
onUsernameBlur: function (event) {
this.validateUsername(event.currentTarget.value);
},
onValidSubmit: function (formData) {
this.setState({waiting: true});
this.validateUsername(formData.user.username, function (isValid) {
this.setState({waiting: false});
if (isValid) return this.props.onNextStep(formData);
}.bind(this));
},
render: function () {
var formatMessage = this.props.intl.formatMessage;
return (
@ -139,7 +156,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 +169,7 @@ module.exports = {
<Input className={this.state.validUsername}
type="text"
name="user.username"
onBlur={this.onUsernameBlur}
validations={{
matchRegexp: /^[\w-]*$/,
minLength: 3,
@ -473,14 +491,6 @@ module.exports = {
onChooseOrganization: function (name, values) {
this.setState({otherDisabled: values.indexOf(this.organizationL10nStems.indexOf('orgChoiceOther')) === -1});
},
onValidSubmit: function (formData, reset, invalidate) {
if (formData.organization.type.length < 1) {
return invalidate({
'organization.type': this.props.intl.formatMessage({id: 'teacherRegistration.validationRequired'})
});
}
return this.props.onNextStep(formData);
},
render: function () {
var formatMessage = this.props.intl.formatMessage;
return (
@ -494,7 +504,7 @@ module.exports = {
tipContent={formatMessage({id: 'registration.nameStepTooltip'})} />
</p>
<Card>
<Form onValidSubmit={this.onValidSubmit}>
<Form onValidSubmit={this.props.onNextStep}>
<Input label={formatMessage({id: 'teacherRegistration.organization'})}
type="text"
name="organization.name"
@ -512,13 +522,22 @@ module.exports = {
value={[]}
options={this.getOrganizationOptions()}
onChange={this.onChooseOrganization}
validations={{
minLength: 1
}}
validationErrors={{
minLength: formatMessage({
id: 'teacherRegistration.validationRequired'
})
}}
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 +551,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} />

View file

@ -16,6 +16,7 @@
"general.discuss": "Discuss",
"general.dmca": "DMCA",
"general.emailAddress": "Email Address",
"general.error": "Oops! Something went wrong",
"general.explore": "Explore",
"general.faq": "FAQ",
"general.female": "Female",