client/components/mma/holiday/HolidayReview.tsx (304 lines of code) (raw):

import { css } from '@emotion/react'; import { space, textSans14, until } from '@guardian/source/foundations'; import { Button, Checkbox, InlineError, } from '@guardian/source/react-components'; import { useContext, useState } from 'react'; import { Link, Navigate, useLocation } from 'react-router-dom'; import type { DateRange } from '../../../../shared/dates'; import { DATE_FNS_INPUT_FORMAT, dateString } from '../../../../shared/dates'; import type { ProductDetail } from '../../../../shared/productResponse'; import { MDA_TEST_USER_HEADER } from '../../../../shared/productResponse'; import { fetchWithDefaultParameters } from '../../../utilities/fetch'; import { CallCentreNumbers } from '../../shared/CallCentreNumbers'; import { InfoIcon } from '../shared/assets/InfoIcon'; import { LinkButton } from '../shared/Buttons'; import { ProgressIndicator } from '../shared/ProgressIndicator'; import { buttonBarCss, cancelLinkCss } from './HolidayDateChooser'; import { creditExplainerSentence, HolidayQuestionsModal, } from './HolidayQuestionsModal'; import type { CreateOrAmendHolidayStopsResponse, GetHolidayStopsResponse, HolidayStopDetail, HolidayStopRequest, } from './HolidayStopApi'; import { CreateOrAmendHolidayStopsAsyncLoader, isHolidayStopsResponse, } from './HolidayStopApi'; import type { HolidayStopsContextInterface, HolidayStopsRouterState, } from './HolidayStopsContainer'; import { HolidayStopsContext } from './HolidayStopsContainer'; import { Modal } from './Modal'; import { SummaryTable } from './SummaryTable'; const getPerformCreateOrAmendFetcher = ( selectedRange: DateRange, subscriptionName: string, isTestUser: boolean, existingHolidayStopToAmend: HolidayStopRequest | null, ) => () => fetchWithDefaultParameters( `/api/holidays${ existingHolidayStopToAmend ? `/${subscriptionName}/${existingHolidayStopToAmend.id}` : '' }`, { method: existingHolidayStopToAmend ? 'PATCH' : 'POST', body: JSON.stringify({ startDate: dateString( selectedRange.start, DATE_FNS_INPUT_FORMAT, ), endDate: dateString( selectedRange.end, DATE_FNS_INPUT_FORMAT, ), subscriptionName, }), headers: { 'Content-Type': 'application/json', [MDA_TEST_USER_HEADER]: `${isTestUser}`, }, }, ); const getRenderCreateOrAmendError = (modificationKeyword: string) => () => ( <div css={css` text-align: left; margin-top: 10px; `} > <h2> Sorry, {modificationKeyword} your holiday suspension failed. </h2> <p>To try again please go back and re-enter your dates.</p> <CallCentreNumbers prefixText="Alternatively, to contact us" /> <LinkButton to=".." text="Back" left /> </div> ); export const HolidayReview = () => { const [isExecuting, setIsExecuting] = useState<boolean>(false); const [isCheckboxConfirmed, setIsCheckboxConfirmed] = useState<boolean>(false); const { productDetail, productType, selectedRange, publicationsImpacted, holidayStopResponse, existingHolidayStopToAmend, } = useContext(HolidayStopsContext) as HolidayStopsContextInterface; const location = useLocation(); const routerState = location.state as HolidayStopsRouterState; const buildActualRenderer = ( holidayStopsResponse: GetHolidayStopsResponse, productDetail: ProductDetail, selectedRange: DateRange, publicationsImpacted: HolidayStopDetail[], ) => { const innerContent = ( <> <div> <h1>Review details before confirming</h1> <p> Check the details carefully and amend them if necessary.{' '} {creditExplainerSentence( productType.holidayStops.issueKeyword, )}{' '} {productType.holidayStops.additionalHowAdvice} </p> <HolidayQuestionsModal annualIssueLimit={holidayStopsResponse.annualIssueLimit} holidayStopFlowProperties={productType.holidayStops} /> <div css={css` height: 25px; `} /> <SummaryTable data={{ selectedRange, publicationsImpacted }} alternateSuspendedColumnHeading="To be suspended" isTestUser={productDetail.isTestUser} subscription={productDetail.subscription} issueKeyword={productType.holidayStops.issueKeyword} /> {productType.holidayStops.explicitConfirmationRequired && ( <> <div css={css` margin-top: 20px; margin-bottom: 10px; `} > <Checkbox label={ productType.holidayStops .explicitConfirmationRequired .checkboxLabel } checked={isCheckboxConfirmed} onChange={() => { setIsCheckboxConfirmed( !isCheckboxConfirmed, ); }} /> </div> <Modal instigator={ <a css={css` ${textSans14}; cursor: pointer; text-decoration: underline; margin: 10px; `} > <InfoIcon /> Tell me more </a> } title={ productType.holidayStops .explicitConfirmationRequired .explainerModalTitle } > <p> { productType.holidayStops .explicitConfirmationRequired .explainerModalBody } </p> </Modal> </> )} </div> {isExecuting ? ( <div css={css` margin-top: 40px; text-align: right; `} > <CreateOrAmendHolidayStopsAsyncLoader fetch={getPerformCreateOrAmendFetcher( selectedRange, productDetail.subscription.subscriptionId, productDetail.isTestUser, existingHolidayStopToAmend, )} render={(_: CreateOrAmendHolidayStopsResponse) => ( <Navigate to="../confirmed" state={routerState} /> )} errorRender={getRenderCreateOrAmendError( existingHolidayStopToAmend ? 'amending' : 'creating', )} loadingMessage={`${ existingHolidayStopToAmend ? 'Amending' : 'Creating' } your suspension...`} spinnerScale={0.7} inline /> </div> ) : ( <div css={css` margin-top: ${space[5]}px; ${until.mobileMedium} { margin-top: 0; }, `} > <div css={[ buttonBarCss, css` margin-top: ${space[5]}px; `, ]} > <Link css={cancelLinkCss} to=".." state={routerState} > Cancel </Link> <Button disabled={ !!productType.holidayStops .explicitConfirmationRequired && !isCheckboxConfirmed } onClick={() => setIsExecuting(true)} > Confirm </Button> </div> {!!productType.holidayStops .explicitConfirmationRequired && !isCheckboxConfirmed && ( <InlineError cssOverrides={css` margin-top: ${space[3]}px; `} > Please confirm you will destroy the affected vouchers by checking the box. </InlineError> )} </div> )} </> ); return ( <> <ProgressIndicator steps={[ { title: 'Choose dates' }, { title: 'Review', isCurrentStep: true }, { title: 'Confirmation' }, ]} additionalCSS={css` margin: ${space[5]}px 0 ${space[12]}px; `} /> {innerContent} </> ); }; return isHolidayStopsResponse(holidayStopResponse) && productDetail?.tier && selectedRange && publicationsImpacted ? ( buildActualRenderer( holidayStopResponse, productDetail, selectedRange, publicationsImpacted, ) ) : ( <Navigate to=".." state={routerState} /> ); };