client/components/mma/cancel/cancellationSaves/CancellationLanding.tsx (164 lines of code) (raw):
import { css } from '@emotion/react';
import { space, textSans17 } from '@guardian/source/foundations';
import { Button, Stack } from '@guardian/source/react-components';
import { useContext } from 'react';
import { Navigate, useLocation, useNavigate } from 'react-router';
import { CallCentreAccordion } from '@/client/components/shared/CallCentreAccordion';
import type {
MembersDataApiResponse,
ProductDetail,
} from '../../../../../shared/productResponse';
import { getSpecificProductType } from '../../../../../shared/productResponse';
import { headingCss } from '../../../../styles/GenericStyles';
import {
LoadingState,
useAsyncLoader,
} from '../../../../utilities/hooks/useAsyncLoader';
import { allRecurringProductsDetailFetcher } from '../../../../utilities/productUtils';
import { GenericErrorScreen } from '../../../shared/GenericErrorScreen';
import { JsonResponseHandler } from '../../shared/asyncComponents/DefaultApiResponseHandler';
import { DefaultLoadingView } from '../../shared/asyncComponents/DefaultLoadingView';
import { Heading } from '../../shared/Heading';
import type {
CancellationContextInterface,
CancellationRouterState,
} from '../CancellationContainer';
import { CancellationContext } from '../CancellationContainer';
import { ineligibleForSave } from './saveEligibilityCheck';
function getNextRoute(productToCancel: ProductDetail): string {
const specificProductTypeKey = getSpecificProductType(
productToCancel.tier,
).productType;
switch (specificProductTypeKey) {
case 'membership': {
return '../details';
}
case 'digipack': {
return '../discount-offer';
}
default: {
return '/';
}
}
}
export const CancellationLanding = () => {
const location = useLocation();
const routerState = location.state as CancellationRouterState;
const navigate = useNavigate();
const { productDetail: productToCancel } = useContext(
CancellationContext,
) as CancellationContextInterface;
const {
data,
loadingState,
}: {
data: MembersDataApiResponse | null;
loadingState: LoadingState;
} = useAsyncLoader(allRecurringProductsDetailFetcher, JsonResponseHandler);
if (!productToCancel) {
return <Navigate to="/" />;
}
if (loadingState == LoadingState.HasError) {
return <GenericErrorScreen />;
}
if (loadingState == LoadingState.IsLoading) {
return <DefaultLoadingView loadingMessage="Loading your products..." />;
}
if (data === null) {
return <GenericErrorScreen />;
}
if (ineligibleForSave(data.products as ProductDetail[], productToCancel)) {
return (
<Navigate
to="../"
state={{
dontShowOffer: true,
}}
/>
);
}
return (
<>
<section
css={css`
margin-top: ${space[4]}px;
`}
>
<Stack space={1}>
<h2 css={headingCss}>
We're sorry to hear you're thinking of leaving
</h2>
<p
css={css`
${textSans17};
`}
>
To cancel today, please choose from the following
options.
</p>
</Stack>
</section>
<section
css={css`
margin-top: ${space[6] + space[2]}px;
`}
>
<Stack space={4}>
<div>
<Heading borderless sansSerif level="3">
Contact us
</Heading>
<p
css={css`
${textSans17};
margin: 0;
`}
>
Speak to our customer service team.
</p>
</div>
<CallCentreAccordion
phoneRegionFilterKeys={
productToCancel.selfServiceCancellation
.phoneRegionsToDisplay
}
/>
</Stack>
</section>
<section
css={css`
margin-top: ${space[6] + space[2]}px;
`}
>
<Stack space={2}>
<span>
<Heading borderless sansSerif level="3">
Cancel online
</Heading>
<p
css={css`
${textSans17};
margin: 0;
`}
>
End your subscription with just a few clicks.
</p>
</span>
<div>
<Button
priority="subdued"
onClick={() =>
navigate(getNextRoute(productToCancel), {
state: {
...routerState,
user: data.user,
},
})
}
>
Continue to cancel online
</Button>
</div>
</Stack>
</section>
</>
);
};