Skip to content

Commit

Permalink
Merge pull request #6751 from guardian/confirm-email-pattern
Browse files Browse the repository at this point in the history
Confirm email - use pattern validation
  • Loading branch information
andrewHEguardian authored Feb 3, 2025
2 parents d2c8177 + c77810f commit a214d2d
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 5 deletions.
3 changes: 2 additions & 1 deletion support-e2e/tests/test/checkout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ export const testCheckout = (testDetails: TestDetails) => {
context,
baseURL,
}) => {
const url = `/${internationalisationId.toLowerCase()}/checkout?product=${product}&ratePlan=${ratePlan}`;
// Temporary opt out of this test
const url = `/${internationalisationId.toLowerCase()}/checkout?product=${product}&ratePlan=${ratePlan}#ab-confirmEmail=control`;
const page = await context.newPage();
await setupPage(page, context, baseURL, url);

Expand Down
21 changes: 21 additions & 0 deletions support-frontend/assets/helpers/abTests/abtestDefinitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,25 @@ export const tests: Tests = {
targetPage: pageUrlRegexes.contributions.allLandingPagesAndThankyouPages,
excludeContributionsOnlyCountries: true,
},
confirmEmail: {
variants: [
{
id: 'control',
},
{
id: 'variant',
},
],
audiences: {
ALL: {
offset: 0,
size: 1,
},
},
isActive: true,
referrerControlled: false, // ab-test name not needed to be in paramURL
seed: 5,
targetPage: pageUrlRegexes.contributions.genericCheckoutOnly,
excludeContributionsOnlyCountries: false,
},
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { TextInput } from '@guardian/source/react-components';
import escapeStringRegexp from 'escape-string-regexp';
import { useState } from 'react';
import {
doesNotContainExtendedEmojiOrLeadingSpace,
Expand All @@ -14,6 +15,9 @@ type PersonalDetailsFieldsProps = {
email: string;
setEmail: (value: string) => void;
isEmailAddressReadOnly: boolean;
requireConfirmedEmail: boolean;
confirmedEmail: string;
setConfirmedEmail: (value: string) => void;
};

export function PersonalDetailsFields({
Expand All @@ -25,10 +29,14 @@ export function PersonalDetailsFields({
email,
setEmail,
isEmailAddressReadOnly,
requireConfirmedEmail,
confirmedEmail,
setConfirmedEmail,
}: PersonalDetailsFieldsProps) {
const [firstNameError, setFirstNameError] = useState<string>();
const [lastNameError, setLastNameError] = useState<string>();
const [emailError, setEmailError] = useState<string>();
const [confirmedEmailError, setConfirmedEmailError] = useState<string>();

return (
<>
Expand Down Expand Up @@ -66,6 +74,44 @@ export function PersonalDetailsFields({
}}
/>
</div>
{requireConfirmedEmail && !isEmailAddressReadOnly && (
<div>
<TextInput
id="confirm-email"
data-qm-masking="blocklist"
label="Confirm email address"
value={confirmedEmail}
type="email"
autoComplete="email"
onChange={(event) => {
setConfirmedEmail(event.currentTarget.value);
}}
onBlur={(event) => {
event.target.checkValidity();
}}
name="confirm-email"
required
maxLength={80}
error={confirmedEmailError}
pattern={escapeStringRegexp(email)}
onInvalid={(event) => {
preventDefaultValidityMessage(event.currentTarget);
const validityState = event.currentTarget.validity;
if (validityState.valid) {
setConfirmedEmailError(undefined);
} else {
if (validityState.valueMissing) {
setConfirmedEmailError('Please confirm your email address.');
} else if (validityState.patternMismatch) {
setConfirmedEmailError('The email addresses do not match.');
} else {
setConfirmedEmailError('Please enter a valid email address.');
}
}
}}
/>
</div>
)}
{children}
<div>
<TextInput
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ export function CheckoutComponent({
abParticipations.newspaperArchiveBenefit ?? '',
);

const inConfirmEmailVariant = abParticipations.confirmEmail === 'variant';

const productDescription = showNewspaperArchiveBenefit
? productCatalogDescriptionNewBenefits(countryGroupId)[productKey]
: productCatalogDescription[productKey];
Expand Down Expand Up @@ -381,6 +383,7 @@ export function CheckoutComponent({
const [firstName, setFirstName] = useState(user?.firstName ?? '');
const [lastName, setLastName] = useState(user?.lastName ?? '');
const [email, setEmail] = useState(user?.email ?? '');
const [confirmedEmail, setConfirmedEmail] = useState('');

/** Delivery and billing addresses */
const [deliveryPostcode, setDeliveryPostcode] = useState('');
Expand Down Expand Up @@ -438,6 +441,7 @@ export function CheckoutComponent({

const formOnSubmit = async (formData: FormData) => {
setIsProcessingPayment(true);

/**
* The validation for this is currently happening on the client side form validation
* So we'll assume strings are not null.
Expand Down Expand Up @@ -571,10 +575,6 @@ export function CheckoutComponent({
labels: ['generic-checkout'],
};

if (stripeExpressCheckoutPaymentType === 'link') {
referrerAcquisitionData.labels.push('express-checkout-link');
}

if (paymentMethod && paymentFields) {
/** TODO
* - add debugInfo
Expand Down Expand Up @@ -879,6 +879,8 @@ export function CheckoutComponent({

event.billingDetails?.email &&
setEmail(event.billingDetails.email);
event.billingDetails?.email &&
setConfirmedEmail(event.billingDetails.email);

setPaymentMethod('StripeExpressCheckoutElement');
setStripeExpressCheckoutPaymentType(
Expand Down Expand Up @@ -942,6 +944,11 @@ export function CheckoutComponent({
setLastName={(lastName) => setLastName(lastName)}
email={email}
setEmail={(email) => setEmail(email)}
requireConfirmedEmail={inConfirmEmailVariant}
confirmedEmail={confirmedEmail}
setConfirmedEmail={(confirmedEmail) =>
setConfirmedEmail(confirmedEmail)
}
>
<Signout isSignedIn={isSignedIn} />
</PersonalDetailsFields>
Expand Down
1 change: 1 addition & 0 deletions support-frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
"@types/uuid": "^9.0.2",
"classnames": "^2.5.1",
"dompurify": "^3.2.0",
"escape-string-regexp": "5.0.0",
"framer-motion": "^1.11.1",
"lodash.debounce": "^4.0.6",
"mockdate": "^3.0.5",
Expand Down
5 changes: 5 additions & 0 deletions support-frontend/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5700,6 +5700,11 @@ escape-html@~1.0.3:
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=

[email protected]:
version "5.0.0"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8"
integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==

escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
Expand Down

0 comments on commit a214d2d

Please sign in to comment.