2019-07-29 22:29:04 -04:00
|
|
|
const bindAll = require('lodash.bindall');
|
2019-08-01 15:40:46 -04:00
|
|
|
const classNames = require('classnames');
|
2019-07-29 22:29:04 -04:00
|
|
|
const React = require('react');
|
|
|
|
const PropTypes = require('prop-types');
|
|
|
|
import {Formik} from 'formik';
|
|
|
|
const {injectIntl, intlShape} = require('react-intl');
|
2019-08-06 20:22:58 -04:00
|
|
|
const emailValidator = require('email-validator');
|
2019-08-13 12:16:42 -04:00
|
|
|
const FormattedMessage = require('react-intl').FormattedMessage;
|
2019-07-29 22:29:04 -04:00
|
|
|
|
|
|
|
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');
|
2019-07-29 22:29:04 -04:00
|
|
|
|
|
|
|
require('./join-flow-steps.scss');
|
|
|
|
|
|
|
|
class EmailStep extends React.Component {
|
|
|
|
constructor (props) {
|
|
|
|
super(props);
|
|
|
|
bindAll(this, [
|
2019-08-26 16:02:07 -04:00
|
|
|
'handleSetEmailRef',
|
2019-07-29 22:29:04 -04:00
|
|
|
'handleValidSubmit',
|
2019-08-27 15:42:33 -04:00
|
|
|
'validateEmail',
|
2019-08-20 17:05:43 -04:00
|
|
|
'validateForm',
|
|
|
|
'setCaptchaRef',
|
2019-08-27 15:42:33 -04:00
|
|
|
'captchaSolved',
|
|
|
|
'onCaptchaLoad',
|
|
|
|
'onCaptchaError'
|
2019-07-29 22:29:04 -04:00
|
|
|
]);
|
|
|
|
}
|
2019-08-20 17:05:43 -04:00
|
|
|
|
2019-08-26 16:02:07 -04:00
|
|
|
componentDidMount () {
|
|
|
|
// automatically start with focus on username field
|
|
|
|
if (this.emailInput) this.emailInput.focus();
|
2019-08-20 17:05:43 -04:00
|
|
|
this.grecaptcha = window.grecaptcha;
|
|
|
|
if (!this.grecaptcha) {
|
2019-08-27 15:42:33 -04:00
|
|
|
// 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.
|
2019-08-20 17:05:43 -04:00
|
|
|
}
|
2019-08-27 15:42:33 -04:00
|
|
|
// TODO: Add in error callback for render once we have an error screen.
|
2019-08-20 17:05:43 -04:00
|
|
|
this.widgetId = this.grecaptcha.render(this.captchaRef,
|
|
|
|
{
|
|
|
|
callback: this.captchaSolved,
|
2019-08-21 13:59:49 -04:00
|
|
|
sitekey: process.env.RECAPTCHA_SITE_KEY
|
2019-08-20 17:05:43 -04:00
|
|
|
},
|
|
|
|
true);
|
2019-08-26 16:02:07 -04:00
|
|
|
}
|
|
|
|
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'});
|
|
|
|
}
|
2019-07-29 22:29:04 -04:00
|
|
|
validateForm () {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
handleValidSubmit (formData, formikBag) {
|
2019-08-20 17:05:43 -04:00
|
|
|
this.formData = formData;
|
|
|
|
this.formikBag = formikBag;
|
2019-08-27 15:51:48 -04:00
|
|
|
// 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);
|
2019-08-20 17:05:43 -04:00
|
|
|
this.grecaptcha.execute(this.widgetId);
|
|
|
|
}
|
|
|
|
captchaSolved (token) {
|
2019-08-27 15:51:48 -04:00
|
|
|
// Now thatcaptcha is done, we can tell Formik we're submitting.
|
|
|
|
this.formikBag.setSubmitting(true);
|
2019-08-20 17:05:43 -04:00
|
|
|
this.formData['g-recaptcha-response'] = token;
|
|
|
|
this.props.onNextStep(this.formData);
|
|
|
|
}
|
|
|
|
setCaptchaRef (ref) {
|
|
|
|
this.captchaRef = ref;
|
2019-07-29 22:29:04 -04:00
|
|
|
}
|
|
|
|
render () {
|
|
|
|
return (
|
|
|
|
<Formik
|
|
|
|
initialValues={{
|
2019-08-21 08:25:21 -04:00
|
|
|
email: '',
|
|
|
|
subscribe: false
|
2019-07-29 22:29:04 -04:00
|
|
|
}}
|
|
|
|
validate={this.validateForm}
|
|
|
|
validateOnBlur={false}
|
|
|
|
validateOnChange={false}
|
|
|
|
onSubmit={this.handleValidSubmit}
|
|
|
|
>
|
|
|
|
{props => {
|
|
|
|
const {
|
2019-08-01 15:40:46 -04:00
|
|
|
errors,
|
2019-07-29 22:29:04 -04:00
|
|
|
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
|
2019-07-29 22:29:04 -04:00
|
|
|
} = props;
|
|
|
|
return (
|
|
|
|
<JoinFlowStep
|
|
|
|
description={this.props.intl.formatMessage({id: 'registration.emailStepDescription'})}
|
2019-08-13 12:16:42 -04:00
|
|
|
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"
|
2019-08-10 23:18:33 -04:00
|
|
|
nextButton={this.props.intl.formatMessage({id: 'registration.createAccount'})}
|
2019-07-29 22:29:04 -04:00
|
|
|
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 */
|
2019-08-26 16:02:07 -04:00
|
|
|
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>
|
2019-08-20 17:05:43 -04:00
|
|
|
<div
|
|
|
|
className="g-recaptcha"
|
2019-08-20 17:37:52 -04:00
|
|
|
data-badge="bottomright"
|
2019-08-21 13:59:49 -04:00
|
|
|
data-sitekey={process.env.RECAPTCHA_SITE_KEY}
|
2019-08-20 17:05:43 -04:00
|
|
|
data-size="invisible"
|
|
|
|
ref={this.setCaptchaRef}
|
|
|
|
/>
|
2019-08-01 15:40:46 -04:00
|
|
|
</JoinFlowStep>
|
2019-07-29 22:29:04 -04:00
|
|
|
);
|
|
|
|
}}
|
|
|
|
</Formik>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EmailStep.propTypes = {
|
|
|
|
intl: intlShape,
|
|
|
|
onNextStep: PropTypes.func
|
|
|
|
};
|
|
|
|
|
2019-08-06 20:22:58 -04:00
|
|
|
|
2019-07-29 22:29:04 -04:00
|
|
|
module.exports = injectIntl(EmailStep);
|