Skip to content

Commit

Permalink
sp+ annual cancellation offer page design amends
Browse files Browse the repository at this point in the history
  • Loading branch information
Richard Bangay committed Nov 6, 2024
1 parent 0b0a2e2 commit 68568a5
Show file tree
Hide file tree
Showing 5 changed files with 321 additions and 72 deletions.
26 changes: 13 additions & 13 deletions client/components/mma/cancel/Cancellation.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export const OfferMonthly: StoryObj<typeof CancellationContainer> = {
discountedPrice: 0,
discountPercentage: 100,
upToPeriods: 2,
upToPeriodsType: 'month',
upToPeriodsType: 'months',
firstDiscountedPaymentDate: '2024-05-30',
nextNonDiscountedPaymentDate: '2024-07-30',
nonDiscountedPayments: [{ date: '2024-07-30', amount: 14.99 }],
Expand Down Expand Up @@ -150,8 +150,8 @@ export const OfferYearly: StoryObj<typeof CancellationContainer> = {
productDetail: supporterPlusAnnual(),
discountedPrice: 90,
discountPercentage: 25,
upToPeriods: 1,
upToPeriodsType: 'year',
upToPeriods: 12,
upToPeriodsType: 'months',
firstDiscountedPaymentDate: '2024-05-30',
nextNonDiscountedPaymentDate: '2025-05-30',
nonDiscountedPayments: [{ date: '2025-05-30', amount: 120 }],
Expand All @@ -177,7 +177,7 @@ export const OfferReviewMonthly: StoryObj<typeof CancellationContainer> = {
discountedPrice: 0,
discountPercentage: 100,
upToPeriods: 2,
upToPeriodsType: 'month',
upToPeriodsType: 'months',
firstDiscountedPaymentDate: '2024-05-30',
nextNonDiscountedPaymentDate: '2024-07-30',
nonDiscountedPayments: [{ date: '2024-07-30', amount: 14.99 }],
Expand Down Expand Up @@ -209,8 +209,8 @@ export const OfferReviewYearly: StoryObj<typeof CancellationContainer> = {
productDetail: supporterPlusAnnual(),
discountedPrice: 90,
discountPercentage: 25,
upToPeriods: 1,
upToPeriodsType: 'year',
upToPeriods: 12,
upToPeriodsType: 'months',
firstDiscountedPaymentDate: '2024-05-30',
nextNonDiscountedPaymentDate: '2025-05-30',
nonDiscountedPayments: [{ date: '2025-05-30', amount: 120 }],
Expand Down Expand Up @@ -239,7 +239,7 @@ export const OfferConfirmedMonthly: StoryObj<typeof CancellationContainer> = {
reactRouter: {
state: {
upToPeriods: 2,
upToPeriodsType: 'month',
upToPeriodsType: 'months',
nextNonDiscountedPaymentDate: '2024-07-30',
nonDiscountedPayments: [{ date: '2024-07-30', amount: 14.99 }],
},
Expand All @@ -260,8 +260,8 @@ export const OfferConfirmedYearly: StoryObj<typeof CancellationContainer> = {
reactRouter: {
state: {
productDetail: supporterPlusAnnual(),
upToPeriods: 1,
upToPeriodsType: 'year',
upToPeriods: 12,
upToPeriodsType: 'months',
discountPercentage: 25,
discountedPrice: 90,
firstDiscountedPaymentDate: '2024-05-30',
Expand Down Expand Up @@ -293,7 +293,7 @@ export const Pause: StoryObj<typeof CancellationContainer> = {
discountedPrice: 0,
discountPercentage: 100,
upToPeriods: 2,
upToPeriodsType: 'month',
upToPeriodsType: 'months',
firstDiscountedPaymentDate: '2024-05-30',
nextNonDiscountedPaymentDate: '2024-07-30',
nonDiscountedPayments: [{ date: '2024-07-30', amount: 14.99 }],
Expand All @@ -318,7 +318,7 @@ export const PauseReview: StoryObj<typeof CancellationContainer> = {
discountedPrice: 0,
discountPercentage: 100,
upToPeriods: 2,
upToPeriodsType: 'month',
upToPeriodsType: 'months',
firstDiscountedPaymentDate: '2024-05-30',
nextNonDiscountedPaymentDate: '2024-07-30',
nonDiscountedPayments: [{ date: '2024-07-30', amount: 14.99 }],
Expand Down Expand Up @@ -347,7 +347,7 @@ export const PauseConfirmed: StoryObj<typeof CancellationContainer> = {
reactRouter: {
state: {
upToPeriods: 2,
upToPeriodsType: 'month',
upToPeriodsType: 'months',
nextNonDiscountedPaymentDate: '2024-07-30',
nonDiscountedPayments: [{ date: '2024-07-30', amount: 14.99 }],
},
Expand All @@ -372,7 +372,7 @@ export const SupportplusCancelConfirm: StoryObj<typeof CancellationContainer> =
eligibleForFreePeriodOffer: true,
discountedPrice: 0,
upToPeriods: 2,
upToPeriodsType: 'month',
upToPeriodsType: 'months',
firstDiscountedPaymentDate: '2024-05-30',
nextNonDiscountedPaymentDate: '2024-07-30',
nonDiscountedPayments: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,30 @@ import { css } from '@emotion/react';
import {
from,
neutral,
news,
palette,
space,
textEgyptian17,
textSans12,
textSans15,
textSans17,
textSans20,
textSansBold15,
textSansBold20,
textSansBold24,
textSansBold28,
} from '@guardian/source/foundations';
import { Button } from '@guardian/source/react-components';
import { capitalize } from 'lodash';
import { useContext } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import { Ribbon } from '@/client/components/shared/Ribbon';
import { Pill } from '@/client/components/shared/Pill';
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 {
DATE_FNS_LONG_OUTPUT_FORMAT,
getAppropriateReadableTimePeriod,
parseDate,
} from '@/shared/dates';
import { number2words } from '@/shared/numberUtils';
import { getMainPlan, isPaidSubscriptionPlan } from '@/shared/productResponse';
import type { ProductTypeKeys } from '@/shared/productTypes';
Expand Down Expand Up @@ -75,7 +78,7 @@ const availableOfferBoxInnerCss = css`
${from.tablet} {
background-color: ${palette.neutral[100]};
width: 363px;
padding-top: var(--offerBoxTopPadding);
padding: var(--offerBoxTopPadding) ${space[6]}px ${space[5]}px;
margin: ${space[6]}px;
}
`;
Expand Down Expand Up @@ -108,12 +111,14 @@ const headerImageCss = css`
}
`;

const ribbonCss = css`
const pillCss = css`
transform: translateY(-50%);
margin-left: ${space[4]}px;
${from.tablet} {
transform: translateY(0);
margin-left: 0;
position: absolute;
top: ${space[6] + space[4]}px;
top: ${space[6]}px;
left: ${space[12]}px;
}
`;

Expand All @@ -125,7 +130,7 @@ const strikethroughPriceCss = css`

const discountedPriceSpan = css`
${textSansBold20};
color: ${news[500]};
color: ${neutral[0]};
`;

const offerBoxTitleCss = css`
Expand All @@ -134,7 +139,7 @@ const offerBoxTitleCss = css`
`;

const billingResumptionDateCss = css`
${textSans15};
${textSans12};
color: ${neutral[38]};
margin: 0;
`;
Expand All @@ -148,6 +153,13 @@ const offerButtonCss = css`
}
`;

const offerButtonSmallBottomMargin = css`
margin-bottom: ${space[2]}px;
${from.tablet} {
margin-bottom: ${space[2]}px;
}
`;

const benefitsSubTitleCss = css`
margin: 0 0 ${space[5]}px;
${textSansBold15};
Expand Down Expand Up @@ -211,13 +223,12 @@ export const CancelAlternativeOffer = () => {
(routerState.discountPercentage < 100 ? 'percentage' : 'free');

const standfirstCopy: Partial<Record<ProductTypeKeys, string>> = {
supporterplus: `Instead of cancelling, enjoy ${
supporterplus:
offerIsPercentageOrFree === 'percentage'
? `${routerState.discountPercentage}% off for `
: ''
}${offerPeriodWord} ${offerPeriodType} with all your existing benefits${
offerIsPercentageOrFree === 'free' ? ' — for free' : ''
}.`,
? `Instead of cancelling, take ${routerState.discountPercentage}% off and keep enjoying all your existing benefits.`
: `Instead of cancelling, enjoy ${offerPeriodWord} ${offerPeriodType} with all your existing benefits${
offerIsPercentageOrFree === 'free' ? ' — for free' : ''
}.`,
contributions: `Instead of cancelling, you can pause your recurring payment for ${offerPeriodWord} ${offerPeriodType}.`,
};

Expand Down Expand Up @@ -270,16 +281,16 @@ export const CancelAlternativeOffer = () => {
<img src={heroImageSrc.mobile} />
</picture>
)}

{alternativeIsOffer && (
<Ribbon
<Pill
copy="Your one-time offer"
ribbonColour={palette.brand[500]}
copyColour={palette.neutral[100]}
roundedCornersRight
withoutTail
small
additionalCss={ribbonCss}
colour={
offerIsPercentageOrFree === 'percentage'
? palette.news[400]
: palette.brand[500]
}
sharpLeftSideMobileOnly
additionalCss={pillCss}
/>
)}
<div
Expand All @@ -289,10 +300,26 @@ export const CancelAlternativeOffer = () => {
]}
style={{
['--offerBoxTopPadding' as string]: alternativeIsOffer
? `${space[3] + space[4] + 30}px`
? `${space[8]}px`
: `${space[4]}px`,
}}
>
{offerIsPercentageOrFree === 'percentage' && (
<h4
css={[
offerBoxTitleCss,
css`
${textSansBold24}
`,
]}
>
{routerState.discountPercentage}% off for{' '}
{getAppropriateReadableTimePeriod(
routerState.upToPeriods,
offerPeriodType,
)}
</h4>
)}
{alternativeIsOffer && isPaidSubscriptionPlan(mainPlan) && (
<p css={strikethroughPriceCss}>
<s>
Expand All @@ -310,31 +337,36 @@ export const CancelAlternativeOffer = () => {
)}
</p>
)}

<h4
css={[
offerBoxTitleCss,
css`
${alternativeIsOffer && textSansBold28}
${alternativeIsPause && textSansBold20}
`,
]}
>
{offerIsPercentageOrFree &&
offerIsPercentageOrFree === 'free'
? `${capitalize(
offerPeriodWord,
)} ${offerPeriodType} free`
: 'New copy needed'}
{alternativeIsPause &&
`Would you like to pause your support to the Guardian for ${offerPeriodWord} ${offerPeriodType}?`}
</h4>
<p css={billingResumptionDateCss}>
{offerIsPercentageOrFree === 'percentage' &&
isPaidSubscriptionPlan(mainPlan)
? `You will pay ${mainPlan.currency}${routerState.discountedPrice} for the next 12 months then ${mainPlan.currency}${humanReadableStrikethroughPrice}/${mainPlan.billingPeriod}`
: `Billing resumes on ${nextNonDiscountedPaymentDate}`}
</p>
{alternativeIsPause && (
<h4
css={[
offerBoxTitleCss,
css`
${textSansBold20}
`,
]}
>
Would you like to pause your support to the Guardian
for {offerPeriodWord} {offerPeriodType}?
</h4>
)}
{offerIsPercentageOrFree === 'free' && (
<h4
css={[
offerBoxTitleCss,
css`
${textSansBold28}
`,
]}
>
{capitalize(offerPeriodWord)} {offerPeriodType} free
</h4>
)}
{offerIsPercentageOrFree === 'free' && (
<p css={billingResumptionDateCss}>
Billing resumes on {nextNonDiscountedPaymentDate}
</p>
)}
<Button
onClick={() => {
const reviewUrlPart = `../${
Expand All @@ -344,11 +376,39 @@ export const CancelAlternativeOffer = () => {
state: routerState,
});
}}
cssOverrides={offerButtonCss}
cssOverrides={[
offerButtonCss,
css`
${offerIsPercentageOrFree === 'percentage'
? offerButtonSmallBottomMargin
: ''}
`,
]}
>
{alternativeIsOffer && 'Redeem your offer'}
{alternativeIsPause && 'Yes, pause my support'}
</Button>
{offerIsPercentageOrFree === 'percentage' &&
isPaidSubscriptionPlan(mainPlan) && (
<p
css={[
billingResumptionDateCss,
css`
margin-bottom: ${space[5]}px;
`,
]}
>
You will pay {mainPlan.currency}
{routerState.discountedPrice} for the next{' '}
{routerState.upToPeriods} {offerPeriodType} then{' '}
{mainPlan.currency}
{getMaxNonDiscountedPrice(
routerState.nonDiscountedPayments,
true,
)}
/{mainPlan.billingPeriod}
</p>
)}
{alternativeIsOffer && (
<>
<p css={benefitsSubTitleCss}>
Expand All @@ -366,6 +426,10 @@ export const CancelAlternativeOffer = () => {
description:
'Unlimited access to the Guardian app',
},
{
description:
'Unlimited access to the Guardian Feast App',
},
{
description:
'Ad-free reading across all your devices',
Expand Down
Loading

0 comments on commit 68568a5

Please sign in to comment.