diff --git a/package.json b/package.json index 583b1648e..e05febcca 100644 --- a/package.json +++ b/package.json @@ -89,6 +89,7 @@ "glob": "5.0.15", "google-libphonenumber": "3.2.3", "html-webpack-plugin": "2.22.0", + "isemail": "3.2.0", "iso-3166-2": "0.4.0", "jest": "^23.6.0", "json-loader": "0.5.2", diff --git a/src/components/formik-forms/formik-input.jsx b/src/components/formik-forms/formik-input.jsx index 8883e4cca..3937a0bd5 100644 --- a/src/components/formik-forms/formik-input.jsx +++ b/src/components/formik-forms/formik-input.jsx @@ -5,6 +5,7 @@ import {Field} from 'formik'; const ValidationMessage = require('../forms/validation-message.jsx'); +require('./input.scss'); require('../forms/input.scss'); require('../forms/row.scss'); diff --git a/src/components/formik-forms/input.scss b/src/components/formik-forms/input.scss new file mode 100644 index 000000000..1ac2a0b7e --- /dev/null +++ b/src/components/formik-forms/input.scss @@ -0,0 +1,7 @@ +@import "../../colors"; +@import "../../frameless"; + +.input::placeholder { + font-style: italic; + color: $type-gray-75percent; +} diff --git a/src/components/join-flow/email-step.jsx b/src/components/join-flow/email-step.jsx index fcfe613a3..3ece5b5a6 100644 --- a/src/components/join-flow/email-step.jsx +++ b/src/components/join-flow/email-step.jsx @@ -1,10 +1,13 @@ const bindAll = require('lodash.bindall'); +const classNames = require('classnames'); const React = require('react'); const PropTypes = require('prop-types'); import {Formik} from 'formik'; const {injectIntl, intlShape} = require('react-intl'); +const isEmail = require('isemail'); const JoinFlowStep = require('./join-flow-step.jsx'); +const FormikInput = require('../../components/formik-forms/formik-input.jsx'); require('./join-flow-steps.scss'); @@ -13,9 +16,18 @@ class EmailStep extends React.Component { super(props); bindAll(this, [ 'handleValidSubmit', + 'validateEmailIfPresent', 'validateForm' ]); } + validateEmailIfPresent (email) { + if (!email) return null; // skip validation if email is blank; null indicates valid + const localResult = isEmail.validate(email); + if (localResult) { + return null; // TODO: validate email address remotely + } + return this.props.intl.formatMessage({id: 'registration.validationEmailInvalid'}); + } validateForm () { return {}; } @@ -35,17 +47,35 @@ class EmailStep extends React.Component { > {props => { const { + errors, handleSubmit, - isSubmitting + isSubmitting, + validateField } = props; return ( + > + validateField('email')} // eslint-disable-line react/jsx-no-bind + /> + ); }} diff --git a/src/components/join-flow/join-flow-step.jsx b/src/components/join-flow/join-flow-step.jsx index f9367210f..de04315e7 100644 --- a/src/components/join-flow/join-flow-step.jsx +++ b/src/components/join-flow/join-flow-step.jsx @@ -13,6 +13,7 @@ const JoinFlowStep = ({ className, description, headerImgSrc, + innerContentClassName, nextButton, onSubmit, title, @@ -29,6 +30,7 @@ const JoinFlowStep = ({ className={classNames( 'join-flow-inner-content', className + innerContentClassName )} > {title && ( @@ -57,6 +59,7 @@ JoinFlowStep.propTypes = { className: PropTypes.string, description: PropTypes.string, headerImgSrc: PropTypes.string, + innerContentClassName: PropTypes.string, nextButton: PropTypes.node, onSubmit: PropTypes.func, title: PropTypes.string, diff --git a/src/components/join-flow/join-flow-steps.scss b/src/components/join-flow/join-flow-steps.scss index 6df450f14..f907e6f0a 100644 --- a/src/components/join-flow/join-flow-steps.scss +++ b/src/components/join-flow/join-flow-steps.scss @@ -13,6 +13,10 @@ } } +.join-flow-input-tall { + height: 3rem; +} + .join-flow-input-title { font-weight: bold; margin-bottom: .5rem; @@ -93,3 +97,7 @@ height: 2rem; margin-left: .5rem; } + +.modal-inner-content-email { + padding-top: 2.9rem; +} diff --git a/src/l10n.json b/src/l10n.json index ed9c73f2f..98c72aad7 100644 --- a/src/l10n.json +++ b/src/l10n.json @@ -196,6 +196,7 @@ "registration.validationUsernameExists": "Sorry, that username already exists", "registration.validationUsernameVulgar": "Hmm, that looks inappropriate", "registration.validationUsernameInvalid": "Invalid username", + "registration.validationEmailInvalid": "Email doesn’t look right. Try another?", "registration.waitForApproval": "Wait for Approval", "registration.waitForApprovalDescription": "You can log into your Scratch Account now, but the features specific to Teachers are not yet available. Your information is being reviewed. Please be patient, the approval process can take up to one day. You will receive an email indicating your account has been upgraded once your account has been approved.", "registration.welcomeStepDescription": "You have successfully set up a Scratch account! You are now a member of the class:",