Skip to content

Commit 4121257

Browse files
Merge pull request #1275 from guardian/cc/digisub/journey-routes
DigiSub routes and cancellation reasons
2 parents 07255be + bbe3c8c commit 4121257

19 files changed

+571
-258
lines changed

client/components/mma/MMAPage.tsx

+70-13
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ import { breakpoints, from, space } from '@guardian/source-foundations';
44
import type { ReactNode } from 'react';
55
import { lazy, Suspense, useEffect, useState } from 'react';
66
import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom';
7-
import { initFeatureSwitchUrlParamOverride } from '../../../shared/featureSwitches';
7+
import {
8+
featureSwitches,
9+
initFeatureSwitchUrlParamOverride,
10+
} from '../../../shared/featureSwitches';
811
import type {
912
ProductType,
1013
ProductTypeWithDeliveryRecordsProperties,
@@ -66,6 +69,11 @@ const ManageProduct = lazy(() =>
6669
/* webpackChunkName: "ManageProduct" */ './accountoverview/ManageProduct'
6770
).then(({ ManageProduct }) => ({ default: ManageProduct })),
6871
);
72+
const ManageProductV2 = lazy(() =>
73+
import(
74+
/* webpackChunkName: "ManageProduct" */ './accountoverview/manageProducts/ManageProductV2'
75+
).then(({ ManageProductV2 }) => ({ default: ManageProductV2 })),
76+
);
6977
const CancellationContainer = lazy(() =>
7078
import(
7179
/* webpackChunkName: "Cancellation" */ './cancel/CancellationContainer'
@@ -134,7 +142,7 @@ const MembershipSwitch = lazy(() =>
134142

135143
const SelectReason = lazy(() =>
136144
import(
137-
/* webpackChunkName: "Cancellation" */ './cancel/cancellationSaves/membership/SelectReason'
145+
/* webpackChunkName: "Cancellation" */ './cancel/cancellationSaves/SelectReason'
138146
).then(({ SelectReason }) => ({
139147
default: SelectReason,
140148
})),
@@ -164,6 +172,30 @@ const SwitchThankYou = lazy(() =>
164172
})),
165173
);
166174

175+
const ConfirmDigiSubCancellation = lazy(() =>
176+
import(
177+
/* webpackChunkName: "Cancellation" */ './cancel/cancellationSaves/digipack/ConfirmDigiSubCancellation'
178+
).then(({ ConfirmDigiSubCancellation: ConfirmDigiSubCancellation }) => ({
179+
default: ConfirmDigiSubCancellation,
180+
})),
181+
);
182+
183+
const DigiSubThankYouOffer = lazy(() =>
184+
import(
185+
/* webpackChunkName: "Cancellation" */ './cancel/cancellationSaves/digipack/ThankYouOffer'
186+
).then(({ ThankYouOffer: ThankYouOffer }) => ({
187+
default: ThankYouOffer,
188+
})),
189+
);
190+
191+
const ConfirmDigiSubDiscount = lazy(() =>
192+
import(
193+
/* webpackChunkName: "Cancellation" */ './cancel/cancellationSaves/digipack/DigiSubDiscountConfirm'
194+
).then(({ DigiSubDiscountConfirm: DigiSubDiscountConfirm }) => ({
195+
default: DigiSubDiscountConfirm,
196+
})),
197+
);
198+
167199
const PaymentDetailUpdateContainer = lazy(() =>
168200
import(
169201
/* webpackChunkName: "PaymentDetailUpdate" */ './paymentUpdate/PaymentDetailUpdateContainer'
@@ -475,17 +507,29 @@ const MMARouter = () => {
475507
</Route>
476508
))}
477509
{Object.values(PRODUCT_TYPES).map(
478-
(productType: ProductType) => (
479-
<Route
480-
key={productType.urlPart}
481-
path={`/${productType.urlPart}`}
482-
element={
483-
<ManageProduct
484-
productType={productType}
485-
/>
486-
}
487-
/>
488-
),
510+
(productType: ProductType) =>
511+
featureSwitches.digisubSave &&
512+
productType.productType === 'digipack' ? (
513+
<Route
514+
key={productType.urlPart}
515+
path={`/${productType.urlPart}`}
516+
element={
517+
<ManageProductV2
518+
productType={productType}
519+
/>
520+
}
521+
/>
522+
) : (
523+
<Route
524+
key={productType.urlPart}
525+
path={`/${productType.urlPart}`}
526+
element={
527+
<ManageProduct
528+
productType={productType}
529+
/>
530+
}
531+
/>
532+
),
489533
)}
490534
{Object.values(PRODUCT_TYPES)
491535
.filter(hasDeliveryFlow)
@@ -658,6 +702,19 @@ const MMARouter = () => {
658702
path="switch-thank-you"
659703
element={<SwitchThankYou />}
660704
/>
705+
706+
<Route
707+
path="confirm-cancel"
708+
element={<ConfirmDigiSubCancellation />}
709+
/>
710+
<Route
711+
path="confirm-discount"
712+
element={<ConfirmDigiSubDiscount />}
713+
/>
714+
<Route
715+
path="discount-offer"
716+
element={<DigiSubThankYouOffer />}
717+
/>
661718
</Route>
662719
),
663720
)}

