Add formatting for teacher reg flow

This commit is contained in:
Matthew Taylor 2016-06-23 07:27:43 -04:00
parent 9d6fb63d18
commit 8fb16bf397
28 changed files with 773 additions and 149 deletions

View file

@ -3,5 +3,6 @@
.card {
border-radius: 8px / $em;
box-shadow: 0 0 0 .125rem $active-gray;
background-color: $ui-white;
}

View file

@ -8,8 +8,10 @@ var Deck = React.createClass({
render: function () {
return (
<div className={classNames(['deck', this.props.className])}>
<img src="/images/logo_sm.png" />
{this.props.children}
<div className="inner">
<img src="/images/logo_sm.png" />
{this.props.children}
</div>
</div>
);
}

View file

@ -1,7 +1,148 @@
@import "../../colors";
@import "../../frameless";
@include responsive-layout (".deck", ".slide");
.deck {
min-height: 100vh;
img {
padding: 10px 0;
width: 125px;
}
.step-navigation {
margin-top: 2rem;
}
}
.slide {
max-width: 28.75rem;
h2,
p {
text-align: center;
color: $type-white;
}
.description {
margin-top: 0;
margin-bottom: 2rem;
}
}
.card {
margin: 0 auto;
width: 23.75rem;
&,
h2,
p {
color: $type-gray;
}
}
.step-navigation {
text-align: center;
}
.form {
padding: 3rem 4rem;
.form-group {
margin-bottom: 2rem;
&.has-error {
.input {
border: 1px solid $ui-orange;
}
}
}
.button {
margin: 0 0 -3rem -4rem;
border-radius: .5rem;
box-shadow: none;
width: 23.75rem;
height: 4rem;
&.card-button {
display: block;
border-top-left-radius: 0;
border-top-right-radius: 0;
background-color: $ui-aqua;
}
&:hover {
box-shadow: none;
}
}
}
.input {
width: $cols5;
}
.help-block {
$arrow-border-width: 1rem;
display: block;
position: absolute;
margin-left: $arrow-border-width;
border: 1px solid $active-gray;
border-radius: 5px;
background-color: $ui-orange;
padding: 1rem;
max-width: 18.75rem;
min-height: 1rem;
max-height: 3rem;
overflow: visible;
color: $type-white;
&:before {
display: block;
position: absolute;
top: 1rem;
left: -$arrow-border-width / 2;
transform: rotate(45deg);
border-bottom: 1px solid $active-gray;
border-left: 1px solid $active-gray;
border-radius: 5px;
background-color: $ui-orange;
width: $arrow-border-width;
height: $arrow-border-width;
content: "";
}
}
.radio {
width: 50%;
line-height: 3rem;
input {
margin-right: 1rem;
}
}
@media only screen and (max-width: $tablet - 1) {
.input {
width: 90%;
}
}
@media only screen and (max-width: $desktop - 1) {
.help-block {
position: relative;
transform: none;
margin: inherit;
width: 100%;
height: inherit;
&:before {
display: none;
}
}
}

View file

@ -12,7 +12,28 @@
justify-content: center;
}
&.uneven {
align-items: flex-start;
.short {
width: $cols3;
}
.long {
width: $cols8;
text-align: left;
}
}
@media only screen and (max-width: $tablet - 1) {
flex-direction: column;
&.uneven {
.short,
.long {
margin: auto;
width: 90%;
}
}
}
}

View file

@ -0,0 +1,28 @@
var classNames = require('classnames');
var React = require('react');
require('./charcount.scss');
var CharCount = React.createClass({
type: 'CharCount',
getDefaultProps: function () {
return {
maxCharacters: 0,
currentCharacters: 0
};
},
render: function () {
var classes = classNames(
'char-count',
this.props.className,
{overmax: (this.props.currentCharacters > this.props.maxCharacters)}
);
return (
<p className={classes}>
({this.props.currentCharacters}/{this.props.maxCharacters})
</p>
);
}
});
module.exports = CharCount;

View file

@ -0,0 +1,11 @@
@import "../../colors";
p {
&.char-count {
color: $active-dark-gray;
&.overmax {
color: $ui-orange;
}
}
}

View file

