client/components/mma/holiday/HolidaysOverview.tsx (319 lines of code) (raw):

import { css } from '@emotion/react'; import { from, space, textEgyptianBold17, textSans14, until, } from '@guardian/source/foundations'; import { Button } from '@guardian/source/react-components'; import type * as React from 'react'; import { useContext } from 'react'; import { useNavigate } from 'react-router'; import { useLocation } from 'react-router-dom'; import { DATE_FNS_LONG_OUTPUT_FORMAT, dateString, parseDate, } from '../../../../shared/dates'; import { getMainPlan, isPaidSubscriptionPlan, } from '../../../../shared/productResponse'; import { InfoIcon } from '../shared/assets/InfoIcon'; import { CollatedCredits } from './CollatedCredits'; import { creditExplainerSentence, HolidayQuestionsModal, } from './HolidayQuestionsModal'; import { calculateIssuesImpactedPerYear, isNotBulkSuspension, isNotWithdrawn, } from './HolidayStopApi'; import type { HolidayStopsContextInterface, HolidayStopsRouterState, } from './HolidayStopsContainer'; import { HolidayStopsContext } from './HolidayStopsContainer'; import { SummaryTable } from './SummaryTable'; interface OverviewRowProps { heading: string; fullWidth?: boolean; children: React.ReactNode; } const OverviewRow = (props: OverviewRowProps) => ( <div css={css` display: flex; flex-wrap: wrap; align-items: start; margin-bottom: ${space[5]}px; `} > <div css={css` flex: 1 0 180px; `} > <h3 css={css` ${textEgyptianBold17}; margin-top: 0; padding-top: 0; `} > {props.heading} </h3> </div> <div css={css` flex: 0 1 ${props.fullWidth ? '100%' : '450px'}; `} > {props.children} </div> </div> ); export const HolidaysOverview = () => { const holidayStopsContext = useContext( HolidayStopsContext, ) as HolidayStopsContextInterface; const { productType, productDetail, setExistingHolidayStopToAmend, holidayStopResponse, setSelectedRange, } = holidayStopsContext; const navigate = useNavigate(); const location = useLocation(); const routerState = location.state as HolidayStopsRouterState; const renewalDate = parseDate(productDetail.subscription.renewalDate).date; const combinedIssuesImpactedPerYear = calculateIssuesImpactedPerYear( holidayStopResponse.existing .filter(isNotWithdrawn) .filter(isNotBulkSuspension) .flatMap((existing) => existing.publicationsImpacted), renewalDate, ); const mainPlan = getMainPlan(productDetail.subscription); const currency = isPaidSubscriptionPlan(mainPlan) ? mainPlan.currency : undefined; const createSuspensionButton = ( <Button onClick={() => { setExistingHolidayStopToAmend(null); setSelectedRange(undefined); navigate('create', { state: routerState }); }} > Create suspension </Button> ); return ( <> <h1>Suspend {productType.friendlyName}</h1> {productDetail.subscription.autoRenew ? ( <OverviewRow heading="How"> <> <div> You can suspend up to{' '} <strong> {holidayStopResponse.annualIssueLimit}{' '} {productType.holidayStops.issueKeyword}s </strong>{' '} per year on your subscription. <br /> </div> {productType.holidayStops.alternateNoticeString && ( <div> Please provide{' '} <strong> { productType.holidayStops .alternateNoticeString } </strong> . </div> )} <div> {creditExplainerSentence( productType.holidayStops.issueKeyword, )} </div> {productType.holidayStops.additionalHowAdvice && ( <div> {productType.holidayStops.additionalHowAdvice} </div> )} <div css={css` ${textSans14}; margin: 10px; display: flex; align-items: top; `} > <InfoIcon /> <div> <strong> {dateString( renewalDate, DATE_FNS_LONG_OUTPUT_FORMAT, )} </strong>{' '} is the next anniversary of your subscription. <br /> The number of{' '} {productType.holidayStops.issueKeyword}s you can suspend per year is reset on this date. </div> </div> <HolidayQuestionsModal annualIssueLimit={ holidayStopResponse.annualIssueLimit } holidayStopFlowProperties={productType.holidayStops} /> </> </OverviewRow> ) : ( <h4> This subscription does not automatically renew, so unfortunately you{' '} {holidayStopResponse.existing.length > 0 ? 'can no longer' : 'cannot'}{' '} create a holiday suspension for this subscription. </h4> )} {(productDetail.subscription.autoRenew || holidayStopResponse.existing.length > 0) && ( <> <OverviewRow heading="Summary"> <> {holidayStopResponse.existing.length > 0 ? ( <> <div> You have suspended{' '} <strong> { combinedIssuesImpactedPerYear .issuesThisYear.length } / { holidayStopResponse.annualIssueLimit } </strong>{' '} {productType.holidayStops.issueKeyword}s until{' '} {dateString( renewalDate, DATE_FNS_LONG_OUTPUT_FORMAT, )} {combinedIssuesImpactedPerYear .issuesNextYear.length > 0 && ( <span> {' '} and{' '} <strong> { combinedIssuesImpactedPerYear .issuesNextYear .length } / { holidayStopResponse.annualIssueLimit } </strong>{' '} { productType.holidayStops .issueKeyword } s the following year </span> )} . </div> </> ) : ( <div> You have{' '} <strong> {holidayStopResponse.annualIssueLimit} </strong>{' '} {productType.holidayStops.issueKeyword}s available to suspend until{' '} {dateString( renewalDate, DATE_FNS_LONG_OUTPUT_FORMAT, )} </div> )} <div css={css` text-align: right; margin-top: 10px; ${from.phablet} { display: none; } `} > {productDetail.subscription.autoRenew && createSuspensionButton} </div> </> </OverviewRow> {holidayStopResponse.existing.length > 0 && ( <OverviewRow heading="Expected Credits"> <CollatedCredits publicationsImpacted={holidayStopResponse.existing .filter(isNotWithdrawn) .flatMap((_) => _.publicationsImpacted)} currency={currency} /> </OverviewRow> )} <OverviewRow heading="Details" fullWidth> {holidayStopResponse.existing.length > 0 ? ( <SummaryTable data={holidayStopResponse.existing} isTestUser={productDetail.isTestUser} subscription={productDetail.subscription} issueKeyword={ productType.holidayStops.issueKeyword } setExistingHolidayStopToAmend={ setExistingHolidayStopToAmend } /> ) : ( "You currently don't have any scheduled suspensions." )} </OverviewRow> </> )} <div css={css` display: flex; justify-content: space-between; align-items: center; margin-top: 30px; ${until.phablet} { flex-direction: column-reverse; } `} > <div css={css` margin-top: 10px; align-self: flex-start; `} > <Button onClick={() => { navigate('/'); }} priority="tertiary" > Return to your account </Button> </div> <div data-cy="create-suspension-cta" css={css` margin-top: 10px; align-self: flex-end; `} > {productDetail.subscription.autoRenew && createSuspensionButton} </div> </div> </> ); };