client/components/mma/accountoverview/AccountOverview.stories.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ import { user } from '../../../fixtures/user';
3131
import { AccountOverview } from './AccountOverview';
3232

3333
featureSwitches['appSubscriptions'] = true;
34-
featureSwitches['singleContributions'] = true;
3534

3635
export default {
3736
title: 'Pages/AccountOverview',

client/components/mma/accountoverview/ManageProduct.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import {
88
} from '@guardian/source-foundations';
99
import { useState } from 'react';
1010
import { Link, Navigate, useLocation } from 'react-router-dom';
11+
import { featureSwitches } from '@/shared/featureSwitches';
1112
import { cancellationFormatDate } from '../../../../shared/dates';
12-
import { featureSwitches } from '../../../../shared/featureSwitches';
1313
import type {
1414
MembersDataApiResponse,
1515
ProductDetail,

client/components/mma/accountoverview/manageProducts/ManageProductV2.tsx

+19-56
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ import {
77
until,
88
} from '@guardian/source-foundations';
99
import {
10+
Button,
1011
LinkButton,
1112
Stack,
1213
SvgCalendar,
1314
SvgClock,
1415
SvgCreditCard,
1516
} from '@guardian/source-react-components';
16-
import { Link, Navigate, useLocation } from 'react-router-dom';
17+
import { useLocation, useNavigate } from 'react-router-dom';
1718
import { PageContainer } from '@/client/components/mma/Page';
1819
import { ErrorIcon } from '@/client/components/mma/shared/assets/ErrorIcon';
1920
import { JsonResponseHandler } from '@/client/components/mma/shared/asyncComponents/DefaultApiResponseHandler';
@@ -71,6 +72,8 @@ const InnerContent = ({
7172
manageProductV2Props,
7273
productDetail,
7374
}: InnerContentProps) => {
75+
const navigate = useNavigate();
76+
7477
const mainPlan = getMainPlan(productDetail.subscription);
7578
if (!mainPlan) {
7679
throw new Error('mainPlan does not exist in manageProductV2 page');
@@ -248,11 +251,17 @@ const InnerContent = ({
248251
`}
249252
>
250253
{!hasCancellationPending && (
251-
<CancellationCTA
252-
productDetail={productDetail}
253-
friendlyName={groupedProductType.friendlyName()}
254-
specificProductType={specificProductType}
255-
/>
254+
<Button
255+
priority="subdued"
256+
onClick={() => {
257+
navigate(
258+
'/cancel/' +
259+
specificProductType.urlPart,
260+
);
261+
}}
262+
>
263+
Cancel {groupedProductType.friendlyName()}
264+
</Button>
256265
)}
257266
</div>
258267
</div>
@@ -261,60 +270,13 @@ const InnerContent = ({
261270
);
262271
};
263272

264-
interface CancellationCTAProps {
265-
productDetail: ProductDetail;
266-
friendlyName: string;
267-
specificProductType: ProductType;
268-
}
269-
270-
const CancellationCTA = (props: CancellationCTAProps) => {
271-
const shouldContactUsToCancel =
272-
!props.productDetail.selfServiceCancellation.isAllowed ||
273-
!props.specificProductType.cancellation;
274-
return (
275-
<>
276-
{shouldContactUsToCancel && (
277-
<div
278-
css={css`
279-
${textSans.medium()};
280-
color: ${palette.neutral[46]};
281-
margin-top: 16px;
282-
justify-content: center;
283-
`}
284-
>
285-
Would you like to cancel your {props.friendlyName}?
286-
<Link
287-
css={css`
288-
${textSans.medium()};
289-
color: ${palette.brand[400]};
290-
font-weight: 700;
291-
text-decoration-line: underline;
292-
justify-content: center;
293-
margin-left: 5px;
294-
`}
295-
to={'/cancel/' + props.specificProductType.urlPart}
296-
state={{ productDetail: props.productDetail }}
297-
>
298-
Contact us
299-
</Link>
300-
</div>
301-
)}
302-
303-
{!shouldContactUsToCancel && (
304-
<Link to={'/cancel/' + props.specificProductType.urlPart}>
305-
{' '}
306-
Cancel {props.friendlyName}{' '}
307-
</Link>
308-
)}
309-
</>
310-
);
311-
};
312-
313273
interface ManageProductV2RouterState {
314274
productDetail: ProductDetail;
315275
}
316276

317277
const AsyncLoadedInnerContent = (props: WithProductType<ProductType>) => {
278+
const navigate = useNavigate();
279+
318280
const request = createProductDetailFetcher(
319281
props.productType.allProductsProductTypeFilterString,
320282
);
@@ -332,7 +294,8 @@ const AsyncLoadedInnerContent = (props: WithProductType<ProductType>) => {
332294
}
333295

334296
if (data == null || data.products.length == 0) {
335-
return <Navigate to="/" />;
297+
navigate('/');
298+
return null;
336299
}
337300

338301
const productDetail = data.products.filter(isProduct)[0];

client/components/mma/cancel/CancellationSaveEligibilityCheck.tsx

+16-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,27 @@
11
import { useContext } from 'react';
22
import { Navigate, useLocation } from 'react-router-dom';
3+
import { featureSwitches } from '@/shared/featureSwitches';
4+
import {
5+
getSpecificProductTypeFromProduct,
6+
type ProductDetail,
7+
} from '@/shared/productResponse';
38
import { CancellationContext } from './CancellationContainer';
49
import type {
510
CancellationContextInterface,
611
CancellationRouterState,
712
} from './CancellationContainer';
813
import { CancellationReasonSelection } from './CancellationReasonSelection';
914

15+
function productHasSaveJourney(productToCancel: ProductDetail): boolean {
16+
const specificProductTypeKey =
17+
getSpecificProductTypeFromProduct(productToCancel).productType;
18+
19+
return (
20+
specificProductTypeKey === 'membership' ||
21+
(featureSwitches.digisubSave && specificProductTypeKey === 'digipack')
22+
);
23+
}
24+
1025
export const CancellationSaveEligibilityCheck = () => {
1126
const location = useLocation();
1227
const routerState = location.state as CancellationRouterState;
@@ -20,10 +35,7 @@ export const CancellationSaveEligibilityCheck = () => {
2035
return <Navigate to="/" />;
2136
}
2237

23-
if (
24-
!routerState?.dontShowOffer &&
25-
productDetail.mmaCategory === 'membership'
26-
) {
38+
if (!routerState?.dontShowOffer && productHasSaveJourney(productDetail)) {
2739
return <Navigate to="./landing" />;
2840
}
2941

client/components/mma/cancel/cancellationSaves/CancellationLanding.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ function getNextRoute(productToCancel: ProductDetail): string {
3131
case 'membership': {
3232
return '../details';
3333
}
34+
case 'digipack': {
35+
return '../discount-offer';
36+
}
3437
default: {
3538
return '/';
3639
}

client/components/mma/cancel/cancellationSaves/CancellationSaves.stories.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import { ConfirmMembershipCancellation } from './membership/ConfirmMembershipCan
77
import { ContinueMembershipConfirmation } from './membership/ContinueMembershipConfirmation';
88
import { MembershipSwitch } from './membership/MembershipSwitch';
99
import { SaveOptions } from './membership/SaveOptions';
10-
import { SelectReason } from './membership/SelectReason';
1110
import { SwitchThankYou } from './membership/SwitchThankYou';
1211
import { ValueOfSupport } from './membership/ValueOfSupport';
12+
import { SelectReason } from './SelectReason';
1313

1414
export default {
1515
title: 'Pages/CancellationSave',

0 commit comments

Comments
 (0)