@ -5,6 +5,7 @@ var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC;
var inputHOC = require('./input-hoc.jsx');
require('./row.scss');
require('./checkbox-group.scss');
var CheckboxGroup = React.createClass({
type: 'CheckboxGroup',
@ -14,7 +15,9 @@ var CheckboxGroup = React.createClass({
this.props.className
);
return (
<FRCCheckboxGroup {... this.props} className={classes} />
<div className={classes}>
<FRCCheckboxGroup {... this.props} className={classes} />
</div>
);
}
});

View file

@ -0,0 +1,9 @@
.checkbox-group {
.col-sm-9 {
flex-flow: column wrap;
.checkbox {
margin: 16px 0;
}
}
}

View file

@ -5,6 +5,7 @@ var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC;
var inputHOC = require('./input-hoc.jsx');
require('./row.scss');
require('./checkbox.scss');
var Checkbox = React.createClass({
type: 'Checkbox',
@ -14,7 +15,9 @@ var Checkbox = React.createClass({
this.props.className
);
return (
<FRCCheckbox {... this.props} rowClassName={classes} />
<div className={classes}>
<FRCCheckbox {... this.props} />
</div>
);
}
});

View file

@ -0,0 +1,29 @@
@import "../../colors";
@import "../../frameless";
input {
&[type=checkbox] {
display: block;
float: left;
margin-right: 1rem;
border: 1px solid $active-gray;
border-radius: 3px;
width: 1.25rem;
height: 1.25rem;
appearance: none;
&:checked,
&:focus {
outline: none;
}
&:checked {
background-color: $ui-blue;
&:after {
color: $type-white;
content: "\2714";
}
}
}
}

View file

@ -12,14 +12,33 @@ var Input = React.createClass({
getDefaultProps: function () {
return {};
},
getInitialState: function () {
return {
status: ''
};
},
onValid: function () {
this.setState({
status: 'pass'
});
},
onInvalid: function () {
this.setState({
status: 'fail'
});
},
render: function () {
var classes = classNames(
'input',
this.state.status,
this.props.className
);
return (this.props.type === 'submit' || this.props.noformsy ?
<input {... this.props} className={classes} /> :
<FRCInput {... this.props} className={classes} />
<FRCInput {... this.props}
className={classes}
onValid={this.onValid}
onInvalid={this.onInvalid} />
);
}
});

View file

@ -1,34 +1,36 @@
@import "../../colors";
@import "../../frameless";
$base-bg: $ui-white;
$focus-bg: lighten($ui-blue, 35%);
$fail-bg: lighten($ui-orange, 35%);
$base-bg: $ui-light-gray;
$pass-bg: lighten($ui-aqua, 35%);
.input {
transition: all 1s ease;
margin: .5em 0;
transition: all .5s ease;
margin: .8rem 0;
border: 1px solid $active-gray;
border-radius: 5px;
background-color: $base-bg;
padding: .75em 1em;
padding: 0 1rem;
height: 3rem;
color: $type-gray;
font-size: .8rem;
font-size: .875rem;
&:focus {
transition: all 1s ease;
transition: all .5s ease;
outline: none;
border: 1px solid $active-dark-gray;
background-color: $focus-bg;
border: 1px solid $ui-blue;
}
&.fail {
border: 1px solid $active-dark-gray;
background-color: $fail-bg;
border: 1px solid $ui-orange;
}
&.pass {
border: 1px solid $active-dark-gray;
background-color: $pass-bg;
}
label {
font-weight: 500;
}
}

View file

