mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2025-02-17 00:21:20 -05:00
Merge pull request #782 from LLK/release/2.2.11
[Develop] Release 2.2.11
This commit is contained in:
commit
02ff0217c9
22 changed files with 234 additions and 144 deletions
|
@ -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 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.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 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
width: $cols5;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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({
|
||||||
},
|
},
|
||||||
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%);
|
||||||
|
|
||||||
.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({
|
||||||
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({
|
||||||
label={null}
|
label={null}
|
||||||
disabled={this.isFormDisabled() || this.props.disabled}
|
disabled={this.isFormDisabled() || this.props.disabled}
|
||||||
/>
|
/>
|
||||||
|
{this.renderHelp()}
|
||||||
|
{this.renderErrorMessage()}
|
||||||
</div>
|
</div>
|
||||||
{this.renderHelp()}
|
|
||||||
{this.renderErrorMessage()}
|
|
||||||
</Row>
|
</Row>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
@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 @@
|
||||||
* 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 @@
|
||||||
|
|
||||||
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({
|
||||||
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 @@
|
||||||
|
|
||||||
.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');
|
||||||
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({
|
||||||
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({
|
||||||
</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 @@
|
||||||
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');
|
||||||
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 = {
|
||||||
<Card>
|
<Card>
|
||||||
<Form onValidSubmit={this.onValidSubmit}>
|
<Form onValidSubmit={this.onValidSubmit}>
|
||||||
<div>
|
<div>
|
||||||
<b>{formatMessage({id: 'registration.createUsername'})}</b>
|
<div className="username-label">
|
||||||
{this.props.usernameHelp ? (
|
<b>{formatMessage({id: 'registration.createUsername'})}</b>
|
||||||
<p className="help-text">{this.props.usernameHelp}</p>
|
{this.props.usernameHelp ? (
|
||||||
):(
|
<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 = {
|
||||||
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 = {
|
||||||
'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 = {
|
||||||
</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 = {
|
||||||
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 = {
|
||||||
<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 = {
|
||||||
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 = {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
ClassInviteStep: intl.injectIntl(React.createClass({
|
ClassInviteNewStudentStep: intl.injectIntl(React.createClass({
|
||||||
getDefaultProps: function () {
|
getDefaultProps: function () {
|
||||||
return {
|
return {
|
||||||
waiting: false
|
waiting: false
|
||||||
|
@ -825,7 +833,7 @@ 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>,
|
</p>,
|
||||||
<Card>
|
<Card>
|
||||||
<div className="contents">
|
<div className="contents">
|
||||||
|
@ -842,6 +850,47 @@ module.exports = {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
|
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>,
|
||||||
|
<Card>
|
||||||
|
<div className="contents">
|
||||||
|
<h3>{this.props.classroom.title}</h3>
|
||||||
|
<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>
|
||||||
|
<NextStepButton onClick={this.onNextStep}
|
||||||
|
waiting={this.props.waiting}
|
||||||
|
text={formatMessage({id: 'general.getStarted'})} />
|
||||||
|
</Card>,
|
||||||
|
<p><a onClick={this.props.onHandleLogOut}>{formatMessage({id: 'registration.notYou'})}</a></p>,
|
||||||
|
<StepNavigation steps={this.props.totalSteps - 1} active={this.props.activeStep} />
|
||||||
|
]}
|
||||||
|
</Slide>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})),
|
||||||
ClassWelcomeStep: intl.injectIntl(React.createClass({
|
ClassWelcomeStep: intl.injectIntl(React.createClass({
|
||||||
getDefaultProps: function () {
|
getDefaultProps: function () {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -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 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.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 @@
|
||||||
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 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.address-step {
|
|
||||||
.select {
|
|
||||||
.validation-message {
|
|
||||||
transform: translate(0, .5rem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.usescratch-step {
|
&.usescratch-step {
|
||||||
.form {
|
.form {
|
||||||
.form-group {
|
.form-group {
|
||||||
|
@ -119,12 +112,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.validation-message {
|
|
||||||
margin-top: .75rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
|
|
|
@ -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 () {
|
||||||
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');
|
||||||
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({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
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({
|
||||||
}.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({
|
||||||
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,36 +100,36 @@ 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) {
|
var label = field + ': ';
|
||||||
var label = field + ': ';
|
if (field === '__all__') {
|
||||||
if (field === '__all__') {
|
label = '';
|
||||||
label = '';
|
}
|
||||||
}
|
return (<li>{label}{registrationErrors[field]}</li>);
|
||||||
return (<li>{label}{registrationErrors[field]}</li>);
|
})}
|
||||||
})}
|
</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({
|
||||||
waiting={this.state.waiting} />
|
waiting={this.state.waiting} />
|
||||||
</Progression>
|
</Progression>
|
||||||
)
|
)
|
||||||
:
|
)}
|
||||||
<Spinner />
|
|
||||||
}
|
|
||||||
</Deck>
|
</Deck>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
{
|
|
||||||
"studentRegistration.classroomApiGeneralError": "Sorry, we could not find the registration information for this class"
|
|
||||||
}
|
|
|
@ -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,9 +106,9 @@ 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}
|
||||||
title={usernameTitle}
|
title={usernameTitle}
|
||||||
description={usernameDescription}
|
description={usernameDescription}
|
||||||
|
|
|
@ -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');
|
||||||
|
|
||||||
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 || {};
|
||||||
|
|
Loading…
Reference in a new issue