scratch-www/src/components/join-flow/email-step.jsx

172 lines
7.1 KiB
React
Raw Normal View History

const bindAll = require('lodash.bindall');
2019-08-01 15:40:46 -04:00
const classNames = require('classnames');
const React = require('react');
const PropTypes = require('prop-types');
import {Formik} from 'formik';
const {injectIntl, intlShape} = require('react-intl');
const emailValidator = require('email-validator');
const FormattedMessage = require('react-intl').FormattedMessage;
const JoinFlowStep = require('./join-flow-step.jsx');
2019-08-01 15:40:46 -04:00
const FormikInput = require('../../components/formik-forms/formik-input.jsx');
2019-08-16 17:13:24 -04:00
const FormikCheckbox = require('../../components/formik-forms/formik-checkbox.jsx');
require('./join-flow-steps.scss');
class EmailStep extends React.Component {
constructor (props) {
super(props);
bindAll(this, [
'handleSetEmailRef',
'handleValidSubmit',
'validateEmail',
'validateForm',
'setCaptchaRef',
'captchaSolved',
'onCaptchaLoad',
'onCaptchaError'
]);
}
componentDidMount () {
// automatically start with focus on username field
if (this.emailInput) this.emailInput.focus();
this.grecaptcha = window.grecaptcha;
if (!this.grecaptcha) {
// According to the reCaptcha documentation, this callback shouldn't get
// called unless window.grecaptcha exists. This is just here to be extra defensive.
// TODO: Put up the error screen when we have one.
}
// TODO: Add in error callback for render once we have an error screen.
this.widgetId = this.grecaptcha.render(this.captchaRef,
{
callback: this.captchaSolved,
sitekey: process.env.RECAPTCHA_SITE_KEY
},
true);
}
handleSetEmailRef (emailInputRef) {
this.emailInput = emailInputRef;
}
2019-08-16 16:22:33 -04:00
validateEmail (email) {
if (!email) return this.props.intl.formatMessage({id: 'general.required'});
2019-08-08 00:22:15 -04:00
const isValidLocally = emailValidator.validate(email);
if (isValidLocally) {
2019-08-01 15:40:46 -04:00
return null; // TODO: validate email address remotely
}
return this.props.intl.formatMessage({id: 'registration.validationEmailInvalid'});
}
validateForm () {
return {};
}
handleValidSubmit (formData, formikBag) {
this.formData = formData;
this.formikBag = formikBag;
// Change set submitting to false so that if the user clicks out of
// the captcha, the button is clickable again (instead of a disabled button with a spinner).
this.formikBag.setSubmitting(false);
this.grecaptcha.execute(this.widgetId);
}
captchaSolved (token) {
// Now thatcaptcha is done, we can tell Formik we're submitting.
this.formikBag.setSubmitting(true);
this.formData['g-recaptcha-response'] = token;
this.props.onNextStep(this.formData);
}
setCaptchaRef (ref) {
this.captchaRef = ref;
}
render () {
return (
<Formik
initialValues={{
email: '',
subscribe: false
}}
validate={this.validateForm}
validateOnBlur={false}
validateOnChange={false}
onSubmit={this.handleValidSubmit}
>
{props => {
const {
2019-08-01 15:40:46 -04:00
errors,
handleSubmit,
2019-08-01 15:40:46 -04:00
isSubmitting,
2019-08-16 16:22:33 -04:00
setFieldError,
2019-08-01 15:40:46 -04:00
validateField
} = props;
return (
<JoinFlowStep
description={this.props.intl.formatMessage({id: 'registration.emailStepDescription'})}
footerContent={(
<FormattedMessage
id="registration.acceptTermsOfUse"
values={{
touLink: (
<a
className="join-flow-link"
href="/terms_of_use"
target="_blank"
>
<FormattedMessage id="general.termsOfUse" />
</a>
)
}}
/>
)}
2019-08-16 15:05:15 -04:00
headerImgSrc="/images/join-flow/email-header.png"
2019-08-17 00:52:52 -04:00
innerClassName="join-flow-inner-email-step"
nextButton={this.props.intl.formatMessage({id: 'registration.createAccount'})}
title={this.props.intl.formatMessage({id: 'registration.emailStepTitle'})}
waiting={isSubmitting}
onSubmit={handleSubmit}
2019-08-01 15:40:46 -04:00
>
<FormikInput
className={classNames(
'join-flow-input',
'join-flow-input-tall',
{fail: errors.email}
)}
error={errors.email}
id="email"
name="email"
2019-08-08 11:19:18 -04:00
placeholder={this.props.intl.formatMessage({id: 'general.emailAddress'})}
2019-08-16 16:22:33 -04:00
validate={this.validateEmail}
2019-08-01 15:40:46 -04:00
validationClassName="validation-full-width-input"
2019-08-16 16:22:33 -04:00
/* eslint-disable react/jsx-no-bind */
onBlur={() => validateField('email')}
onFocus={() => setFieldError('email', null)}
/* eslint-enable react/jsx-no-bind */
onSetRef={this.handleSetEmailRef}
2019-08-01 15:40:46 -04:00
/>
2019-08-16 17:13:24 -04:00
<div className="join-flow-email-checkbox-row">
<FormikCheckbox
id="subscribeCheckbox"
label={this.props.intl.formatMessage({id: 'registration.receiveEmails'})}
name="subscribe"
/>
</div>
<div
className="g-recaptcha"
data-badge="bottomright"
data-sitekey={process.env.RECAPTCHA_SITE_KEY}
data-size="invisible"
ref={this.setCaptchaRef}
/>
2019-08-01 15:40:46 -04:00
</JoinFlowStep>
);
}}
</Formik>
);
}
}
EmailStep.propTypes = {
intl: intlShape,
onNextStep: PropTypes.func
};
module.exports = injectIntl(EmailStep);