Split sign up email messaging based on if user is under 13

This commit is contained in:
Georgi Angelov 2024-08-07 15:19:28 +03:00
parent 14132591e8
commit 0fb18c4650
4 changed files with 56 additions and 10 deletions

View file

@ -39,7 +39,7 @@ class EmailStep extends React.Component {
if (this.props.sendAnalytics) {
this.props.sendAnalytics('join-email');
}
// automatically start with focus on username field
// automatically start with focus on email field
if (this.emailInput) this.emailInput.focus();
}
handleSetEmailRef (emailInputRef) {
@ -48,7 +48,7 @@ class EmailStep extends React.Component {
handleCaptchaLoad () {
this.setState({captchaIsLoading: false});
}
// simple function to memoize remote requests for usernames
// simple function to memoize remote requests for emails
validateEmailRemotelyWithCache (email) {
if (Object.prototype.hasOwnProperty.call(this.emailRemoteCache, email)) {
return Promise.resolve(this.emailRemoteCache[email]);
@ -89,7 +89,7 @@ class EmailStep extends React.Component {
this.captchaRef.executeCaptcha();
}
handleCaptchaSolved (token) {
// Now thatcaptcha is done, we can tell Formik we're submitting.
// Now that captcha is done, we can tell Formik we're submitting.
this.formikBag.setSubmitting(true);
this.formData['g-recaptcha-response'] = token;
this.props.onNextStep(this.formData);
@ -98,6 +98,14 @@ class EmailStep extends React.Component {
this.captchaRef = ref;
}
render () {
const title = this.props.under13 ?
this.props.intl.formatMessage({id: 'registration.under13.emailStepTitle'}) :
this.props.intl.formatMessage({id: 'registration.emailStepTitle'});
const description = this.props.under13 ?
this.props.intl.formatMessage({id: 'registration.under13.emailStepDescription'}) :
undefined;
return (
<Formik
initialValues={{
@ -149,8 +157,9 @@ class EmailStep extends React.Component {
headerImgSrc="/images/join-flow/email-header.png"
innerClassName="join-flow-inner-email-step"
nextButton={this.props.intl.formatMessage({id: 'registration.createAccount'})}
title={this.props.intl.formatMessage({id: 'registration.emailStepTitle'})}
title={title}
titleClassName="join-flow-email-title"
description={description}
waiting={this.props.waiting || isSubmitting || this.state.captchaIsLoading}
onSubmit={handleSubmit}
>
@ -205,7 +214,8 @@ EmailStep.propTypes = {
onCaptchaError: PropTypes.func,
onNextStep: PropTypes.func,
sendAnalytics: PropTypes.func.isRequired,
waiting: PropTypes.bool
waiting: PropTypes.bool,
under13: PropTypes.bool
};

View file

@ -61,7 +61,7 @@ class JoinFlow extends React.Component {
formData: defaults({}, newFormData, this.state.formData)
};
this.setState(newState, () => {
this.handleSubmitRegistration(this.state.formData);
this.handleSubmitRegistration(this.state.formData, this.isUnder13());
});
}
getErrorsFromResponse (err, body, res) {
@ -175,7 +175,7 @@ class JoinFlow extends React.Component {
});
});
}
handleSubmitRegistration (formData) {
handleSubmitRegistration (formData, isUnder13) {
this.setState({
registrationError: null, // clear any existing error
waiting: true
@ -191,6 +191,7 @@ class JoinFlow extends React.Component {
'password': formData.password,
'birth_month': formData.birth_month,
'birth_year': formData.birth_year,
'under_13': isUnder13,
'g-recaptcha-response': formData['g-recaptcha-response'],
'gender': formData.gender,
'country': formData.country,
@ -213,7 +214,7 @@ class JoinFlow extends React.Component {
}
handleErrorNext () {
if (this.canTryAgain()) {
this.handleSubmitRegistration(this.state.formData);
this.handleSubmitRegistration(this.state.formData, this.isUnder13());
} else {
this.resetState();
}
@ -229,6 +230,39 @@ class JoinFlow extends React.Component {
});
}
parseDateComponent (fieldValue) {
// The dates are set to either `'null'` (before the BirthDateStep) or a string representation of a number.
if (fieldValue && fieldValue !== 'null') {
return Number(fieldValue);
} else {
return undefined;
}
}
isUnder13 () {
const birthYear = this.parseDateComponent(this.state.formData.birth_year);
const birthMonth = this.parseDateComponent(this.state.formData.birth_month);
if (!birthYear || !birthMonth) {
// We're not yet at the point where the user has specified their birth date
return false;
}
const now = new Date();
const yearDiff = now.getFullYear() - birthYear;
if (yearDiff > 13) {
return false;
} else if (yearDiff < 13) {
return true;
} else {
const currentMonth1Based = now.getMonth() + 1;
const monthsLeftToBirthday = birthMonth - currentMonth1Based;
return monthsLeftToBirthday >= 0;
}
}
render () {
return (
<main>
@ -264,6 +298,7 @@ class JoinFlow extends React.Component {
<EmailStep
sendAnalytics={this.sendAnalytics}
waiting={this.state.waiting}
under13={this.isUnder13()}
onCaptchaError={this.handleCaptchaError}
onNextStep={this.handlePrepareToRegister}
/>

View file

@ -208,6 +208,8 @@
"registration.genderOptionAnother": "Another gender:",
"registration.genderOptionPreferNotToSay": "Prefer not to say",
"registration.emailStepTitle": "What's your email?",
"registration.under13.emailStepTitle": "What's your parent/adult email address?",
"registration.under13.emailStepDescription": "They will need to verify your account through an email link.",
"registration.emailStepInfo": "This will help if you forget your password. This information will not be made public on your account.",
"registration.goToClass": "Go to Class",
"registration.invitedBy": "invited by",
@ -462,7 +464,7 @@
"bluetooth.enableLocationServicesTitle": "Make sure you have location services enabled on Chromebooks or Android tablets",
"bluetooth.enableLocationServicesText": "Bluetooth can be used to provide location data to the app. In addition to granting the Scratch App permission to access location, location must be enabled in your general device settings. Search for 'Location' in your settings, and make sure it is on. On Chromebooks search for 'Location' in the Google Play Store Android preferences.",
"privacyBanner.update": "The Scratch privacy policy has been updated, effective May 25, 2023. You can see the new policy <a>here</a>.",
"renameAccount.accountBlocked": "Account Blocked",
"renameAccount.toRecover": "To recover access to your account, change your username.",
"renameAccount.yourScratchAccount": "Your scratch account has been temporarily blocked because your username appears to contain personal information.",

View file

@ -16,7 +16,6 @@ const Register = () => (
src="/images/logo_sm.png"
/>
</a>
</nav>
<Scratch3Registration
createProjectOnComplete