diff --git a/client/components/mma/cancel/Cancellation.stories.tsx b/client/components/mma/cancel/Cancellation.stories.tsx index 870b5d84c..dd1906450 100644 --- a/client/components/mma/cancel/Cancellation.stories.tsx +++ b/client/components/mma/cancel/Cancellation.stories.tsx @@ -98,6 +98,7 @@ export const Offer: StoryObj = { upToPeriodsType: 'months', firstDiscountedPaymentDate: '2024-05-30', nextNonDiscountedPaymentDate: '2024-07-30', + nonDiscountedPayments: [{ date: '2024-07-30', amount: 14.99 }], }, }, }, @@ -116,6 +117,7 @@ export const OfferReview: StoryObj = { upToPeriodsType: 'months', firstDiscountedPaymentDate: '2024-05-30', nextNonDiscountedPaymentDate: '2024-07-30', + nonDiscountedPayments: [{ date: '2024-07-30', amount: 14.99 }], }, }, msw: [ @@ -136,6 +138,7 @@ export const OfferConfirmed: StoryObj = { reactRouter: { state: { nextNonDiscountedPaymentDate: '2024-07-30', + nonDiscountedPayments: [{ date: '2024-07-30', amount: 14.99 }], }, }, }, @@ -156,6 +159,9 @@ export const SupportplusCancelConfirm: StoryObj = upToPeriodsType: 'months', firstDiscountedPaymentDate: '2024-05-30', nextNonDiscountedPaymentDate: '2024-07-30', + nonDiscountedPayments: [ + { date: '2024-07-30', amount: 14.99 }, + ], }, }, }, diff --git a/client/components/mma/cancel/cancellationSaves/supporterplus/SupporterPlusOffer.tsx b/client/components/mma/cancel/cancellationSaves/supporterplus/SupporterPlusOffer.tsx index 9ef48f9dc..5019294fc 100755 --- a/client/components/mma/cancel/cancellationSaves/supporterplus/SupporterPlusOffer.tsx +++ b/client/components/mma/cancel/cancellationSaves/supporterplus/SupporterPlusOffer.tsx @@ -19,6 +19,7 @@ import { useLocation, useNavigate } from 'react-router-dom'; import { Ribbon } from '@/client/components/shared/Ribbon'; import { measure } from '@/client/styles/typography'; import type { DiscountPreviewResponse } from '@/client/utilities/discountPreview'; +import { getMaxNonDiscountedPrice } from '@/client/utilities/discountPreview'; import { DATE_FNS_LONG_OUTPUT_FORMAT, parseDate } from '@/shared/dates'; import { number2words } from '@/shared/numberUtils'; import { getMainPlan, isPaidSubscriptionPlan } from '@/shared/productResponse'; @@ -175,6 +176,11 @@ export const SupporterPlusOffer = () => { 'yyyy-MM-dd', ).dateStr(DATE_FNS_LONG_OUTPUT_FORMAT); + const humanReadableStrikethroughPrice = getMaxNonDiscountedPrice( + routerState.nonDiscountedPayments, + true, + ); + return ( <> {

{mainPlan.currency} - {mainPlan.price / 100}/{mainPlan.billingPeriod} + {humanReadableStrikethroughPrice}/ + {mainPlan.billingPeriod}

)} diff --git a/client/components/mma/cancel/cancellationSaves/supporterplus/SupporterPlusOfferConfirmed.tsx b/client/components/mma/cancel/cancellationSaves/supporterplus/SupporterPlusOfferConfirmed.tsx index 968fcf6f1..fdaf485a7 100755 --- a/client/components/mma/cancel/cancellationSaves/supporterplus/SupporterPlusOfferConfirmed.tsx +++ b/client/components/mma/cancel/cancellationSaves/supporterplus/SupporterPlusOfferConfirmed.tsx @@ -13,7 +13,10 @@ import { useContext, useEffect } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { measure } from '@/client/styles/typography'; import type { DiscountPreviewResponse } from '@/client/utilities/discountPreview'; +import { getMaxNonDiscountedPrice } from '@/client/utilities/discountPreview'; import { DATE_FNS_LONG_OUTPUT_FORMAT, parseDate } from '@/shared/dates'; +import type { PaidSubscriptionPlan } from '@/shared/productResponse'; +import { getMainPlan } from '@/shared/productResponse'; import { DownloadAppCta } from '../../../shared/DownloadAppCta'; import { Heading } from '../../../shared/Heading'; import type { @@ -170,6 +173,9 @@ export const SupporterPlusOfferConfirmed = () => { ) as CancellationContextInterface; const productDetail = cancellationContext.productDetail; + const mainPlan = getMainPlan( + productDetail.subscription, + ) as PaidSubscriptionPlan; useEffect(() => { pageTitleContext.setPageTitle('Confirmation'); @@ -181,6 +187,11 @@ export const SupporterPlusOfferConfirmed = () => { 'yyyy-MM-dd', ).dateStr(DATE_FNS_LONG_OUTPUT_FORMAT); + const humanReadableNextNonDiscountedPrice = getMaxNonDiscountedPrice( + routerState.nonDiscountedPayments, + true, + ); + return ( <> {
  • You will not be billed until{' '} - {nextNonDiscountedPaymentDate} + {nextNonDiscountedPaymentDate} after which you will pay{' '} + {mainPlan.currency} + {humanReadableNextNonDiscountedPrice}/ + {mainPlan.billingPeriod}
  • diff --git a/client/components/mma/cancel/cancellationSaves/supporterplus/SupporterPlusOfferReview.tsx b/client/components/mma/cancel/cancellationSaves/supporterplus/SupporterPlusOfferReview.tsx index 6974e0e06..c0c1d7fea 100755 --- a/client/components/mma/cancel/cancellationSaves/supporterplus/SupporterPlusOfferReview.tsx +++ b/client/components/mma/cancel/cancellationSaves/supporterplus/SupporterPlusOfferReview.tsx @@ -18,6 +18,7 @@ import { useContext, useState } from 'react'; import { Link, useLocation, useNavigate } from 'react-router-dom'; import { measure } from '@/client/styles/typography'; import type { DiscountPreviewResponse } from '@/client/utilities/discountPreview'; +import { getMaxNonDiscountedPrice } from '@/client/utilities/discountPreview'; import { fetchWithDefaultParameters } from '@/client/utilities/fetch'; import { DATE_FNS_LONG_OUTPUT_FORMAT, parseDate } from '@/shared/dates'; import { number2words } from '@/shared/numberUtils'; @@ -127,6 +128,11 @@ export const SupporterPlusOfferReview = () => { 'yyyy-MM-dd', ).dateStr(DATE_FNS_LONG_OUTPUT_FORMAT); + const humanReadableStrikethroughPrice = getMaxNonDiscountedPrice( + routerState.nonDiscountedPayments, + true, + ); + const [performingDiscountStatus, setPerformingDiscountStatus] = useState('NOT_READY'); @@ -194,7 +200,8 @@ export const SupporterPlusOfferReview = () => {

    {mainPlan.currency} - {mainPlan.price / 100}/{mainPlan.billingPeriod} + {humanReadableStrikethroughPrice}/ + {mainPlan.billingPeriod}

    )} diff --git a/client/utilities/discountPreview.ts b/client/utilities/discountPreview.ts index 574f505f1..2239fe7ae 100644 --- a/client/utilities/discountPreview.ts +++ b/client/utilities/discountPreview.ts @@ -1,7 +1,27 @@ +interface NonDiscountedPayments { + date: string; + amount: number; +} + export type DiscountPreviewResponse = { discountedPrice: number; upToPeriods: number; upToPeriodsType: string; firstDiscountedPaymentDate: string; nextNonDiscountedPaymentDate: string; + nonDiscountedPayments: NonDiscountedPayments[]; +}; + +export const getMaxNonDiscountedPrice = ( + nonDiscountedPayments: NonDiscountedPayments[], + asHumanReadable?: boolean, +) => { + const allNonDiscountedAmounts = nonDiscountedPayments.map((p) => p.amount); + const maxNonDiscountedPrice = Math.max(...allNonDiscountedAmounts); + if (!asHumanReadable) { + return maxNonDiscountedPrice; + } + return Number.isInteger(maxNonDiscountedPrice) + ? maxNonDiscountedPrice + : maxNonDiscountedPrice.toFixed(2); }; diff --git a/cypress/tests/mocked/parallel-2/cancelSupporterPlus.cy.ts b/cypress/tests/mocked/parallel-2/cancelSupporterPlus.cy.ts index 1fb1e8609..90faa6c62 100644 --- a/cypress/tests/mocked/parallel-2/cancelSupporterPlus.cy.ts +++ b/cypress/tests/mocked/parallel-2/cancelSupporterPlus.cy.ts @@ -149,6 +149,7 @@ describe('Cancel Supporter Plus', () => { upToPeriodsType: 'Months', firstDiscountedPaymentDate: '2024-05-30', nextNonDiscountedPaymentDate: '2024-07-30', + nonDiscountedPayments: [{ date: '2024-07-30', amount: 14.5 }], }; it('user accepts offer instead of cancelling', () => { cy.intercept('GET', '/api/me/mma', { @@ -184,6 +185,8 @@ describe('Cancel Supporter Plus', () => { name: 'Continue to cancellation', }).click(); + cy.findByText('£14.50/month'); + cy.findByRole('button', { name: 'Redeem your offer' }).click(); cy.findByRole('button', {