diff --git a/support-frontend/assets/helpers/forms/paymentMethods.ts b/support-frontend/assets/helpers/forms/paymentMethods.ts index abdd600bdc..c5971e250d 100644 --- a/support-frontend/assets/helpers/forms/paymentMethods.ts +++ b/support-frontend/assets/helpers/forms/paymentMethods.ts @@ -8,6 +8,9 @@ const Sepa = 'Sepa'; const AmazonPay = 'AmazonPay'; const None = 'None'; +const Success = 'success'; +const Pending = 'pending'; + export type PaymentMethodMap = { Stripe: T; PayPal: T; @@ -25,6 +28,8 @@ export type PaymentMethod = | typeof AmazonPay | typeof None; +export type PaymentStatus = typeof Success | typeof Pending; + export type FullPaymentMethod = { paymentMethod: PaymentMethod; stripePaymentMethod?: StripePaymentMethod; diff --git a/support-frontend/assets/pages/[countryGroupId]/components/checkoutComponent.tsx b/support-frontend/assets/pages/[countryGroupId]/components/checkoutComponent.tsx index cd808cfa59..3592c7b122 100644 --- a/support-frontend/assets/pages/[countryGroupId]/components/checkoutComponent.tsx +++ b/support-frontend/assets/pages/[countryGroupId]/components/checkoutComponent.tsx @@ -158,6 +158,7 @@ function paymentMethodIsActive(paymentMethod: LegacyPaymentMethod) { */ type ProcessPaymentResponse = | { status: 'success' } + | { status: 'pending' } | { status: 'failure'; failureReason?: ErrorReason }; type CreateSubscriptionResponse = StatusResponse & { @@ -190,7 +191,7 @@ const handlePaymentStatus = ( if (status === 'failure') { return { status, failureReason }; } else { - return { status: 'success' }; // success or pending + return { status: status }; // success or pending } }; @@ -620,11 +621,15 @@ export function CheckoutComponent({ }; } - if (processPaymentResponse.status === 'success') { + if ( + processPaymentResponse.status === 'success' || + processPaymentResponse.status === 'pending' + ) { const order = { firstName: personalData.firstName, email: personalData.email, paymentMethod: paymentMethod, + status: processPaymentResponse.status, }; setThankYouOrder(order); const thankYouUrlSearchParams = new URLSearchParams(); diff --git a/support-frontend/assets/pages/[countryGroupId]/components/oneTimeCheckoutComponent.tsx b/support-frontend/assets/pages/[countryGroupId]/components/oneTimeCheckoutComponent.tsx index c3f97ff9ea..91d45d9f50 100644 --- a/support-frontend/assets/pages/[countryGroupId]/components/oneTimeCheckoutComponent.tsx +++ b/support-frontend/assets/pages/[countryGroupId]/components/oneTimeCheckoutComponent.tsx @@ -461,6 +461,7 @@ export function OneTimeCheckoutComponent({ firstName: '', email: email, paymentMethod: paymentMethod, + status: 'success', // retry pending mechanism not applied to one-time payments }); const thankYouUrlSearchParams = new URLSearchParams(); thankYouUrlSearchParams.set('contribution', finalAmount.toString()); diff --git a/support-frontend/assets/pages/[countryGroupId]/components/thankYouComponent.tsx b/support-frontend/assets/pages/[countryGroupId]/components/thankYouComponent.tsx index d240aefe3f..342c5821df 100644 --- a/support-frontend/assets/pages/[countryGroupId]/components/thankYouComponent.tsx +++ b/support-frontend/assets/pages/[countryGroupId]/components/thankYouComponent.tsx @@ -71,6 +71,7 @@ const OrderSchema = object({ 'AmazonPay', 'None', ]), + status: picklist(['success', 'pending']), }); export function setThankYouOrder(order: InferInput) { storage.session.set('thankYouOrder', order); @@ -119,6 +120,7 @@ export function ThankYouComponent({ ); } const order = parsedOrder.output; + const isPending = order.status === 'pending'; /** * contributionType is only applicable to SupporterPlus and Contributions. @@ -262,9 +264,12 @@ export function ThankYouComponent({ ): ThankYouModuleType[] => (condition ? [moduleType] : []); const thankYouModules: ThankYouModuleType[] = [ - ...maybeThankYouModule(isNotRegistered && !isGuardianAdLite, 'signUp'), // Complete your Guardian account ...maybeThankYouModule( - !isNotRegistered && !isSignedIn && !isGuardianAdLite, + !isPending && isNotRegistered && !isGuardianAdLite, + 'signUp', + ), // Complete your Guardian account + ...maybeThankYouModule( + !isPending && !isNotRegistered && !isSignedIn && !isGuardianAdLite, 'signIn', ), // Sign in to access your benefits ...maybeThankYouModule(isTier3, 'benefits'), @@ -286,7 +291,7 @@ export function ThankYouComponent({ ...maybeThankYouModule(!isTier3 && !isGuardianAdLite, 'socialShare'), ...maybeThankYouModule(isGuardianAdLite, 'whatNext'), // All ...maybeThankYouModule( - isGuardianAdLite && isRegisteredAndNotSignedIn, + !isPending && isGuardianAdLite && isRegisteredAndNotSignedIn, 'signInToActivate', ), ...maybeThankYouModule( @@ -327,6 +332,7 @@ export function ThankYouComponent({ currency={currencyKey} promotion={promotion} identityUserType={identityUserType} + paymentStatus={order.status} /> diff --git a/support-frontend/assets/pages/supporter-plus-thank-you/components/thankYouHeader/heading.tsx b/support-frontend/assets/pages/supporter-plus-thank-you/components/thankYouHeader/heading.tsx index 17b5f564f3..4b400b5265 100644 --- a/support-frontend/assets/pages/supporter-plus-thank-you/components/thankYouHeader/heading.tsx +++ b/support-frontend/assets/pages/supporter-plus-thank-you/components/thankYouHeader/heading.tsx @@ -2,6 +2,7 @@ import { css } from '@emotion/react'; import { from, space, titlepiece42 } from '@guardian/source/foundations'; import type { ContributionType } from 'helpers/contributions'; import { formatAmount } from 'helpers/forms/checkouts'; +import type { PaymentStatus } from 'helpers/forms/paymentMethods'; import type { IsoCurrency } from 'helpers/internationalisation/currency'; import { currencies, @@ -182,6 +183,7 @@ type HeadingProps = { amount: number | undefined; currency: IsoCurrency; contributionType: ContributionType; + paymentStatus: PaymentStatus; promotion?: Promotion; }; function Heading({ @@ -191,20 +193,26 @@ function Heading({ amount, currency, contributionType, + paymentStatus, promotion, }: HeadingProps): JSX.Element { + const isPending = paymentStatus === 'pending'; const isGuardianAdLite = productKey === 'GuardianLight'; const isTier3 = productKey === 'TierThree'; const maybeNameAndTrailingSpace: string = name && name.length < 10 ? `${name} ` : ''; // Do not show special header to paypal/one-off as we don't have the relevant info after the redirect - if (isOneOffPayPal || !amount) { + if (isOneOffPayPal || !amount || isPending) { + const headerTitleSuffix = isPending + ? 'your recurring subscription is being processed' + : 'your valuable contribution'; + return (

Thank you{' '} - {maybeNameAndTrailingSpace}for - your valuable contribution + {maybeNameAndTrailingSpace} + {headerTitleSuffix}

); } diff --git a/support-frontend/assets/pages/supporter-plus-thank-you/components/thankYouHeader/subheading.tsx b/support-frontend/assets/pages/supporter-plus-thank-you/components/thankYouHeader/subheading.tsx index 838763e641..8fa0372792 100644 --- a/support-frontend/assets/pages/supporter-plus-thank-you/components/thankYouHeader/subheading.tsx +++ b/support-frontend/assets/pages/supporter-plus-thank-you/components/thankYouHeader/subheading.tsx @@ -1,5 +1,6 @@ import { css } from '@emotion/react'; import type { ContributionType } from 'helpers/contributions'; +import type { PaymentStatus } from 'helpers/forms/paymentMethods'; import { productCatalogDescription, type ProductKey, @@ -12,6 +13,7 @@ interface SubheadingProps { amountIsAboveThreshold: boolean; isSignedIn: boolean; identityUserType: UserType; + paymentStatus: PaymentStatus; } function MarketingCopy({ @@ -33,6 +35,15 @@ function MarketingCopy({ ); } +const getPendingCopy = (isPending: boolean) => { + const pendingCopy = ( + + {`Thankyou for subscribing to a recurring subscription. Your subscription is being processed and =you will receive an email when your account is live.`} + + ); + return isPending ? pendingCopy : null; +}; + const getSubHeadingCopy = ( productKey: ProductKey, amountIsAboveThreshold: boolean, @@ -89,6 +100,7 @@ function Subheading({ amountIsAboveThreshold, isSignedIn, identityUserType, + paymentStatus, }: SubheadingProps): JSX.Element { const isTier3 = productKey === 'TierThree'; const isGuardianAdLite = productKey === 'GuardianLight'; @@ -99,9 +111,10 @@ function Subheading({ isSignedIn, identityUserType, ); - + const pendingCopy = getPendingCopy(paymentStatus === 'pending'); return ( <> + {pendingCopy} {subheadingCopy} {!isGuardianAdLite && ( <> diff --git a/support-frontend/assets/pages/supporter-plus-thank-you/components/thankYouHeader/thankYouHeader.tsx b/support-frontend/assets/pages/supporter-plus-thank-you/components/thankYouHeader/thankYouHeader.tsx index 512ec9b662..64012e45dc 100644 --- a/support-frontend/assets/pages/supporter-plus-thank-you/components/thankYouHeader/thankYouHeader.tsx +++ b/support-frontend/assets/pages/supporter-plus-thank-you/components/thankYouHeader/thankYouHeader.tsx @@ -1,6 +1,7 @@ import { css } from '@emotion/react'; import { from, space, textEgyptian15 } from '@guardian/source/foundations'; import type { ContributionType } from 'helpers/contributions'; +import type { PaymentStatus } from 'helpers/forms/paymentMethods'; import { type IsoCurrency } from 'helpers/internationalisation/currency'; import type { ProductKey } from 'helpers/productCatalog'; import type { Promotion } from 'helpers/productPrice/promotions'; @@ -39,6 +40,7 @@ type ThankYouHeaderProps = { amountIsAboveThreshold: boolean; isSignedIn: boolean; identityUserType: UserType; + paymentStatus: PaymentStatus; promotion?: Promotion; showOffer?: boolean; }; @@ -54,8 +56,9 @@ function ThankYouHeader({ amountIsAboveThreshold, isSignedIn, identityUserType, - showOffer, + paymentStatus, promotion, + showOffer, }: ThankYouHeaderProps): JSX.Element { return (
@@ -64,9 +67,10 @@ function ThankYouHeader({ productKey={productKey} isOneOffPayPal={isOneOffPayPal} amount={amount} - promotion={promotion} currency={currency} contributionType={contributionType} + paymentStatus={paymentStatus} + promotion={promotion} />

@@ -77,6 +81,7 @@ function ThankYouHeader({ amountIsAboveThreshold={amountIsAboveThreshold} isSignedIn={isSignedIn} identityUserType={identityUserType} + paymentStatus={paymentStatus} />

{showOffer && (