Redo team-based registration (#657)

For compatibility with referral campaign flows, re-implement team registration such that the team is selected through providing an email with a known team domain. The support email is now only shown when an email that _looks_ like a UK/US university email address, but is not known.
This commit is contained in:
Luke Barnard 2017-01-27 16:31:36 +00:00 committed by GitHub
parent f462bd8f99
commit d9a8acd431
2 changed files with 60 additions and 83 deletions

View file

@ -90,6 +90,7 @@ module.exports = React.createClass({
}, },
componentWillMount: function() { componentWillMount: function() {
this._unmounted = false;
this.dispatcherRef = dis.register(this.onAction); this.dispatcherRef = dis.register(this.onAction);
// attach this to the instance rather than this.state since it isn't UI // attach this to the instance rather than this.state since it isn't UI
this.registerLogic = new Signup.Register( this.registerLogic = new Signup.Register(
@ -107,6 +108,7 @@ module.exports = React.createClass({
componentWillUnmount: function() { componentWillUnmount: function() {
dis.unregister(this.dispatcherRef); dis.unregister(this.dispatcherRef);
this._unmounted = true;
}, },
componentDidMount: function() { componentDidMount: function() {
@ -273,6 +275,14 @@ module.exports = React.createClass({
}); });
}, },
onTeamSelected: function(team) {
if (!this._unmounted) {
this.setState({
teamIcon: team ? team.icon : null,
});
}
},
_getRegisterContentJsx: function() { _getRegisterContentJsx: function() {
var currStep = this.registerLogic.getStep(); var currStep = this.registerLogic.getStep();
var registerStep; var registerStep;
@ -293,7 +303,9 @@ module.exports = React.createClass({
guestUsername={this.props.username} guestUsername={this.props.username}
minPasswordLength={MIN_PASSWORD_LENGTH} minPasswordLength={MIN_PASSWORD_LENGTH}
onError={this.onFormValidationFailed} onError={this.onFormValidationFailed}
onRegisterClick={this.onFormSubmit} /> onRegisterClick={this.onFormSubmit}
onTeamSelected={this.onTeamSelected}
/>
); );
break; break;
case "Register.STEP_m.login.email.identity": case "Register.STEP_m.login.email.identity":
@ -367,7 +379,7 @@ module.exports = React.createClass({
return ( return (
<div className="mx_Login"> <div className="mx_Login">
<div className="mx_Login_box"> <div className="mx_Login_box">
<LoginHeader /> <LoginHeader icon={this.state.teamIcon}/>
{this._getRegisterContentJsx()} {this._getRegisterContentJsx()}
<LoginFooter /> <LoginFooter />
</div> </div>

View file

@ -44,8 +44,8 @@ module.exports = React.createClass({
teams: React.PropTypes.arrayOf(React.PropTypes.shape({ teams: React.PropTypes.arrayOf(React.PropTypes.shape({
// The displayed name of the team // The displayed name of the team
"name": React.PropTypes.string, "name": React.PropTypes.string,
// The suffix with which every team email address ends // The domain of team email addresses
"emailSuffix": React.PropTypes.string, "domain": React.PropTypes.string,
})).required, })).required,
}), }),
@ -117,9 +117,6 @@ module.exports = React.createClass({
_doSubmit: function() { _doSubmit: function() {
let email = this.refs.email.value.trim(); let email = this.refs.email.value.trim();
if (this.state.selectedTeam) {
email += "@" + this.state.selectedTeam.emailSuffix;
}
var promise = this.props.onRegisterClick({ var promise = this.props.onRegisterClick({
username: this.refs.username.value.trim() || this.props.guestUsername, username: this.refs.username.value.trim() || this.props.guestUsername,
password: this.refs.password.value.trim(), password: this.refs.password.value.trim(),
@ -134,25 +131,6 @@ module.exports = React.createClass({
} }
}, },
onSelectTeam: function(teamIndex) {
let team = this._getSelectedTeam(teamIndex);
if (team) {
this.refs.email.value = this.refs.email.value.split("@")[0];
}
this.setState({
selectedTeam: team,
showSupportEmail: teamIndex === "other",
});
},
_getSelectedTeam: function(teamIndex) {
if (this.props.teamsConfig &&
this.props.teamsConfig.teams[teamIndex]) {
return this.props.teamsConfig.teams[teamIndex];
}
return null;
},
/** /**
* Returns true if all fields were valid last time * Returns true if all fields were valid last time
* they were validated. * they were validated.
@ -167,20 +145,36 @@ module.exports = React.createClass({
return true; return true;
}, },
_isUniEmail: function(email) {
return email.endsWith('.ac.uk') || email.endsWith('.edu');
},
validateField: function(field_id) { validateField: function(field_id) {
var pwd1 = this.refs.password.value.trim(); var pwd1 = this.refs.password.value.trim();
var pwd2 = this.refs.passwordConfirm.value.trim(); var pwd2 = this.refs.passwordConfirm.value.trim();
switch (field_id) { switch (field_id) {
case FIELD_EMAIL: case FIELD_EMAIL:
let email = this.refs.email.value; const email = this.refs.email.value;
if (this.props.teamsConfig) { if (this.props.teamsConfig && this._isUniEmail(email)) {
let team = this.state.selectedTeam; const matchingTeam = this.props.teamsConfig.teams.find(
if (team) { (team) => {
email = email + "@" + team.emailSuffix; return email.split('@').pop() === team.domain;
} }
) || null;
this.setState({
selectedTeam: matchingTeam,
showSupportEmail: !matchingTeam,
});
this.props.onTeamSelected(matchingTeam);
} else {
this.props.onTeamSelected(null);
this.setState({
selectedTeam: null,
showSupportEmail: false,
});
} }
let valid = email === '' || Email.looksValid(email); const valid = email === '' || Email.looksValid(email);
this.markFieldValid(field_id, valid, "RegistrationForm.ERR_EMAIL_INVALID"); this.markFieldValid(field_id, valid, "RegistrationForm.ERR_EMAIL_INVALID");
break; break;
case FIELD_USERNAME: case FIELD_USERNAME:
@ -260,61 +254,35 @@ module.exports = React.createClass({
return cls; return cls;
}, },
_renderEmailInputSuffix: function() {
let suffix = null;
if (!this.state.selectedTeam) {
return suffix;
}
let team = this.state.selectedTeam;
if (team) {
suffix = "@" + team.emailSuffix;
}
return suffix;
},
render: function() { render: function() {
var self = this; var self = this;
var emailSection, teamSection, teamAdditionSupport, registerButton; var emailSection, belowEmailSection, registerButton;
if (this.props.showEmail) { if (this.props.showEmail) {
let emailSuffix = this._renderEmailInputSuffix();
emailSection = ( emailSection = (
<div> <input type="text" ref="email"
<input type="text" ref="email" autoFocus={true} placeholder="Email address (optional)"
autoFocus={true} placeholder="Email address (optional)" defaultValue={this.props.defaultEmail}
defaultValue={this.props.defaultEmail} className={this._classForField(FIELD_EMAIL, 'mx_Login_field')}
className={this._classForField(FIELD_EMAIL, 'mx_Login_field')} onBlur={function() {self.validateField(FIELD_EMAIL);}}
onBlur={function() {self.validateField(FIELD_EMAIL);}} value={self.state.email}/>
value={self.state.email}/>
{emailSuffix ? <input className="mx_Login_field" value={emailSuffix} disabled/> : null }
</div>
); );
if (this.props.teamsConfig) { if (this.props.teamsConfig) {
teamSection = (
<select
defaultValue="-1"
className="mx_Login_field"
onBlur={function() {self.validateField(FIELD_EMAIL);}}
onChange={function(ev) {self.onSelectTeam(ev.target.value);}}
>
<option key="-1" value="-1">No team</option>
{this.props.teamsConfig.teams.map((t, index) => {
return (
<option key={index} value={index}>
{t.name}
</option>
);
})}
<option key="-2" value="other">Other</option>
</select>
);
if (this.props.teamsConfig.supportEmail && this.state.showSupportEmail) { if (this.props.teamsConfig.supportEmail && this.state.showSupportEmail) {
teamAdditionSupport = ( belowEmailSection = (
<span> <p className="mx_Login_support">
If your team is not listed, email&nbsp; Sorry, but your university is not registered with us just yet.&nbsp;
Email us on&nbsp;
<a href={"mailto:" + this.props.teamsConfig.supportEmail}> <a href={"mailto:" + this.props.teamsConfig.supportEmail}>
{this.props.teamsConfig.supportEmail} {this.props.teamsConfig.supportEmail}
</a> </a>&nbsp;
</span> to get your university signed up. Or continue to register with Riot to enjoy our open source platform.
</p>
);
} else if (this.state.selectedTeam) {
belowEmailSection = (
<p className="mx_Login_support">
You are registering with {this.state.selectedTeam.name}
</p>
); );
} }
} }
@ -333,11 +301,8 @@ module.exports = React.createClass({
return ( return (
<div> <div>
<form onSubmit={this.onSubmit}> <form onSubmit={this.onSubmit}>
{teamSection}
{teamAdditionSupport}
<br />
{emailSection} {emailSection}
<br /> {belowEmailSection}
<input type="text" ref="username" <input type="text" ref="username"
placeholder={ placeholderUserName } defaultValue={this.props.defaultUsername} placeholder={ placeholderUserName } defaultValue={this.props.defaultUsername}
className={this._classForField(FIELD_USERNAME, 'mx_Login_field')} className={this._classForField(FIELD_USERNAME, 'mx_Login_field')}