@ -12,6 +12,7 @@ var inputHOC = require('./input-hoc.jsx');
var allIso2 = allCountries.map(function (country) {return country.iso2;});
require('./row.scss');
require('./phone-input.scss');
var PhoneInput = React.createClass({
displayName: 'PhoneInput',

View file

@ -0,0 +1,42 @@
@import "../../colors";
.input-group {
margin: .8rem 0;
width: 100%;
}
.react-tel-input {
width: 100%;
input {
&[type=tel] {
background-color: $ui-light-gray;
height: 3rem;
&:focus {
outline: none;
}
}
}
.flag-dropdown {
background-color: $ui-light-gray;
height: 3rem;
.selected-flag {
background-color: $ui-light-gray;
height: 100%;
&:hover,
&:focus,
&:active {
background-color: $active-gray;
}
}
.country-list {
top: 3rem;
background-color: $ui-light-gray;
}
}
}

View file

@ -5,6 +5,7 @@ var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC;
var inputHOC = require('./input-hoc.jsx');
require('./row.scss');
require('./radio-group.scss');
var RadioGroup = React.createClass({
type: 'RadioGroup',

View file

@ -0,0 +1,36 @@
@import "../../colors";
.col-sm-9 {
display: flex;
flex-flow: row wrap;
input {
&[type="radio"] {
margin-top: 1px;
border: 1px solid $active-gray;
border-radius: .8rem;
width: .8rem;
height: .8rem;
appearance: none;
&:checked,
&:focus {
outline: none;
}
&:checked {
background-color: $ui-blue;
&:after {
display: block;
transform: translate(.25rem, .25rem);
border-radius: .2rem;
background-color: $ui-white;
width: .2rem;
height: .2rem;
content: "";
}
}
}
}
}

View file

@ -23,7 +23,9 @@ var Select = React.createClass({
props = defaults({}, this.props, {value: this.props.options[0].value});
}
return (
<FRCSelect {... props} className={classes} />
<div className={classes}>
<FRCSelect {... props} />
</div>
);
}
});

View file

@ -1,9 +1,30 @@
@import "../../colors";
@import "../../frameless";
.select {
background-color: $ui-white;
width: 220px;
height: 28px;
line-height: 28px;
font-size: 1em;
label {
font-weight: 500;
}
}
select {
margin: .8rem 0;
border: 1px solid $active-gray;
border-radius: 5px;
background: $ui-light-gray url("../../../static/images/dropdown.png") no-repeat right center;
background-size: 1rem 1rem;
width: 100%;
height: 3rem;
text-indent: 1rem;
font-size: .875rem;
appearance: none;
&:focus {
outline: none;
}
> option {
background-color: $ui-white;
width: 100%;
}
}

View file

@ -1,19 +1,22 @@
@import "../../colors";
$base-bg: $ui-white;
$focus-bg: lighten($ui-blue, 35%);
$base-bg: $ui-light-gray;
$focus-bg: lighten($ui-light-gray, 35%);
$fail-bg: lighten($ui-orange, 35%);
$pass-bg: lighten($ui-aqua, 35%);
.textarea {
transition: all 1s ease;
margin: .5em 0;
margin: .75rem 0;
border: 1px solid $active-gray;
border-radius: 5px;
background-color: $base-bg;
padding: .75em 1em;
padding: .75rem 1rem;
width: 100%;
min-height: 15rem;
line-height: 1.75em;
color: $type-gray;
font-size: .8rem;
font-size: .875rem;
&:focus {
transition: all 1s ease;

View file

@ -101,29 +101,6 @@
section {
padding: 64px 0;
}
.flex-row {
&.uneven {
align-items: flex-start;
.short {
width: $cols3;
}
.long {
width: $cols8;
text-align: left;
}
@media only screen and (max-width: $tablet - 1) {
.short,
.long {
margin: auto;
width: 90%;
}
}
}
}
}
@media only screen and (max-width: $mobile - 1) {

View file

@ -1,2 +1,11 @@
@import "../../frameless";
.slide {
padding: 10px;
}
@media only screen and (max-width: $tablet - 1) {
.slide {
padding: 0;
}
}

View file

@ -0,0 +1,33 @@
var classNames = require('classnames');
var React = require('react');
require('./tooltip.scss');
var Tooltip = React.createClass({
type: 'Tooltip',
getDefaultProps: function () {
return {
title: '',
tipContent: ''
};
},
render: function () {
var classes = classNames(
'tooltip',
this.props.className,
{overmax: (this.props.currentCharacters > this.props.maxCharacters)}
);
return (
<span className={classes}>
<span className="tip">
{this.props.title}
</span>
<span className="expand">
{this.props.tipContent}
</span>
</span>
);
}
});
module.exports = Tooltip;

View file

@ -0,0 +1,76 @@
@import "../../colors";
@import "../../frameless";
.tooltip {
.tip {
display: inline-block;
margin: 0 5px;
border-radius: $font-size;
background-color: $ui-blue;
padding: 0 ($font-size / 2);
color: $type-white;
}
.expand {
$arrow-border-width: 1rem;
position: absolute;
transform: translate(-2.75rem, 2rem);
visibility: hidden;
margin-top: $arrow-border-width;
border-radius: 5px;
background-color: $ui-blue;
padding: 1rem;
width: 13.75rem;
text-align: left;
color: $type-white;
&:before {
display: block;
position: absolute;
top: -$arrow-border-width / 2;
left: $arrow-border-width;
transform: rotate(45deg);
border-bottom: 5px solid $ui-blue;
border-left: 5px solid $ui-blue;
border-radius: 5px;
background-color: $ui-blue;
width: $arrow-border-width;
height: $arrow-border-width;
content: "";
}
}
&:hover {
.expand {
visibility: visible;
}
}
}
@media only screen and (max-width: $desktop - 1) {
.tooltip {
display: block;
.expand {
display: none;
position: relative;
clear: both;
transform: none;
&:before {
display: none;
}
}
&:hover {
.expand {
display: block;
margin: 5px auto;
}
}
}
}

View file

@ -83,7 +83,8 @@ p {
}
}
b {
b,
strong {
font-weight: 500;
}

View file

@ -1,7 +1,7 @@
{
"teacherRegistration.usernameStepDescription": "Fill in the following forms to request an account. The approval process may take up to 24 hours.",
"teacherRegistration.usernameStepTitle": "Request a Teacher Account",
"teacherRegistration.validationUsernameRegexp": "Your username may only contain characters and -",
"teacherRegistration.validationUsernameRegexp": "Your username may only contain characters and \"-\"",
"teacherRegistration.validationUsernameMinLength": "Usernames must be at least 3 characters",
"teacherRegistration.validationUsernameMaxLength": "Usernames must be at most 20 characters",
"teacherRegistration.validationPasswordLength": "Passwords must be at least six characters",
@ -12,7 +12,8 @@
"teacherRegistration.personalStepTitle": "Personal Information",
"teacherRegistration.personalStepDescription": "Your individual responses will not be displayed publicly, and will be kept confidential and secure",
"teacherRegistration.nameStepTitle": "First &amp; Last Name",
"teacherRegistration.nameStepDescription": "Your name will not be displayed publicly, and will be kept confidential and secure",
"teacherRegistration.nameStepDescription": "Your name will not be displayed publicly, and will be kept confidential and secure.",
"teacherRegistration.nameStepTooltip": "This information is used for verification and to aggregate usage statistics.",
"teacherRegistration.firstName": "First Name",
"teacherRegistration.lastName": "Last Name",
"teacherRegistration.phoneStepTitle": "Phone Number",
@ -34,11 +35,12 @@
"teacherRegistration.orgChoiceMuseum": "Museum",
"teacherRegistration.orgChoiceLibrary": "Library",
"teacherRegistration.orgChoiceCamp": "Camp",
"teacherRegistration.orgChoiceOther": "Other",
"teacherRegistration.orgChoiceOther": " ",
"teacherRegistration.notRequired": "Not Required",
"teacherRegistration.selectCountry": "select country",
"teacherRegistration.validationAddress": "This doesn't look like a real address",
"teacherRegistration.addressLine1": "Address Line 1",
"teacherRegistration.addressLine2": "Address Line 2",
"teacherRegistration.addressLine2": "Address Line 2 (Optional)",
"teacherRegistration.zipCode": "ZIP",
"teacherRegistration.stateProvince": "State",
"teacherRegistration.city": "City",
@ -46,6 +48,7 @@
"teacherRegistration.addressStepDescription": "Your information will not be displayed publicly, and will be kept confidential and secure.",
"teacherRegistration.useScratchStepTitle": "How you plan to use Scratch",
"teacherRegistration.useScratchStepDescription": "Tell us a little about how you plan to use Scratch. Why do we ask for this information",
"teacherRegistration.useScratchMaxLength": "Description must be at most 300 characters",
"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.",

View file

@ -5,11 +5,12 @@ var countryData = require('../../lib/country-data');
var intl = require('../../lib/intl.jsx');
var log = require('../../lib/log');
var smartyStreets = require('../../lib/smarty-streets');
var urlParams = require('../../lib/url-params');
var Button = require('../../components/forms/button.jsx');
var Card = require('../../components/card/card.jsx');
var CharCount = require('../../components/forms/charcount.jsx');
var Checkbox = require('../../components/forms/checkbox.jsx');
var FlexRow = require('../../components/flex-row/flex-row.jsx');
var CheckboxGroup = require('../../components/forms/checkbox-group.jsx');
var Form = require('../../components/forms/form.jsx');
var Input = require('../../components/forms/input.jsx');
@ -20,6 +21,7 @@ var Slide = require('../../components/slide/slide.jsx');
var Spinner = require('../../components/spinner/spinner.jsx');
var StepNavigation = require('../../components/stepnavigation/stepnavigation.jsx');
var TextArea = require('../../components/forms/textarea.jsx');
var Tooltip = require('../../components/tooltip/tooltip.jsx');
var DEFAULT_COUNTRY = 'us';
@ -52,7 +54,8 @@ module.exports = {
getInitialState: function () {
return {
showPassword: false,
waiting: false
waiting: false,
validUsername: ''
};
},
onChangeShowPassword: function (field, value) {
@ -70,6 +73,9 @@ module.exports = {
res = res[0];
switch (res.msg) {
case 'valid username':
this.setState({
validUsername: 'pass'
});
return this.props.onNextStep(formData);
case 'username exists':
return invalidate({
@ -90,14 +96,15 @@ module.exports = {
render: function () {
var formatMessage = this.props.intl.formatMessage;
return (
<Slide>
<h1><intl.FormattedMessage id="teacherRegistration.usernameStepTitle" /></h1>
<Slide className="username-step">
<h2><intl.FormattedMessage id="teacherRegistration.usernameStepTitle" /></h2>
<p className="description">
<intl.FormattedMessage id="teacherRegistration.usernameStepDescription" />
</p>
<Card>
<Form onValidSubmit={this.onValidSubmit}>
<Input label={formatMessage({id: 'general.username'})}
className={this.state.validUsername}
type="text"
name="user.username"
validations={{
@ -143,7 +150,7 @@ module.exports = {
help={null}
name="showPassword" />
<NextStepButton waiting={this.props.waiting || this.state.waiting}
text={<intl.FormattedMessage id="teacherRegistration.nextStep" />} />
text={<intl.FormattedMessage id="teacherRegistration.nextStep" />} />
</Form>
</Card>
<StepNavigation steps={this.props.totalSteps - 1} active={this.props.activeStep} />
@ -183,12 +190,14 @@ module.exports = {
render: function () {
var formatMessage = this.props.intl.formatMessage;
return (
<Slide>
<h1>
<Slide className="demographics-step">
<h2>
<intl.FormattedMessage id="teacherRegistration.personalStepTitle" />
</h1>
</h2>
<p className="description">
<intl.FormattedMessage id="teacherRegistration.personalStepDescription" />
<Tooltip title={'?'}
tipContent={formatMessage({id: 'teacherRegistration.nameStepTooltip'})} />
</p>
<Card>
<Form onValidSubmit={this.props.onNextStep}>
@ -205,24 +214,26 @@ module.exports = {
options={[
{value: 'female', label: formatMessage({id: 'general.female'})},
{value: 'male', label: formatMessage({id: 'general.male'})},
{value: 'other', label: formatMessage({id: 'general.other'})}
{value: 'other', label: ''}
]}
required />
<Input name="user.genderOther"
type="text"
disabled={this.state.otherDisabled}
required={!this.state.otherDisabled}
help={null} />
<div className="gender-input">
<Input name="user.genderOther"
type="text"
disabled={this.state.otherDisabled}
required={!this.state.otherDisabled}
help={null} />
</div>
<Select label={formatMessage({id: 'general.country'})}
name="user.country"
options={countryData.countryOptions}
value={this.props.defaultCountry}
required />
<Checkbox className="demographics-checkbox-is-robot"
label="I'm a robot!"
name="user.isRobot" />
<Checkbox className="demographics-checkbox-is-robot"
label="I'm a robot!"
name="user.isRobot" />
<NextStepButton waiting={this.props.waiting}
text={<intl.FormattedMessage id="teacherRegistration.nextStep" />} />
text={<intl.FormattedMessage id="teacherRegistration.nextStep" />} />
</Form>
</Card>
<StepNavigation steps={this.props.totalSteps - 1} active={this.props.activeStep} />
@ -239,12 +250,14 @@ module.exports = {
render: function () {
var formatMessage = this.props.intl.formatMessage;
return (
<Slide>
<h1>
<Slide className="name-step">
<h2>
<intl.FormattedHTMLMessage id="teacherRegistration.nameStepTitle" />
</h1>
</h2>
<p className="description">
<intl.FormattedMessage id="teacherRegistration.nameStepDescription" />
<Tooltip title={'?'}
tipContent={formatMessage({id: 'teacherRegistration.nameStepTooltip'})} />
</p>
<Card>
<Form onValidSubmit={this.props.onNextStep}>
@ -257,7 +270,7 @@ module.exports = {
name="user.name.last"
required />
<NextStepButton waiting={this.props.waiting}
text={<intl.FormattedMessage id="teacherRegistration.nextStep" />} />
text={<intl.FormattedMessage id="teacherRegistration.nextStep" />} />
</Form>
</Card>
<StepNavigation steps={this.props.totalSteps - 1} active={this.props.activeStep} />
@ -275,12 +288,14 @@ module.exports = {
render: function () {
var formatMessage = this.props.intl.formatMessage;
return (
<Slide>
<h1>
<Slide className="phone-step">
<h2>
<intl.FormattedMessage id="teacherRegistration.phoneStepTitle" />
</h1>
</h2>
<p>
<intl.FormattedMessage id="teacherRegistration.phoneStepDescription" />
<Tooltip title={'?'}
tipContent={formatMessage({id: 'teacherRegistration.nameStepTooltip'})} />
</p>
<Card>
<Form onValidSubmit={this.props.onNextStep}>
@ -298,7 +313,7 @@ module.exports = {
isFalse: formatMessage({id: 'teacherRegistration.validationPhoneConsent'})
}} />
<NextStepButton waiting={this.props.waiting}
text={<intl.FormattedMessage id="teacherRegistration.nextStep" />} />
text={<intl.FormattedMessage id="teacherRegistration.nextStep" />} />
</Form>
</Card>
<StepNavigation steps={this.props.totalSteps - 1} active={this.props.activeStep} />
@ -344,12 +359,14 @@ module.exports = {
render: function () {
var formatMessage = this.props.intl.formatMessage;
return (
<Slide>
<h1>
<Slide className="organization-step">
<h2>
<intl.FormattedMessage id="teacherRegistration.orgStepTitle" />
</h1>
</h2>
<p>
<intl.FormattedMessage id="teacherRegistration.orgStepDescription" />
<Tooltip title={'?'}
tipContent={formatMessage({id: 'teacherRegistration.nameStepTooltip'})} />
</p>
<Card>
<Form onValidSubmit={this.props.onNextStep}>
@ -361,20 +378,30 @@ module.exports = {
type="text"
name="organization.title"
required />
<CheckboxGroup label={formatMessage({id: 'teacherRegistration.orgType'})}
help={formatMessage({id: 'teacherRegistration.checkAll'})}
name="organization.type"
value={[]}
options={this.getOrganizationOptions()}
onChange={this.onChooseOrganization}
required />
<Input type="text"
name="organization.other"
disabled={this.state.otherDisabled}
required={!this.state.otherDisabled} />
<Input label={formatMessage({id: 'general.website'})}
type="url"
name="organization.url" />
<div className="organization-type">
<b><intl.FormattedMessage id="teacherRegistration.orgType" /></b>
<p><intl.FormattedMessage id="teacherRegistration.checkAll" /></p>
<CheckboxGroup name="organization.type"
value={[]}
options={this.getOrganizationOptions()}
onChange={this.onChooseOrganization}
required />
</div>
<div className="other-input">
<Input type="text"
name="organization.other"
disabled={this.state.otherDisabled}
required="isFalse"
placeholder={formatMessage({id: 'general.other'})} />
</div>
<div className="url-input">
<b><intl.FormattedMessage id="general.website" /></b>
<p><intl.FormattedMessage id="teacherRegistration.notRequired" /></p>
<Input type="url"
name="organization.url"
required="isFalse"
placeholder={'http://'} />
</div>
<NextStepButton waiting={this.props.waiting}
text={<intl.FormattedMessage id="teacherRegistration.nextStep" />} />
</Form>
@ -449,12 +476,14 @@ module.exports = {
return 0;
}.bind(this));
return (
<Slide>
<h1>
<Slide className="address-step">
<h2>
<intl.FormattedMessage id="teacherRegistration.addressStepTitle" />
</h1>
</h2>
<p className="description">
<intl.FormattedMessage id="teacherRegistration.addressStepDescription" />
<Tooltip title={'?'}
tipContent={formatMessage({id: 'teacherRegistration.nameStepTooltip'})} />
</p>
<Card>
<Form onValidSubmit={this.onValidSubmit}>
@ -469,7 +498,8 @@ module.exports = {
required />
<Input label={formatMessage({id: 'teacherRegistration.addressLine2'})}
type="text"
name="address.line2" />
name="address.line2"
required="isFalse" />
<Input label={formatMessage({id: 'teacherRegistration.city'})}
type="text"
name="address.city"
@ -486,7 +516,7 @@ module.exports = {
name="address.zip"
required />
<NextStepButton waiting={this.props.waiting || this.state.waiting}
text={<intl.FormattedMessage id="teacherRegistration.nextStep" />} />
text={<intl.FormattedMessage id="teacherRegistration.nextStep" />} />
</Form>
</Card>
<StepNavigation steps={this.props.totalSteps - 1} active={this.props.activeStep} />
@ -497,26 +527,50 @@ module.exports = {
UseScratchStep: intl.injectIntl(React.createClass({
getDefaultProps: function () {
return {
waiting: false
waiting: false,
maxCharacters: 300
};
},
getInitialState: function () {
return {
characterCount: 0
};
},
handleTyping: function (name, value) {
this.setState({
characterCount: value.length
});
},
render: function () {
var formatMessage = this.props.intl.formatMessage;
return (
<Slide>
<h1>
<Slide className="usescratch-step">
<h2>
<intl.FormattedMessage id="teacherRegistration.useScratchStepTitle" />
</h1>
</h2>
<p className="description">
<intl.FormattedMessage id="teacherRegistration.useScratchStepDescription" />
<Tooltip title={'?'}
tipContent={formatMessage({id: 'teacherRegistration.nameStepTooltip'})} />
</p>
<Card>
<Form onValidSubmit={this.props.onNextStep}>
<TextArea label={formatMessage({id: 'teacherRegistration.howUseScratch'})}
name="useScratch"
onChange={this.handleTyping}
validations={{
maxLength: this.props.maxCharacters
}}
validationErrors={{
maxLength: formatMessage({
id: 'teacherRegistration.useScratchMaxLength'
})
}}
required />
<CharCount maxCharacters={this.props.maxCharacters}
currentCharacters={this.state.characterCount} />
<NextStepButton waiting={this.props.waiting}
text={<intl.FormattedMessage id="teacherRegistration.nextStep" />} />
text={<intl.FormattedMessage id="teacherRegistration.nextStep" />} />
</Form>
</Card>
<StepNavigation steps={this.props.totalSteps - 1} active={this.props.activeStep} />
@ -556,12 +610,14 @@ module.exports = {
render: function () {
var formatMessage = this.props.intl.formatMessage;
return (
<Slide>
<h1>
<Slide className="email-step">
<h2>
<intl.FormattedMessage id="teacherRegistration.emailStepTitle" />
</h1>
</h2>
<p className="description">
<intl.FormattedMessage id="teacherRegistration.emailStepDescription" />
<Tooltip title={'?'}
tipContent={formatMessage({id: 'teacherRegistration.nameStepTooltip'})} />
</p>
<Card>
<Form onValidSubmit={this.onValidSubmit}>
@ -580,7 +636,7 @@ module.exports = {
}}
required />
<NextStepButton waiting={this.props.waiting}
text={<intl.FormattedMessage id="teacherRegistration.nextStep" />} />
text={<intl.FormattedMessage id="teacherRegistration.nextStep" />} />
</Form>
</Card>
<StepNavigation steps={this.props.totalSteps - 1} active={this.props.activeStep} />
@ -591,28 +647,28 @@ module.exports = {
LastStep: intl.injectIntl(React.createClass({
render: function () {
return (
<Slide>
<h1>
<Slide className="last-step">
<h2>
<intl.FormattedMessage id="teacherRegistration.lastStepTitle" />
</h1>
</h2>
<p className="description">
<intl.FormattedMessage id="teacherRegistration.lastStepDescription" />
</p>
<Card className="confirm">
<h2><intl.FormattedMessage id="teacherRegistration.confirmYourEmail" /></h2>
<h4><intl.FormattedMessage id="teacherRegistration.confirmYourEmail" /></h4>
<p>
<intl.FormattedMessage id="teacherRegistration.confirmYourEmailDescription" /><br />
<strong>{this.props.formData.user && this.props.formData.user.email}</strong>
</p>
</Card>
<Card className="wait">
<h2><intl.FormattedMessage id="teacherRegistration.waitForApproval" /></h2>
<h4><intl.FormattedMessage id="teacherRegistration.waitForApproval" /></h4>
<p>
<intl.FormattedMessage id="teacherRegistration.waitForApprovalDescription" />
</p>
</Card>
<Card className="resources">
<h2><intl.FormattedMessage id="teacherRegistration.checkOutResources" /></h2>
<h4><intl.FormattedMessage id="teacherRegistration.checkOutResources" /></h4>
<p>
<intl.FormattedHTMLMessage id="teacherRegistration.checkOutResourcesDescription" />
</p>
@ -624,8 +680,8 @@ module.exports = {
RegistrationError: intl.injectIntl(React.createClass({
render: function () {
return (
<Slide>
<h1>Something went wrong</h1>
<Slide className="error-step">
<h2>Something went wrong</h2>
<Card>
<h2>There was an error while processing your registration</h2>
<p>

View file

@ -79,7 +79,6 @@ var TeacherRegistration = React.createClass({
<Steps.RegistrationError {... this.state} />
:
<Progression {... this.state}>
<Steps.UsernameStep {... this.state} onNextStep={this.advanceStep} />
<Steps.DemographicsStep {... this.state} onNextStep={this.advanceStep} />
<Steps.NameStep {... this.state} onNextStep={this.advanceStep} />
<Steps.PhoneNumberStep {... this.state} onNextStep={this.advanceStep} />

View file

@ -1,36 +1,131 @@
@import "../../colors";
@import "../../frameless";
@include responsive-layout (".teacher-registration", ".slide");
.teacher-registration {
background-color: $ui-purple;
.slide {
h1,
p {
color: $type-white;
}
}
.card {
&,
h2,
p {
color: $type-gray;
}
}
.card-button {
display: block;
border-top-left-radius: 0;
border-top-right-radius: 0;
background-color: $ui-aqua;
width: 100%;
}
.step-navigation {
text-align: center;
}
.demographics-checkbox-is-robot {
display: none;
}
.gender-input,
.other-input {
float: right;
width: 90%;
}
.gender-input {
margin-top: -5.75rem;
}
.other-input {
margin-top: -5.875rem;
}
.username-step,
.name-step,
.address-step,
.email-step {
.help-block {
transform: translate(15.5rem, -4rem);
}
}
.demographics-step {
.help-block {
transform: translate(14rem, -4rem);
}
}
.phone-step {
.form-group {
margin-bottom: 2rem;
}
input {
&[type=checkbox] {
margin-bottom: 1.25rem;
}
}
.help-block {
margin-top: .7rem;
}
.checkbox-row {
.help-block {
margin-top: 0;
}
}
}
.organization-step {
.help-block {
transform: translate(16rem, -4rem);
}
.organization-type,
.url-input {
p {
margin: .25rem 0;
text-align: left;
color: $ui-dark-gray;
}
}
}
.usescratch-step {
.form {
.form-group {
margin-bottom: 0;
}
}
.help-block {
margin-top: .75rem;
}
p {
&.char-count {
margin-top: 0;
margin-bottom: 1rem;
text-align: right;
}
}
}
.last-step {
&.slide {
max-width: 38.75rem;
}
.card {
margin: 1rem 0;
padding: 1.5rem;
width: initial;
h4,
p {
text-align: left;
}
p {
margin: 0;
}
}
}
}
@media only screen and (max-width: $desktop - 1) {
.teacher-registration {
.username-step,
.demographics-step,
.name-step{
.help-block {
transform: none;
}
}
}
}