Commit 02ff0217 authored by Ray Schamp's avatar Ray Schamp Committed by GitHub

Merge pull request #782 from LLK/release/2.2.11

[Develop] Release 2.2.11
parents 7ae7db76 7e89ccef
...@@ -21,31 +21,13 @@ ...@@ -21,31 +21,13 @@
} }
} }
.form {
position: relative;
padding: 3rem 4rem;
.card-button {
margin: 0 0 -3rem -4rem;
}
.form-group {
margin-bottom: 1.2rem;
&.has-error {
.input {
border: 1px solid $ui-orange;
}
}
}
}
.validation-message { .validation-message {
$arrow-border-width: 1rem; $arrow-border-width: 1rem;
display: block; display: block;
position: absolute; position: absolute;
top: 0;
left: 0; left: 0;
transform: translate(20rem, -4rem); transform: translate(16rem, 0);
margin-left: $arrow-border-width; margin-left: $arrow-border-width;
border: 1px solid $active-gray; border: 1px solid $active-gray;
border-radius: 5px; border-radius: 5px;
...@@ -77,6 +59,27 @@ ...@@ -77,6 +59,27 @@
} }
} }
.form {
padding: 3rem 4rem;
.card-button {
margin: 0 0 -3rem -4rem;
}
.row {
margin-bottom: 1.2rem;
&.has-error {
.input {
border: 1px solid $ui-orange;
}
}
.col-sm-9 {
position: relative;
}
}
}
} }
@media only screen and (max-width: $mobile - 1) { @media only screen and (max-width: $mobile - 1) {
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
} }
.input { .input {
width: $cols5; width: 100%;
} }
} }
...@@ -15,9 +15,7 @@ var Checkbox = React.createClass({ ...@@ -15,9 +15,7 @@ var Checkbox = React.createClass({
this.props.className this.props.className
); );
return ( return (
<div className={classes}> <FRCCheckbox rowClassName={classes} {... this.props} />
<FRCCheckbox {... this.props} />
</div>
); );
} }
}); });
......
...@@ -29,14 +29,14 @@ var Input = React.createClass({ ...@@ -29,14 +29,14 @@ var Input = React.createClass({
}, },
render: function () { render: function () {
var classes = classNames( var classes = classNames(
'input',
this.state.status, this.state.status,
this.props.className this.props.className,
{'no-label': (typeof this.props.label === 'undefined')}
); );
return (this.props.type === 'submit' || this.props.noformsy ? return (
<input {... this.props} className={classes} /> :
<FRCInput {... this.props} <FRCInput {... this.props}
className={classes} className="input"
rowClassName={classes}
onValid={this.onValid} onValid={this.onValid}
onInvalid={this.onInvalid} /> onInvalid={this.onInvalid} />
); );
......
...@@ -12,7 +12,7 @@ $pass-bg: lighten($ui-aqua, 35%); ...@@ -12,7 +12,7 @@ $pass-bg: lighten($ui-aqua, 35%);
.input { .input {
transition: all .5s ease; transition: all .5s ease;
margin: .75rem 0; margin-bottom: .75rem;
border: 1px solid $active-gray; border: 1px solid $active-gray;
border-radius: 5px; border-radius: 5px;
background-color: $base-bg; background-color: $base-bg;
......
...@@ -42,7 +42,7 @@ var PhoneInput = React.createClass({ ...@@ -42,7 +42,7 @@ var PhoneInput = React.createClass({
return ( return (
<Row {... this.getRowProperties()} <Row {... this.getRowProperties()}
htmlFor={this.getId()} htmlFor={this.getId()}
className={classNames('phone-input', this.props.className)} rowClassName={classNames('phone-input', this.props.className)}
> >
<div className="input-group"> <div className="input-group">
<ReactPhoneInput className="form-control" <ReactPhoneInput className="form-control"
...@@ -53,9 +53,9 @@ var PhoneInput = React.createClass({ ...@@ -53,9 +53,9 @@ var PhoneInput = React.createClass({
label={null} label={null}
disabled={this.isFormDisabled() || this.props.disabled} disabled={this.isFormDisabled() || this.props.disabled}
/> />
</div>
{this.renderHelp()} {this.renderHelp()}
{this.renderErrorMessage()} {this.renderErrorMessage()}
</div>
</Row> </Row>
); );
} }
......
@import "../../colors"; @import "../../colors";
.input-group { .input-group {
margin: .75rem 0;
width: 100%; width: 100%;
} }
.react-tel-input { .react-tel-input {
margin-bottom: .75rem;
width: 100%; width: 100%;
input { input {
......
...@@ -4,8 +4,19 @@ ...@@ -4,8 +4,19 @@
* the formsy-react-components * the formsy-react-components
*/ */
.form-group { .row {
.required-symbol { .required-symbol {
display: none; display: none;
} }
label {
display: inline-block;
margin-bottom: .75rem;
}
&.no-label {
label {
display: none;
}
}
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
select { select {
transition: all .5s ease; transition: all .5s ease;
margin: .75rem 0; margin-bottom: .75rem;
border: 1px solid $active-gray; border: 1px solid $active-gray;
border-radius: 5px; border-radius: 5px;
background: $ui-light-gray url("../../../static/svgs/forms/carot.svg") no-repeat right center; background: $ui-light-gray url("../../../static/svgs/forms/carot.svg") no-repeat right center;
......
...@@ -11,11 +11,13 @@ var TextArea = React.createClass({ ...@@ -11,11 +11,13 @@ var TextArea = React.createClass({
type: 'TextArea', type: 'TextArea',
render: function () { render: function () {
var classes = classNames( var classes = classNames(
'textarea', 'textarea-row',
this.props.className this.props.className
); );
return ( return (
<FRCTextarea {... this.props} className={classes} /> <FRCTextarea {... this.props}
className="textarea"
rowClassName={classes} />
); );
} }
}); });
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
.textarea { .textarea {
transition: all 1s ease; transition: all 1s ease;
margin: .75rem 0; margin-bottom: .75rem;
border: 1px solid $active-gray; border: 1px solid $active-gray;
border-radius: 5px; border-radius: 5px;
background-color: $ui-light-gray; background-color: $ui-light-gray;
......
...@@ -11,6 +11,7 @@ var api = require('../../../lib/api'); ...@@ -11,6 +11,7 @@ var api = require('../../../lib/api');
var Avatar = require('../../avatar/avatar.jsx'); var Avatar = require('../../avatar/avatar.jsx');
var Button = require('../../forms/button.jsx'); var Button = require('../../forms/button.jsx');
var Dropdown = require('../../dropdown/dropdown.jsx'); var Dropdown = require('../../dropdown/dropdown.jsx');
var Form = require('../../forms/form.jsx');
var Input = require('../../forms/input.jsx'); var Input = require('../../forms/input.jsx');
var log = require('../../../lib/log.js'); var log = require('../../../lib/log.js');
var Login = require('../../login/login.jsx'); var Login = require('../../login/login.jsx');
...@@ -170,6 +171,9 @@ var Navigation = React.createClass({ ...@@ -170,6 +171,9 @@ var Navigation = React.createClass({
this.props.dispatch(sessionActions.refreshSession()); this.props.dispatch(sessionActions.refreshSession());
this.closeRegistration(); this.closeRegistration();
}, },
onSearchSubmit: function (formData) {
window.location.href = '/search/projects?q=' + formData.q;
},
render: function () { render: function () {
var classes = classNames({ var classes = classNames({
'logged-in': this.props.session.session.user 'logged-in': this.props.session.session.user
...@@ -216,14 +220,13 @@ var Navigation = React.createClass({ ...@@ -216,14 +220,13 @@ var Navigation = React.createClass({
</li> </li>
<li className="search"> <li className="search">
<form action="/search/projects" method="get"> <Form onSubmit={this.onSearchSubmit}>
<Button type="submit" className="btn-search" /> <Button type="submit" className="btn-search" />
<Input type="text" <Input type="text"
aria-label={formatMessage({id: 'general.search'})} aria-label={formatMessage({id: 'general.search'})}
placeholder={formatMessage({id: 'general.search'})} placeholder={formatMessage({id: 'general.search'})}
name="q" name="q" />
noformsy /> </Form>
</form>
</li> </li>
{this.props.session.status === sessionActions.Status.FETCHED ? ( {this.props.session.status === sessionActions.Status.FETCHED ? (
this.props.session.session.user ? [ this.props.session.session.user ? [
......
...@@ -47,12 +47,18 @@ ...@@ -47,12 +47,18 @@
width: 100%; width: 100%;
} }
form { .form {
margin: 0; margin: 0;
} }
input, .row {
button { .help-block {
display: none;
}
}
.input,
.button {
display: inline-block; display: inline-block;
margin-top: 5px; margin-top: 5px;
outline: none; outline: none;
......
...@@ -27,6 +27,23 @@ var Tooltip = require('../../components/tooltip/tooltip.jsx'); ...@@ -27,6 +27,23 @@ var Tooltip = require('../../components/tooltip/tooltip.jsx');
require('./steps.scss'); require('./steps.scss');
var DEFAULT_COUNTRY = 'us'; var DEFAULT_COUNTRY = 'us';
var getCountryOptions = function (defaultCountry) {
var options = countryData.countryOptions.concat({
label: <intl.FormattedMessage id="registration.selectCountry" />,
disabled: true,
selected: true
});
if (typeof defaultCountry !== 'undefined') {
return options.sort(function (a, b) {
if (a.disabled) return -1;
if (b.disabled) return 1;
if (a.value === defaultCountry) return -1;
if (b.value === defaultCountry) return 1;
return 0;
}.bind(this));
}
return options;
};
var NextStepButton = React.createClass({ var NextStepButton = React.createClass({
getDefaultProps: function () { getDefaultProps: function () {
...@@ -124,12 +141,14 @@ module.exports = { ...@@ -124,12 +141,14 @@ module.exports = {
<Card> <Card>
<Form onValidSubmit={this.onValidSubmit}> <Form onValidSubmit={this.onValidSubmit}>
<div> <div>
<div className="username-label">
<b>{formatMessage({id: 'registration.createUsername'})}</b> <b>{formatMessage({id: 'registration.createUsername'})}</b>
{this.props.usernameHelp ? ( {this.props.usernameHelp ? (
<p className="help-text">{this.props.usernameHelp}</p> <p className="help-text">{this.props.usernameHelp}</p>
):( ):(
null null
)} )}
</div>
<Input className={this.state.validUsername} <Input className={this.state.validUsername}
type="text" type="text"
name="user.username" name="user.username"
...@@ -251,7 +270,6 @@ module.exports = { ...@@ -251,7 +270,6 @@ module.exports = {
DemographicsStep: intl.injectIntl(React.createClass({ DemographicsStep: intl.injectIntl(React.createClass({
getDefaultProps: function () { getDefaultProps: function () {
return { return {
defaultCountry: DEFAULT_COUNTRY,
waiting: false, waiting: false,
description: null description: null
}; };
...@@ -265,7 +283,7 @@ module.exports = { ...@@ -265,7 +283,7 @@ module.exports = {
'August', 'September', 'October', 'November', 'December' 'August', 'September', 'October', 'November', 'December'
].map(function (label, id) { ].map(function (label, id) {
return { return {
value: id+1, value: id + 1,
label: this.props.intl.formatMessage({id: 'general.month' + label})}; label: this.props.intl.formatMessage({id: 'general.month' + label})};
}.bind(this)); }.bind(this));
}, },
...@@ -321,8 +339,7 @@ module.exports = { ...@@ -321,8 +339,7 @@ module.exports = {
</div> </div>
<Select label={formatMessage({id: 'general.country'})} <Select label={formatMessage({id: 'general.country'})}
name="user.country" name="user.country"
options={countryData.countryOptions} options={getCountryOptions(DEFAULT_COUNTRY)}
value={this.props.defaultCountry}
required /> required />
<Checkbox className="demographics-checkbox-is-robot" <Checkbox className="demographics-checkbox-is-robot"
label="I'm a robot!" label="I'm a robot!"
...@@ -573,17 +590,6 @@ module.exports = { ...@@ -573,17 +590,6 @@ module.exports = {
var formatMessage = this.props.intl.formatMessage; var formatMessage = this.props.intl.formatMessage;
var stateOptions = countryData.subdivisionOptions[this.state.countryChoice]; var stateOptions = countryData.subdivisionOptions[this.state.countryChoice];
stateOptions = [{}].concat(stateOptions); stateOptions = [{}].concat(stateOptions);
var countryOptions = countryData.countryOptions.concat({
label: formatMessage({id: 'teacherRegistration.selectCountry'}),
disabled: true,
selected: true
}).sort(function (a, b) {
if (a.disabled) return -1;
if (b.disabled) return 1;
if (a.value === this.props.defaultCountry) return -1;
if (b.value === this.props.defaultCountry) return 1;
return 0;
}.bind(this));
return ( return (
<Slide className="registration-step address-step"> <Slide className="registration-step address-step">
<h2> <h2>
...@@ -598,7 +604,8 @@ module.exports = { ...@@ -598,7 +604,8 @@ module.exports = {
<Form onValidSubmit={this.onValidSubmit}> <Form onValidSubmit={this.onValidSubmit}>
<Select label={formatMessage({id: 'general.country'})} <Select label={formatMessage({id: 'general.country'})}
name="address.country" name="address.country"
options={countryOptions} options={getCountryOptions()}
value={this.props.defaultCountry}
onChange={this.onChangeCountry} onChange={this.onChangeCountry}
required /> required />
<Input label={formatMessage({id: 'teacherRegistration.addressLine1'})} <Input label={formatMessage({id: 'teacherRegistration.addressLine1'})}
...@@ -762,7 +769,8 @@ module.exports = { ...@@ -762,7 +769,8 @@ module.exports = {
getDefaultProps: function () { getDefaultProps: function () {
return { return {
email: null, email: null,
invited: false invited: false,
confirmed: false
}; };
}, },
render: function () { render: function () {
...@@ -805,7 +813,7 @@ module.exports = { ...@@ -805,7 +813,7 @@ module.exports = {
); );
} }
})), })),
ClassInviteStep: intl.injectIntl(React.createClass({ ClassInviteNewStudentStep: intl.injectIntl(React.createClass({
getDefaultProps: function () { getDefaultProps: function () {
return { return {
waiting: false waiting: false
...@@ -825,17 +833,58 @@ module.exports = { ...@@ -825,17 +833,58 @@ module.exports = {
src={this.props.classroom.educator.profile.images['50x50']} />, src={this.props.classroom.educator.profile.images['50x50']} />,
<h2>{this.props.classroom.educator.username}</h2>, <h2>{this.props.classroom.educator.username}</h2>,
<p className="description"> <p className="description">
{formatMessage({id: 'registration.classroomInviteStepDescription'})} {formatMessage({id: 'registration.classroomInviteNewStudentStepDescription'})}
</p>,
<Card>
<div className="contents">
<h3>{this.props.classroom.title}</h3>
<img className="class-image" src={this.props.classroom.images['250x150']} />
</div>
<NextStepButton onClick={this.onNextStep}
waiting={this.props.waiting}
text={formatMessage({id: 'general.getStarted'})} />
</Card>,
<StepNavigation steps={this.props.totalSteps - 1} active={this.props.activeStep} />
]}
</Slide>
);
}
})),
ClassInviteExistingStudentStep: intl.injectIntl(React.createClass({
getDefaultProps: function () {
return {
classroom: null,
onHandleLogOut: function () {},
studentUsername: null,
waiting: false
};
},
onNextStep: function () {
this.props.onNextStep();
},
render: function () {
var formatMessage = this.props.intl.formatMessage;
return (
<Slide className="registration-step class-invite-step">
{this.props.waiting ? [
<Spinner />
] : [
<h2>{this.props.studentUsername}</h2>,
<p className="description">
{formatMessage({id: 'registration.classroomInviteExistingStudentStepDescription'})}
</p>, </p>,
<Card> <Card>
<div className="contents"> <div className="contents">
<h3>{this.props.classroom.title}</h3> <h3>{this.props.classroom.title}</h3>
<img className="class-image" src={this.props.classroom.images['250x150']} /> <img className="class-image" src={this.props.classroom.images['250x150']} />
<p>{formatMessage({id: 'registration.invitedBy'})}</p>
<p><strong>{this.props.classroom.educator.username}</strong></p>
</div> </div>
<NextStepButton onClick={this.onNextStep} <NextStepButton onClick={this.onNextStep}
waiting={this.props.waiting} waiting={this.props.waiting}
text={formatMessage({id: 'general.getStarted'})} /> text={formatMessage({id: 'general.getStarted'})} />
</Card>, </Card>,
<p><a onClick={this.props.onHandleLogOut}>{formatMessage({id: 'registration.notYou'})}</a></p>,
<StepNavigation steps={this.props.totalSteps - 1} active={this.props.activeStep} /> <StepNavigation steps={this.props.totalSteps - 1} active={this.props.activeStep} />
]} ]}
</Slide> </Slide>
......
...@@ -29,6 +29,15 @@ ...@@ -29,6 +29,15 @@
color: $ui-dark-gray; color: $ui-dark-gray;
} }
&.class-invite-step {
text-align: center;
> p a {
text-decoration: underline;
color: $ui-white;
font-weight: inherit;
}
}
&.class-invite-step, &.class-invite-step,
&.class-welcome-step { &.class-welcome-step {
...@@ -41,6 +50,12 @@ ...@@ -41,6 +50,12 @@
} }
} }
&.username-step {
.username-label {
margin-bottom: .75rem;
}
}
&.demographics-step { &.demographics-step {
.gender-input { .gender-input {
margin-top: -5.5rem; margin-top: -5.5rem;
...@@ -66,26 +81,12 @@ ...@@ -66,26 +81,12 @@
margin-bottom: 1.25rem; margin-bottom: 1.25rem;
} }
} }
.validation-message {
margin-top: .5rem;
}
.checkbox-row {
.validation-message {
margin-top: 0;
}
}
} }
&.organization-step { &.organization-step {
.validation-message {
transform: translate(16rem, -4rem);
}
.checkbox-group { .checkbox-group {
.validation-message { .validation-message {
transform: translate(16rem, -16rem); transform: translate(16rem, 8rem);
} }
} }
...@@ -100,14 +101,6 @@ ...@@ -100,14 +101,6 @@
} }
} }
&.address-step {
.select {
.validation-message {
transform: translate(0, .5rem);
}
}
}
&.usescratch-step { &.usescratch-step {
.form { .form {
.form-group { .form-group {
...@@ -119,12 +112,6 @@ ...@@ -119,12 +112,6 @@
} }
} }
} }
}
.validation-message {
margin-top: .75rem;
} }
p { p {
......
...@@ -111,19 +111,24 @@ ...@@ -111,19 +111,24 @@
"registration.choosePasswordStepDescription": "Type in a new password for your account. You will use this password the next time you log into Scratch.", "registration.choosePasswordStepDescription": "Type in a new password for your account. You will use this password the next time you log into Scratch.",
"registration.choosePasswordStepTitle": "Create a password", "registration.choosePasswordStepTitle": "Create a password",
"registration.choosePasswordStepTooltip": "Don't use your name or anything that's easy for someone else to guess.", "registration.choosePasswordStepTooltip": "Don't use your name or anything that's easy for someone else to guess.",
"registration.classroomInviteStepDescription": "has invited you to join the class:", "registration.classroomApiGeneralError": "Sorry, we could not find the registration information for this class",
"registration.classroomInviteExistingStudentStepDescription": "you have been invited to join the class:",
"registration.classroomInviteNewStudentStepDescription": "has invited you to join the class:",
"registration.confirmYourEmail": "Confirm Your Email", "registration.confirmYourEmail": "Confirm Your Email",
"registration.confirmYourEmailDescription": "If you haven't already, please click the link in the confirmation email sent to:", "registration.confirmYourEmailDescription": "If you haven't already, please click the link in the confirmation email sent to:",
"registration.createUsername": "Create a Username", "registration.createUsername": "Create a Username",
"registration.goToClass": "Go to Class", "registration.goToClass": "Go to Class",
"registration.invitedBy": "invited by",
"registration.lastStepTitle": "Thank you for requesting a Scratch Teacher Account", "registration.lastStepTitle": "Thank you for requesting a Scratch Teacher Account",
"registration.lastStepDescription": "We are currently processing your application. ", "registration.lastStepDescription": "We are currently processing your application. ",
"registration.mustBeNewStudent": "You must be a new student to complete your registration", "registration.mustBeNewStudent": "You must be a new student to complete your registration",
"registration.nameStepTooltip": "This information is used for verification and to aggregate usage statistics.", "registration.nameStepTooltip": "This information is used for verification and to aggregate usage statistics.",
"registration.newPassword": "New Password", "registration.newPassword": "New Password",
"registration.nextStep": "Next Step", "registration.nextStep": "Next Step",
"registration.notYou": "Not you? Log in as another user",
"registration.personalStepTitle": "Personal Information", "registration.personalStepTitle": "Personal Information",
"registration.personalStepDescription": "Your individual responses will not be displayed publicly, and will be kept confidential and secure", "registration.personalStepDescription": "Your individual responses will not be displayed publicly, and will be kept confidential and secure",
"registration.selectCountry": "select country",
"registration.studentPersonalStepDescription": "This information will not appear on the Scratch website.", "registration.studentPersonalStepDescription": "This information will not appear on the Scratch website.",
"registration.showPassword": "Show password", "registration.showPassword": "Show password",
"registration.usernameStepDescription": "Fill in the following forms to request an account. The approval process may take up to 24 hours.", "registration.usernameStepDescription": "Fill in the following forms to request an account. The approval process may take up to 24 hours.",
......
...@@ -79,6 +79,12 @@ module.exports.refreshSession = function () { ...@@ -79,6 +79,12 @@ module.exports.refreshSession = function () {
body.flags.must_complete_registration && body.flags.must_complete_registration &&
window.location.pathname !== '/classes/complete_registration') { window.location.pathname !== '/classes/complete_registration') {
return window.location = '/classes/complete_registration'; return window.location = '/classes/complete_registration';
} else if (
body.flags &&
body.flags.must_reset_password &&
!body.flags.must_complete_registration &&
window.location.pathname !== '/classes/student_password_reset/') {
return window.location = '/classes/student_password_reset/';
} else { } else {
dispatch(tokenActions.getToken()); dispatch(tokenActions.getToken());
dispatch(module.exports.setSession(body)); dispatch(module.exports.setSession(body));
......
...@@ -6,6 +6,7 @@ var render = require('../../lib/render.jsx'); ...@@ -6,6 +6,7 @@ var render = require('../../lib/render.jsx');
var sessionStatus = require('../../redux/session').Status; var sessionStatus = require('../../redux/session').Status;
var api = require('../../lib/api'); var api = require('../../lib/api');
var intl = require('../../lib/intl.jsx'); var intl = require('../../lib/intl.jsx');
var log = require('../../lib/log.js');
var Deck = require('../../components/deck/deck.jsx'); var Deck = require('../../components/deck/deck.jsx');
var Progression = require('../../components/progression/progression.jsx'); var Progression = require('../../components/progression/progression.jsx');
...@@ -33,17 +34,16 @@ var StudentCompleteRegistration = intl.injectIntl(React.createClass({ ...@@ -33,17 +34,16 @@ var StudentCompleteRegistration = intl.injectIntl(React.createClass({
}); });
}, },
componentDidUpdate: function (prevProps) { componentDidUpdate: function (prevProps) {
if (prevProps.session.session !== this.props.session.session && if (prevProps.studentUsername !== this.props.studentUsername && this.props.newStudent) {
this.props.session.session.permissions && this.setState({waiting: true});
this.props.session.session.permissions.student) {
var classroomId = this.props.session.session.user.classroomId;
api({ api({
uri: '/classrooms/' + classroomId uri: '/classrooms/' + this.props.classroomId
}, function (err, body, res) { }, function (err, body, res) {
if (err || res.statusCode === 404) { this.setState({waiting: false});
if (err || res.statusCode !== 200) {
return this.setState({ return this.setState({
registrationErrors: { registrationErrors: {
__all__: this.props.intl.formatMessage({id: 'studentRegistration.classroomApiGeneralError'}) __all__: this.props.intl.formatMessage({id: 'registration.classroomApiGeneralError'})
} }
}); });
} }
...@@ -51,6 +51,18 @@ var StudentCompleteRegistration = intl.injectIntl(React.createClass({ ...@@ -51,6 +51,18 @@ var StudentCompleteRegistration = intl.injectIntl(React.createClass({
}.bind(this)); }.bind(this));
} }
}, },
handleLogOut: function (e) {
e.preventDefault();
api({
host: '',
method: 'post',
uri: '/accounts/logout/',
useCsrf: true
}, function (err) {
if (err) return log.error(err);
window.location = '/';
}.bind(this));
},
register: function (formData) { register: function (formData) {
this.setState({waiting: true}); this.setState({waiting: true});
formData = defaults({}, formData || {}, this.state.formData); formData = defaults({}, formData || {}, this.state.formData);
...@@ -65,7 +77,7 @@ var StudentCompleteRegistration = intl.injectIntl(React.createClass({ ...@@ -65,7 +77,7 @@ var StudentCompleteRegistration = intl.injectIntl(React.createClass({
country: formData.user.country, country: formData.user.country,
is_robot: formData.user.isRobot is_robot: formData.user.isRobot
}; };
if (this.props.session.session.flags.must_reset_password) { if (this.props.must_reset_password) {
submittedData.password = formData.user.password; submittedData.password = formData.user.password;
} }
api({ api({
...@@ -88,18 +100,14 @@ var StudentCompleteRegistration = intl.injectIntl(React.createClass({ ...@@ -88,18 +100,14 @@ var StudentCompleteRegistration = intl.injectIntl(React.createClass({
var demographicsDescription = this.props.intl.formatMessage({ var demographicsDescription = this.props.intl.formatMessage({
id: 'registration.studentPersonalStepDescription'}); id: 'registration.studentPersonalStepDescription'});
var registrationErrors = this.state.registrationErrors; var registrationErrors = this.state.registrationErrors;
var sessionFetched = this.props.session.status === sessionStatus.FETCHED; if (!this.props.newStudent) {
if (sessionFetched &&
!(this.props.session.session.permissions.student &&
this.props.session.session.flags.must_complete_registration)) {
registrationErrors = { registrationErrors = {
__all__: this.props.intl.formatMessage({id: 'registration.mustBeNewStudent'}) __all__: this.props.intl.formatMessage({id: 'registration.mustBeNewStudent'})
}; };
} }
return ( return (
<Deck className="student-registration"> <Deck className="student-registration">
{sessionFetched && this.state.classroom ? {registrationErrors ? (
(registrationErrors ?
<Steps.RegistrationError> <Steps.RegistrationError>
<ul> <ul>
{Object.keys(registrationErrors).map(function (field) { {Object.keys(registrationErrors).map(function (field) {
...@@ -111,13 +119,17 @@ var StudentCompleteRegistration = intl.injectIntl(React.createClass({ ...@@ -111,13 +119,17 @@ var StudentCompleteRegistration = intl.injectIntl(React.createClass({
})} })}
</ul> </ul>
</Steps.RegistrationError> </Steps.RegistrationError>
: ) : (
this.state.waiting || !this.state.classroom ? (
<Spinner />
) : (
<Progression {... this.state}> <Progression {... this.state}>
<Steps.ClassInviteStep classroom={this.state.classroom} <Steps.ClassInviteExistingStudentStep classroom={this.state.classroom}
messages={this.props.messages} onHandleLogOut={this.handleLogOut}
onNextStep={this.advanceStep} onNextStep={this.advanceStep}
studentUsername={this.props.studentUsername}
waiting={this.state.waiting} /> waiting={this.state.waiting} />
{this.props.session.session.flags.must_reset_password ? {this.props.must_reset_password ?
<Steps.ChoosePasswordStep onNextStep={this.advanceStep} <Steps.ChoosePasswordStep onNextStep={this.advanceStep}
showPassword={true} showPassword={true}
waiting={this.state.waiting} /> waiting={this.state.waiting} />
...@@ -132,9 +144,7 @@ var StudentCompleteRegistration = intl.injectIntl(React.createClass({ ...@@ -132,9 +144,7 @@ var StudentCompleteRegistration = intl.injectIntl(React.createClass({
waiting={this.state.waiting} /> waiting={this.state.waiting} />
</Progression> </Progression>
) )
: )}
<Spinner />
}
</Deck> </Deck>
); );
} }
...@@ -142,7 +152,14 @@ var StudentCompleteRegistration = intl.injectIntl(React.createClass({ ...@@ -142,7 +152,14 @@ var StudentCompleteRegistration = intl.injectIntl(React.createClass({
var mapStateToProps = function (state) { var mapStateToProps = function (state) {
return { return {
session: state.session classroomId: state.session.session.user && state.session.session.user.classroomId,
must_reset_password: state.session.session.flags && state.session.session.flags.must_reset_password,
newStudent: (
state.session.session.permissions &&
state.session.session.permissions.student &&
state.session.session.flags.must_complete_registration),
sessionFetched: state.session.status === sessionStatus.FETCHED,
studentUsername: state.session.session.user && state.session.session.user.username
}; };
}; };
......
{
"studentRegistration.classroomApiGeneralError": "Sorry, we could not find the registration information for this class"
}
...@@ -35,14 +35,16 @@ var StudentRegistration = intl.injectIntl(React.createClass({ ...@@ -35,14 +35,16 @@ var StudentRegistration = intl.injectIntl(React.createClass({
}); });
}, },
componentDidMount: function () { componentDidMount: function () {
this.setState({waiting: true});
api({ api({
uri: '/classrooms/' + this.props.classroomId, uri: '/classrooms/' + this.props.classroomId,
params: {token: this.props.classroomToken} params: {token: this.props.classroomToken}
}, function (err, body, res) { }, function (err, body, res) {
this.setState({waiting: false});
if (err) { if (err) {
return this.setState({ return this.setState({
registrationError: this.props.intl.formatMessage({ registrationError: this.props.intl.formatMessage({
id: 'studentRegistration.classroomApiGeneralError' id: 'registration.classroomApiGeneralError'
}) })
}); });
} }
...@@ -104,7 +106,7 @@ var StudentRegistration = intl.injectIntl(React.createClass({ ...@@ -104,7 +106,7 @@ var StudentRegistration = intl.injectIntl(React.createClass({
</Steps.RegistrationError> </Steps.RegistrationError>
: :
<Progression {... this.state}> <Progression {... this.state}>
<Steps.ClassInviteStep classroom={this.state.classroom} <Steps.ClassInviteNewStudentStep classroom={this.state.classroom}
onNextStep={this.advanceStep} onNextStep={this.advanceStep}
waiting={this.state.waiting || !this.state.classroom} /> waiting={this.state.waiting || !this.state.classroom} />
<Steps.UsernameStep onNextStep={this.advanceStep} <Steps.UsernameStep onNextStep={this.advanceStep}
......
...@@ -19,13 +19,12 @@ ...@@ -19,13 +19,12 @@
"teacherRegistration.orgChoiceMiddleSchool": "Middle School", "teacherRegistration.orgChoiceMiddleSchool": "Middle School",
"teacherRegistration.orgChoiceHighSchool": "High School", "teacherRegistration.orgChoiceHighSchool": "High School",
"teacherRegistration.orgChoiceUniversity": "College/University", "teacherRegistration.orgChoiceUniversity": "College/University",
"teacherRegistration.orgChoiceAfterschool": "Afterscool Program", "teacherRegistration.orgChoiceAfterschool": "Afterschool Program",
"teacherRegistration.orgChoiceMuseum": "Museum", "teacherRegistration.orgChoiceMuseum": "Museum",
"teacherRegistration.orgChoiceLibrary": "Library", "teacherRegistration.orgChoiceLibrary": "Library",
"teacherRegistration.orgChoiceCamp": "Camp", "teacherRegistration.orgChoiceCamp": "Camp",
"teacherRegistration.orgChoiceOther": " ", "teacherRegistration.orgChoiceOther": " ",
"teacherRegistration.notRequired": "Not Required", "teacherRegistration.notRequired": "Not Required",
"teacherRegistration.selectCountry": "select country",
"teacherRegistration.addressValidationError": "This doesn't look like a real address", "teacherRegistration.addressValidationError": "This doesn't look like a real address",
"teacherRegistration.addressLine1": "Address Line 1", "teacherRegistration.addressLine1": "Address Line 1",
"teacherRegistration.addressLine2": "Address Line 2 (Optional)", "teacherRegistration.addressLine2": "Address Line 2 (Optional)",
......
...@@ -10,6 +10,11 @@ require('./teacherwaitingroom.scss'); ...@@ -10,6 +10,11 @@ require('./teacherwaitingroom.scss');
var TeacherWaitingRoom = React.createClass({ var TeacherWaitingRoom = React.createClass({
displayName: 'TeacherWaitingRoom', displayName: 'TeacherWaitingRoom',
componentWillReceiveProps: function (nextProps) {
if (nextProps.session.permissions.educator && nextProps.session.permissions.social) {
window.location.href = '/educators/classes/';
}
},
render: function () { render: function () {
var permissions = this.props.session.permissions || {}; var permissions = this.props.session.permissions || {};
var user = this.props.session.user || {}; var user = this.props.session.user || {};
......
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