Commit a4dd1611 authored by Ray Schamp's avatar Ray Schamp

Add student registration update view

parent 1df6eb5d
...@@ -185,6 +185,61 @@ module.exports = { ...@@ -185,6 +185,61 @@ module.exports = {
); );
} }
})), })),
ChoosePasswordStep: intl.injectIntl(React.createClass({
getDefaultProps: function () {
return {
waiting: false
};
},
getInitialState: function () {
return {
showPassword: false
};
},
onChangeShowPassword: function (field, value) {
this.setState({showPassword: value});
},
render: function () {
var formatMessage = this.props.intl.formatMessage;
return (
<Slide className="registration-step choose-password-step">
<h2>{formatMessage({id: 'registration.choosePasswordStepTitle'})}</h2>
<Card>
<Form onValidSubmit={this.props.onNextStep}>
<Input label={formatMessage({id: 'general.password'})}
type={this.state.showPassword ? 'text' : 'password'}
name="user.password"
validations={{
minLength: 6,
notEquals: 'password',
notEqualsField: 'user.username'
}}
validationErrors={{
minLength: formatMessage({
id: 'registration.validationPasswordLength'
}),
notEquals: formatMessage({
id: 'registration.validationPasswordNotEquals'
}),
notEqualsField: formatMessage({
id: 'registration.validationPasswordNotUsername'
})
}}
required />
<Checkbox label={formatMessage({id: 'registration.showPassword'})}
value={this.state.showPassword}
onChange={this.onChangeShowPassword}
help={null}
name="showPassword" />
<NextStepButton waiting={this.props.waiting || this.state.waiting}
text={<intl.FormattedMessage id="registration.nextStep" />} />
</Form>
</Card>
<StepNavigation steps={this.props.totalSteps - 1} active={this.props.activeStep} />
</Slide>
);
}
})),
DemographicsStep: intl.injectIntl(React.createClass({ DemographicsStep: intl.injectIntl(React.createClass({
getDefaultProps: function () { getDefaultProps: function () {
return { return {
......
...@@ -108,6 +108,7 @@ ...@@ -108,6 +108,7 @@
"registration.checkOutResources": "Get Started with Resources", "registration.checkOutResources": "Get Started with Resources",
"registration.checkOutResourcesDescription": "Explore materials for educators and facilitators written by the Scratch Team, including <a href='/educators#resources'>tips, tutorials, and guides</a>.", "registration.checkOutResourcesDescription": "Explore materials for educators and facilitators written by the Scratch Team, including <a href='/educators#resources'>tips, tutorials, and guides</a>.",
"registration.choosePasswordStepTitle": "Choose a password",
"registration.classroomInviteStepDescription": "has invited you to join the class:", "registration.classroomInviteStepDescription": "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:",
...@@ -115,6 +116,7 @@ ...@@ -115,6 +116,7 @@
"registration.goToClass": "Go to Class", "registration.goToClass": "Go to Class",
"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.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.nextStep": "Next Step", "registration.nextStep": "Next Step",
"registration.personalStepTitle": "Personal Information", "registration.personalStepTitle": "Personal Information",
......
...@@ -17,6 +17,12 @@ ...@@ -17,6 +17,12 @@
"view": "guidelines/guidelines", "view": "guidelines/guidelines",
"title": "Scratch Community Guidelines" "title": "Scratch Community Guidelines"
}, },
{
"name": "student-complete-registration",
"pattern": "^/classes/complete_registration",
"view": "studentcompleteregistration/studentcompleteregistration",
"title": "Complete your Registration"
},
{ {
"name": "student-registration", "name": "student-registration",
"pattern": "^/classes/:id/register/:token", "pattern": "^/classes/:id/register/:token",
......
var connect = require('react-redux').connect;
var defaults = require('lodash.defaultsdeep');
var React = require('react');
var render = require('../../lib/render.jsx');
var sessionStatus = require('../../redux/session').Status;
var api = require('../../lib/api');
var intl = require('../../lib/intl.jsx');
var Deck = require('../../components/deck/deck.jsx');
var Progression = require('../../components/progression/progression.jsx');
var Spinner = require('../../components/spinner/spinner.jsx');
var Steps = require('../../components/registration/steps.jsx');
require('./studentcompleteregistration.scss');
var StudentCompleteRegistration = intl.injectIntl(React.createClass({
type: 'StudentCompleteRegistration',
getInitialState: function () {
return {
classroom: null,
formData: {},
registrationError: null,
step: 0,
waiting: false
};
},
advanceStep: function (formData) {
formData = formData || {};
this.setState({
step: this.state.step + 1,
formData: defaults({}, formData, this.state.formData)
});
},
componentDidUpdate: function (prevProps) {
if (prevProps.session.session !== this.props.session.session &&
this.props.session.session.permissions &&
this.props.session.session.permissions.student) {
var classroomId = this.props.session.session.user.classroomId;
api({
uri: '/classrooms/' + classroomId
}, function (err, body, res) {
if (err || res.statusCode === 404) {
return this.setState({
registrationError: this.props.intl.formatMessage({
id: 'studentRegistration.classroomApiGeneralError'
})
});
}
this.setState({classroom: body});
}.bind(this));
}
},
register: function (formData) {
this.setState({waiting: true});
formData = defaults({}, formData || {}, this.state.formData);
var submittedData = {
birth_month: formData.user.birth.month,
birth_year: formData.user.birth.year,
gender: (
formData.user.gender === 'other' ?
formData.user.genderOther :
formData.user.gender
),
country: formData.user.country,
is_robot: formData.user.isRobot
};
if (this.props.session.session.flags.must_reset_password) {
submittedData.password = formData.user.password;
}
api({
host: '',
uri: '/classes/student_update_registration/',
method: 'post',
useCsrf: true,
formData: submittedData
}, function (err, body) {
this.setState({waiting: false});
if (err) return this.setState({registrationError: err});
if (body.success) return this.advanceStep(formData);
this.setState({registrationError: (
<ul>
{Object.keys(body.errors).map(function (field) {
var label = field + ': ';
if (field === '__all__') {
label = '';
}
return (<li>{label}{body.errors[field]}</li>);
})}
</ul>
)});
}.bind(this));
},
goToClass: function () {
window.location = '/classes/' + this.state.classroom.id + '/';
},
render: function () {
var demographicsDescription = this.props.intl.formatMessage({
id: 'registration.studentPersonalStepDescription'});
var registrationError = this.state.registrationError;
var sessionFetched = this.props.session.status === sessionStatus.FETCHED;
if (sessionFetched &&
!(this.props.session.session.permissions.student &&
this.props.session.session.flags.must_complete_registration)) {
registrationError = this.props.intl.formatMessage({id: 'registration.mustBeNewStudent'});
}
return (
<Deck className="student-registration">
{sessionFetched && this.state.classroom ?
(registrationError ?
<Steps.RegistrationError registrationError={registrationError} />
:
<Progression {... this.state}>
<Steps.ClassInviteStep classroom={this.state.classroom}
messages={this.props.messages}
onNextStep={this.advanceStep}
waiting={this.state.waiting} />
{this.props.session.session.flags.must_reset_password ?
<Steps.ChoosePasswordStep onNextStep={this.advanceStep}
waiting={this.state.waiting} />
:
[]
}
<Steps.DemographicsStep description={demographicsDescription}
onNextStep={this.register}
waiting={this.state.waiting} />
<Steps.ClassWelcomeStep classroom={this.state.classroom}
onNextStep={this.goToClass}
waiting={this.state.waiting} />
</Progression>
)
:
<Spinner />
}
</Deck>
);
}
}));
var mapStateToProps = function (state) {
return {
session: state.session
};
};
var ConnectedStudentCompleteRegistration = connect(mapStateToProps)(StudentCompleteRegistration);
render(<ConnectedStudentCompleteRegistration />, document.getElementById('app'));
@import "../../colors";
@import "../../frameless";
@include responsive-layout (".student-registration", ".slide");
html,
body {
background-color: darken($ui-purple, 8%);
}
.student-complete-registration {
background-color: $ui-purple;
}
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