Merge pull request #1135 from LLK/release/2.2.16

[Master] Release 2.2.16
This commit is contained in:
Ray Schamp 2016-12-20 12:27:14 -05:00 committed by GitHub
commit 023d0d6368
25 changed files with 136 additions and 243 deletions

View file

@ -5,6 +5,7 @@
"ast": "Asturianu",
"id": "Bahasa Indonesia",
"ms": "Bahasa Melayu",
"be": "Беларуская",
"bg": "Български",
"ca": "Català",
"cs": "Česky",

View file

@ -1,4 +1,5 @@
var defaults = require('lodash.defaultsdeep');
var intl = require('../../lib/intl.jsx');
var libphonenumber = require('google-libphonenumber');
var phoneNumberUtil = libphonenumber.PhoneNumberUtil.getInstance();
var React = require('react');
@ -44,5 +45,5 @@ module.exports.validationHOCFactory = function (defaultValidationErrors) {
};
module.exports.defaultValidationHOC = module.exports.validationHOCFactory({
isDefaultRequiredValue: 'This field is required'
isDefaultRequiredValue: <intl.FormattedMessage id="form.validationRequired" />
});

View file

@ -36,7 +36,8 @@ var Navigation = React.createClass({
},
getDefaultProps: function () {
return {
session: {}
session: {},
searchTerm: ''
};
},
componentDidMount: function () {
@ -221,6 +222,7 @@ var Navigation = React.createClass({
<Form onSubmit={this.onSearchSubmit}>
<Button type="submit" className="btn-search" />
<Input type="text"
value={this.props.searchTerm}
aria-label={formatMessage({id: 'general.search'})}
placeholder={formatMessage({id: 'general.search'})}
name="q" />
@ -345,7 +347,8 @@ var Navigation = React.createClass({
var mapStateToProps = function (state) {
return {
session: state.session,
permissions: state.permissions
permissions: state.permissions,
searchTerm: state.navigation
};
};

View file

@ -93,7 +93,7 @@ module.exports = {
callback = callback || function () {};
if (!username) {
this.refs.form.refs.formsy.updateInputsWithError({
'user.username': formatMessage({id: 'teacherRegistration.validationRequired'})
'user.username': this.props.intl.formatMessage({id: 'form.validationRequired'})
});
return callback(false);
}
@ -360,24 +360,24 @@ module.exports = {
options={[
{value: 'female', label: formatMessage({id: 'general.female'})},
{value: 'male', label: formatMessage({id: 'general.male'})},
{value: 'other', label: ''}
{value: 'other', label: <Input
className="demographics-step-input-other"
name="user.genderOther"
type="text"
validations={{
maxLength: 25
}}
validationErrors={{
maxLength: formatMessage({
id: 'registration.validationMaxLength'
})
}}
disabled={this.state.otherDisabled}
required={!this.state.otherDisabled}
help={null}
/>}
]}
required />
<div className="gender-input">
<Input name="user.genderOther"
type="text"
validations={{
maxLength: 25
}}
validationErrors={{
maxLength: formatMessage({
id: 'registration.validationMaxLength'
})
}}
disabled={this.state.otherDisabled}
required={!this.state.otherDisabled}
help={null} />
</div>
<Select label={formatMessage({id: 'general.country'})}
name="user.country"
options={getCountryOptions(this.props.intl, DEFAULT_COUNTRY)}
@ -457,7 +457,7 @@ module.exports = {
onValidSubmit: function (formData, reset, invalidate) {
if (!formData.phone || formData.phone.national_number === '+') {
return invalidate({
'phone': this.props.intl.formatMessage({id: 'teacherRegistration.validationRequired'})
'phone': this.props.intl.formatMessage({id: 'form.validationRequired'})
});
}
return this.props.onNextStep(formData);
@ -582,7 +582,7 @@ module.exports = {
}}
validationErrors={{
minLength: formatMessage({
id: 'teacherRegistration.validationRequired'
id: 'form.validationRequired'
})
}}
required />

View file

@ -13,7 +13,6 @@
border-radius: 8px;
}
.gender-input,
.other-input {
float: right;
width: 90%;
@ -61,16 +60,19 @@
}
&.demographics-step {
.gender-input {
margin-top: -5.5rem;
.radio {
margin: 1.5rem 1.5rem 0 0;
}
.radio {
margin-right: 2.5rem;
line-height: 3rem;
input[type="radio"] {
margin-right: 1rem;
}
input {
margin-right: 1rem;
.demographics-step-input-other {
display: inline-block;
.col-sm-9 {
display: inline-block;
}
}
}

View file

@ -93,6 +93,8 @@
"footer.help": "Help Page",
"footer.scratchFamily": "Scratch Family",
"form.validationRequired": "This field is required",
"login.forgotPassword": "Forgot Password?",
"navigation.signOut": "Sign out",
@ -108,6 +110,7 @@
"registration.choosePasswordStepTitle": "Create a password",
"registration.choosePasswordStepTooltip": "Don't use your name or anything that's easy for someone else to guess.",
"registration.classroomApiGeneralError": "Sorry, we could not find the registration information for this class",
"registration.generalError": "Sorry, an unexpected error occurred.",
"registration.classroomInviteExistingStudentStepDescription": "you have been invited to join the class:",
"registration.classroomInviteNewStudentStepDescription": "has invited you to join the class:",
"registration.confirmYourEmail": "Confirm Your Email",

24
src/redux/navigation.js Normal file
View file

@ -0,0 +1,24 @@
var keyMirror = require('keymirror');
var Types = keyMirror({
SET_SEARCH_TERM: null
});
module.exports.navigationReducer = function (state, action) {
if(typeof state === 'undefined') {
state = '';
}
switch (action.type) {
case Types.SET_SEARCH_TERM:
return action.searchTerm;
default:
return state;
}
};
module.exports.setSearchTerm = function (searchTerm) {
return {
type: Types.SET_SEARCH_TERM,
searchTerm: searchTerm
};
};

View file

@ -4,12 +4,14 @@ var scheduleReducer = require('./conference-schedule.js').scheduleReducer;
var detailsReducer = require('./conference-details.js').detailsReducer;
var permissionsReducer = require('./permissions.js').permissionsReducer;
var sessionReducer = require('./session.js').sessionReducer;
var navigationReducer = require('./navigation.js').navigationReducer;
var appReducer = combineReducers({
session: sessionReducer,
permissions: permissionsReducer,
conferenceSchedule: scheduleReducer,
conferenceDetails: detailsReducer
conferenceDetails: detailsReducer,
navigation: navigationReducer
});
module.exports = appReducer;

View file

@ -6,6 +6,11 @@
"view": "splash/splash",
"title": "Imagine, Program, Share"
},
{
"name": "splash-redirect",
"pattern": "^///?$",
"redirect": "/"
},
{
"name": "about",
"pattern": "^/about/?$",

View file

@ -137,7 +137,7 @@ var Explore = injectIntl(React.createClass({
<div className='outer'>
<TitleBanner className="masthead">
<div className="inner">
<h1 className="title-banner-h1">Explore</h1>
<h1 className="title-banner-h1"><FormattedMessage id='general.explore' /></h1>
</div>
</TitleBanner>
<Tabs>
@ -156,9 +156,9 @@ var Explore = injectIntl(React.createClass({
<Form className='sort-mode'>
<Select name="sort"
options={[
{value: 'trending', label: 'Trending'},
{value: 'popular', label: 'Popular'},
{value: 'recent', label: 'Recent'}
{value: 'trending', label: <FormattedMessage id='explore.trending' />},
{value: 'popular', label: <FormattedMessage id='explore.popular' />},
{value: 'recent', label: <FormattedMessage id='explore.recent' />}
]}
value={this.props.mode}
onChange={this.changeSortMode}/>

View file

@ -0,0 +1,5 @@
{
"explore.trending": "Trending",
"explore.popular": "Popular",
"explore.recent": "Recent"
}

View file

@ -195,6 +195,8 @@ var Faq = injectIntl(React.createClass({
<dd><FormattedHTMLMessage id='faq.edBody' /></dd>
<dt><FormattedMessage id='faq.dataTitle' /></dt>
<dd><FormattedMessage id='faq.dataBody' /></dd>
<dt><FormattedMessage id='faq.lawComplianceTitle' /></dt>
<dd><FormattedMessage id='faq.lawComplianceBody' /></dd>
</dl>
<i><FormattedHTMLMessage id='faq.schoolsMoreInfo' /></i>
</section>

View file

@ -13,7 +13,7 @@
"faq.makeGameTitle":"How do I make a game or animation with Scratch?",
"faq.makeGameBody":"Check out the <a href= \"/help \">help page</a> to see lots of ways to get started with Scratch. Or just <a href= \"/projects/editor/?tip_bar=getStarted \">dive in</a> to the project editor.",
"faq.requirementsTitle":"What are the system requirements for Scratch?",
"faq.requirementsBody":"To run Scratch 2, you need to be using (1) a Mac, Linux, or Windows computer; (2) a version of <a href= \" \">Adobe Flash Player</a> released on or after June 15, 2016; (3) a relatively recent web browser: one of the latest two versions of <a href=\"http://google.com/chrome/\">Chrome</a>, <a href=\"http://www.mozilla.org/en-US/firefox/new/\">Firefox</a>, <a href=\"https://support.apple.com/downloads/safari\">Safari</a> (Mac or Windows only), <a href=\"https://www.microsoft.com/EN-US/windows/microsoft-edge\">Edge</a> (Windows only), or <a href=\"https://www.microsoft.com/en-us/download/internet-explorer.aspx\">Internet Explorer 10+</a> (Windows only). If your computer doesnt meet these requirements, you can try downloading and installing <a href=\"/scratch_1.4\">Scratch 1.4</a>, which you can still use to share projects to the Scratch 2 website.",
"faq.requirementsBody":"To run Scratch 2, you need to be using (1) a Mac, Linux, or Windows computer; (2) a version of <a href= \" \">Adobe Flash Player</a> released on or after June 15, 2016; (3) a relatively recent web browser: one of the latest two versions of <a href=\"http://google.com/chrome/\">Chrome</a> (Mac, Windows, or Linux), <a href=\"http://www.mozilla.org/en-US/firefox/new/\">Firefox</a> (Mac or Windows only), <a href=\"https://support.apple.com/downloads/safari\">Safari</a> (Mac or Windows only), <a href=\"https://www.microsoft.com/EN-US/windows/microsoft-edge\">Edge</a> (Windows only), or <a href=\"https://www.microsoft.com/en-us/download/internet-explorer.aspx\">Internet Explorer 10+</a> (Windows only). If your computer doesnt meet these requirements, you can try downloading and installing <a href=\"/scratch_1.4\">Scratch 1.4</a>, which you can still use to share projects to the Scratch 2 website. We do not support Chromium.",
"faq.offlineTitle":"Do you have a downloadable version so I can create and view projects offline?",
"faq.offlineBody":"The Scratch 2 offline editor allows you to create Scratch projects without an internet connection. You can download Scratch 2 from the <a href= \"/scratch2download/ \">website</a>. You can also still use <a href = \"/scratch_1.4 \">Scratch 1.4</a>. Note: You can have both Scratch 1.4 and 2 on your computer.",
"faq.uploadOldTitle":"Can I still upload projects created with older versions of Scratch to the website?",
@ -135,6 +135,8 @@
"faq.edTitle":"What is the difference between a Scratch Teacher Account and a ScratchEd Account?",
"faq.edBody":"Scratch Teacher Accounts are special user accounts on Scratch that have access to additional features to facilitate the creation and management of student accounts. ScratchEd Accounts are accounts on the <a href=\"http://scratched.gse.harvard.edu/\">ScratchEd community</a>, a separate website (managed by the Harvard Graduate School of Education) where educators share stories, exchange resources, ask questions, and meet other Scratch educators.",
"faq.dataTitle":"What data does Scratch collect about students?",
"faq.dataBody":"When a student first signs up on Scratch, we ask for basic demographic data including gender, age (birth month and year), country, and an email address for verification. This data is used (in aggregated form) in research studies intended to improve our understanding of how people learn with Scratch. When an educator uses a Scratch Teacher Account to create student accounts in bulk, no student demographic data is required for account setup.",
"faq.dataBody":"When a student first signs up on Scratch, we ask for basic demographic data including gender, age (birth month and year), country, and an email address for verification. This data is used (in aggregated form) in research studies intended to improve our understanding of how people learn with Scratch. When an educator uses a Scratch Teacher Account to create student accounts in bulk, students are not required to provide an email address for account setup.",
"faq.lawComplianceTitle":"Is Scratch 2.0 (online version) compliant with local and federal data privacy laws?",
"faq.lawComplianceBody":"Scratch cares deeply about the privacy of students and of all individuals who use our platform. We have in place physical and electronic procedures to protect the information we collect on the Scratch website. Although we are not in a position to offer contractual guarantees with each entity that uses our free educational product, we are in compliance with all federal laws that are applicable to MIT, a 501(c)(3) organization and the entity that created and maintains Scratch. We encourage you to read the Scratch Privacy Policy for more information.",
"faq.schoolsMoreInfo":"For more more questions about Teacher Accounts, see the <a href=\"/educators/faq\">Teacher Account FAQ</a>"
}

View file

@ -1,6 +1,7 @@
var injectIntl = require('react-intl').injectIntl;
var FormattedMessage = require('react-intl').FormattedMessage;
var React = require('react');
var connect = require('react-redux').connect;
var render = require('../../lib/render.jsx');
var api = require('../../lib/api');
@ -12,6 +13,7 @@ var Input = require('../../components/forms/input.jsx');
var Button = require('../../components/forms/button.jsx');
var Tabs = require('../../components/tabs/tabs.jsx');
var Grid = require('../../components/grid/grid.jsx');
var navigationActions = require('../../redux/navigation.js');
require('./search.scss');
@ -53,6 +55,7 @@ var Search = injectIntl(React.createClass({
},
componentDidMount: function () {
this.getSearchMore();
this.props.dispatch(navigationActions.setSearchTerm(this.props.searchTerm));
},
getSearchMore: function () {
var termText = '';
@ -103,7 +106,7 @@ var Search = injectIntl(React.createClass({
<div className='outer'>
<TitleBanner className="masthead">
<div className="inner">
<h1 className="title-banner-h1">Search</h1>
<h1 className="title-banner-h1"><FormattedMessage id="general.search" /></h1>
<div className="search">
<Form onSubmit={this.onSearchSubmit}>
<Button type="submit" className="btn-search" />
@ -138,4 +141,12 @@ var Search = injectIntl(React.createClass({
}
}));
render(<Page><Search /></Page>, document.getElementById('app'));
var mapStateToProps = function (state) {
return {
navigation: state.searchTerm
};
};
var ConnectedSearch = connect(mapStateToProps)(Search);
render(<Page><ConnectedSearch /></Page>, document.getElementById('app'));

View file

@ -1,115 +0,0 @@
var FormattedMessage = require('react-intl').FormattedMessage;
var injectIntl = require('react-intl').injectIntl;
var MediaQuery = require('react-responsive');
var React = require('react');
var FlexRow = require('../../../components/flex-row/flex-row.jsx');
var TitleBanner = require('../../../components/title-banner/title-banner.jsx');
var TTTModal = require('../../../components/modal/ttt/modal.jsx');
var TTTTile = require('../../../components/ttt-tile/ttt-tile.jsx');
var frameless = require('../../../lib/frameless');
var tiles = require('../../thingstotry/ttt');
require('../../../components/forms/button.scss');
require('./hoc-banner.scss');
var HocBanner = injectIntl(React.createClass({
getInitialState: function () {
return {
currentTile: tiles[1],
TTTModalOpen: false
};
},
showTTTModal: function (tile) {
return this.setState({
currentTile: tile,
TTTModalOpen: true
});
},
hideTTTModal: function () {
return this.setState({TTTModalOpen: false});
},
renderTTTTiles: function () {
var formatMessage = this.props.intl.formatMessage;
var tileObjects = {
nameTile: {
title: formatMessage({id: tiles[0].title}),
description: formatMessage({id: tiles[0].description}),
tutorialLoc: tiles[0].tutorialLoc,
activityLoc: formatMessage({id: tiles[0].activityLoc}),
guideLoc: formatMessage({id: tiles[0].guideLoc}),
thumbUrl: tiles[0].thumbUrl,
bannerUrl: tiles[0].bannerUrl
},
flyTile: {
title: formatMessage({id: tiles[1].title}),
description: formatMessage({id: tiles[1].description}),
tutorialLoc: tiles[1].tutorialLoc,
activityLoc: formatMessage({id: tiles[1].activityLoc}),
guideLoc: formatMessage({id: tiles[1].guideLoc}),
thumbUrl: tiles[1].thumbUrl,
bannerUrl: tiles[1].bannerUrl
},
musicTile: {
title: formatMessage({id: tiles[2].title}),
description: formatMessage({id: tiles[2].description}),
tutorialLoc: tiles[2].tutorialLoc,
activityLoc: formatMessage({id: tiles[2].activityLoc}),
guideLoc: formatMessage({id: tiles[2].guideLoc}),
thumbUrl: tiles[2].thumbUrl,
bannerUrl: tiles[2].bannerUrl
}
};
return [
<TTTTile
key={0}
className="mod-banner"
onGuideClick={this.showTTTModal.bind(this, tileObjects.nameTile)}
{...tileObjects.nameTile}
/>,
<TTTTile
key={1}
className="mod-banner"
onGuideClick={this.showTTTModal.bind(this, tileObjects.flyTile)}
{...tileObjects.flyTile}
/>,
<TTTTile
key={2}
className="mod-banner"
onGuideClick={this.showTTTModal.bind(this, tileObjects.musicTile)}
{...tileObjects.musicTile}
/>
];
},
render: function () {
return (
<TitleBanner className="mod-splash-hoc">
<div className="hoc-banner inner">
<FlexRow className="mod-hoc-banner-header">
<h1 className="hoc-banner-header-h1">
<FormattedMessage id="hoc-banner.header" />
</h1>
<a href="/go" className="button mod-ttt-try-button">
<FormattedMessage id="hoc-banner.ttt" />
</a>
</FlexRow>
<MediaQuery minWidth={frameless.desktop}>
<FlexRow className="mod-hoc-banner-tiles">
{this.renderTTTTiles()}
</FlexRow>
<TTTModal
isOpen={this.state.TTTModalOpen}
onRequestClose={this.hideTTTModal}
{...this.state.currentTile}
/>
</MediaQuery>
</div>
</TitleBanner>
);
}
}));
module.exports = HocBanner;

View file

@ -1,48 +0,0 @@
@import "../../../colors";
@import "../../../frameless";
.title-banner.mod-splash-hoc {
background: url("/images/blocks-pattern.png");
background-color: $ui-blue;
background-repeat: repeat;
background-size: 180px 180px;
}
.flex-row.mod-hoc-banner-header,
.flex-row.mod-hoc-banner-tiles {
justify-content: space-between;
}
.flex-row.mod-hoc-banner-header {
margin-bottom: 1.25rem;
}
.hoc-banner-header-h1 {
color: $type-white;
}
.button.mod-ttt-try-button {
padding: .75rem 2rem;
}
.button.mod-ttt-try-button,
.button.mod-ttt-try-button:hover {
box-shadow: none;
}
.button.mod-ttt-try-button:link,
.button.mod-ttt-try-button:visited,
.button.mod-ttt-try-button:active
.button.mod-ttt-try-button:hover {
color: $type-white;
}
.ttt-tile.mod-banner {
background-color: $background-color;
}
@media only screen and (min-width: $tablet) and (max-width: $desktop - 1) {
.flex-row.mod-hoc-banner-header {
flex-direction: column;
}
}

View file

@ -1,8 +0,0 @@
{
"ttt.MakeItFlyActivityLoc": "/pdfs/cards/FlyCards.pdf",
"ttt.MakeItFlyGuideLoc": "/pdfs/guides/FlyGuide.pdf",
"ttt.AnimateYourNameActivityLoc": "/pdfs/cards/AnimateYourNameCards.pdf",
"ttt.AnimateYourNameGuideLoc": "/pdfs/guides/NameGuide.pdf",
"ttt.MakeMusicActivityLoc": "/pdfs/cards/MusicCards.pdf",
"ttt.MakeMusicGuideLoc": "/pdfs/guides/MusicGuide.pdf"
}

View file

@ -28,23 +28,6 @@
"teacherbanner.classesButton": "My Classes",
"teacherbanner.faqButton": "Teacher Account FAQ",
"hoc-banner.header": "Get Creative with Coding",
"hoc-banner.ttt": "See things to try",
"ttt.tutorialTitle": "Tutorial",
"ttt.tutorialSubtitle": "Find out how to make this project using a step-by-step tutorial in Scratch.",
"ttt.activityTitle": "Activity Cards",
"ttt.activitySubtitle": "Explore new coding ideas using this set of illustrated cards you can print out.",
"ttt.educatorTitle": "Educator Guide",
"ttt.educatorSubtitle": "Use this educator guide to plan and lead a one-hour Scratch workshop.",
"ttt.tryIt": "Try It",
"ttt.open": "Open",
"ttt.download": "Download",
"ttt.MakeItFlyTitle": "Make It Fly",
"ttt.MakeItFlyDescription": "Animate the Scratch Cat, The Powerpuff Girls, or even a taco!",
"ttt.AnimateYourNameTitle": "Animate Your Name",
"ttt.AnimateYourNameDescription": "Animate the letters of your name, initials, or favorite word.",
"ttt.MakeMusicTitle": "Make Music",
"ttt.MakeMusicDescription": "Choose instruments, add sounds, and press keys to play music.",
"hocevent.dismiss": "Dismiss",
"hocevent.title": "Design and share your own character",
"hocevent.studioLink": "See the studio",

View file

@ -14,7 +14,6 @@ var DropdownBanner = require('../../components/dropdown-banner/banner.jsx');
var Box = require('../../components/box/box.jsx');
var Button = require('../../components/forms/button.jsx');
var Carousel = require('../../components/carousel/carousel.jsx');
var HocBanner = require('./hoc-banner/hoc-banner.jsx');
var HocEventRow = require('./hoc-event-row/hoc-event-row.jsx');
var Intro = require('../../components/intro/intro.jsx');
var IframeModal = require('../../components/modal/iframe/modal.jsx');
@ -376,7 +375,6 @@ var Splash = injectIntl(React.createClass({
{this.props.permissions.educator ? [
<TeacherBanner key="teacherbanner" messages={messages} />
] : []}
<HocBanner />
<div key="inner" className="inner mod-splash">
{this.props.session.status === sessionActions.Status.FETCHED ? (
this.props.session.session.user ? [

View file

@ -86,11 +86,18 @@ var StudentCompleteRegistration = intl.injectIntl(React.createClass({
method: 'post',
useCsrf: true,
formData: submittedData
}, function (err, body) {
}, function (err, body, res) {
this.setState({waiting: false});
if (err) return this.setState({registrationError: err});
if (body.success) return this.advanceStep(formData);
this.setState({registrationErrors: body.errors});
this.setState({
registrationErrors:
body.errors || {
__all__:
this.props.intl.formatMessage({id: 'registration.generalError'}) +
' (' + res.statusCode + ')'
}
});
}.bind(this));
},
goToClass: function () {

View file

@ -78,11 +78,15 @@ var StudentRegistration = intl.injectIntl(React.createClass({
classroom_id: this.props.classroomId,
classroom_token: this.props.classroomToken
}
}, function (err, res) {
}, function (err, body, res) {
this.setState({waiting: false});
if (err) return this.setState({registrationError: err});
if (res[0].success) return this.advanceStep(formData);
this.setState({registrationError: res[0].msg});
if (body[0] && body[0].success) return this.advanceStep(formData);
this.setState({
registrationError:
(body[0] && body[0].msg) ||
this.props.intl.formatMessage({id: 'registration.generalError'}) + ' (' + res.statusCode + ')'
});
}.bind(this));
},
goToClass: function () {

View file

@ -39,6 +39,5 @@
"teacherRegistration.howUseScratch": "How do you plan to use Scratch at your organization?",
"teacherRegistration.emailStepTitle": "Email Address",
"teacherRegistration.emailStepDescription": "We will send you a confirmation email that will allow you to access your Scratch Teacher Account.",
"teacherRegistration.validationEmailMatch": "The emails do not match",
"teacherRegistration.validationRequired": "This field is required"
"teacherRegistration.validationEmailMatch": "The emails do not match"
}

View file

@ -4,6 +4,7 @@ var React = require('react');
var render = require('../../lib/render.jsx');
var api = require('../../lib/api');
var intl = require('../../lib/intl.jsx');
var sessionActions = require('../../redux/session.js');
var Deck = require('../../components/deck/deck.jsx');
@ -13,7 +14,7 @@ var Steps = require('../../components/registration/steps.jsx');
require('./teacherregistration.scss');
var TeacherRegistration = React.createClass({
var TeacherRegistration = intl.injectIntl(React.createClass({
type: 'TeacherRegistration',
getInitialState: function () {
return {
@ -66,16 +67,19 @@ var TeacherRegistration = React.createClass({
address_zip: this.state.formData.address.zip,
how_use_scratch: this.state.formData.useScratch
}
}, function (err, res) {
}, function (err, body, res) {
this.setState({waiting: false});
if (err) return this.setState({registrationError: err});
if (res[0].success) {
if (body[0] && body[0].success) {
this.props.dispatch(sessionActions.refreshSession());
return this.advanceStep(formData);
}
this.setState({registrationError: res[0].msg});
this.setState({
registrationError:
(body[0] && body[0].msg) ||
this.props.intl.formatMessage({id: 'registration.generalError'}) + ' (' + res.statusCode + ')'
});
}.bind(this));
},
render: function () {
var permissions = this.props.session.permissions || {};
@ -118,7 +122,7 @@ var TeacherRegistration = React.createClass({
</Deck>
);
}
});
}));
var mapStateToProps = function (state) {
return {

View file

@ -58,6 +58,10 @@ var TeacherFaq = injectIntl(React.createClass({
<dd><FormattedHTMLMessage id='teacherfaq.studentMultipleBody' /></dd>
<dt><FormattedMessage id='teacherfaq.studentDiscussTitle' /></dt>
<dd><FormattedHTMLMessage id='teacherfaq.studentDiscussBody' /></dd>
<dt><FormattedMessage id='teacherfaq.studentDataTitle' /></dt>
<dd><FormattedMessage id='teacherfaq.studentDataBody' /></dd>
<dt><FormattedMessage id='teacherfaq.studentPrivacyLawsTitle' /></dt>
<dd><FormattedMessage id='teacherfaq.studentPrivacyLawsBody' /></dd>
</dl>
</section>
<section id="community">

View file

@ -34,6 +34,10 @@
"teacherfaq.studentMultipleBody": "A student can only be a part of one class. However, we are looking into adding this functionality in later versions.",
"teacherfaq.studentDiscussTitle": "Is there a space to discuss Teacher Accounts with other teachers?",
"teacherfaq.studentDiscussBody": "Yes, you can engage in discussions with other teachers at <a href=\"http://scratched.gse.harvard.edu/\">ScratchEd</a>, an online community for Scratch educators. Check out their forums to join conversations about a <a href=\"http://scratched.gse.harvard.edu/discussions\">number of topics</a>, including but not limited to Teacher Accounts. ScratchEd is developed and supported by the Harvard Graduate School of Education.",
"teacherfaq.studentDataTitle": "What data does Scratch collect about students?",
"teacherfaq.studentDataBody": "When a student first signs up on Scratch, we ask for basic demographic data including gender, age (birth month and year), country, and an email address for verification. This data is used (in aggregated form) in research studies intended to improve our understanding of how people learn with Scratch. When an educator uses a Scratch Teacher Account to create student accounts in bulk, students are not required to provide an email address for account setup.",
"teacherfaq.studentPrivacyLawsTitle": "Is Scratch 2.0 (online version) compliant with local and federal data privacy laws?",
"teacherfaq.studentPrivacyLawsBody": "Scratch cares deeply about the privacy of students and of all individuals who use our platform. We have in place physical and electronic procedures to protect the information we collect on the Scratch website. Although we are not in a position to offer contractual guarantees with each entity that uses our free educational product, we are in compliance with all federal laws that are applicable to MIT, a 501(c)(3) organization and the entity that created and maintains Scratch. We encourage you to read the Scratch Privacy Policy for more information.",
"teacherfaq.commTitle": "Community",
"teacherfaq.commHiddenTitle": "Can I create a hidden class?",