client/components/mma/delivery/address/DeliveryAddressChangeContainer.tsx (147 lines of code) (raw):

import { css } from '@emotion/react'; import { from } from '@guardian/source/foundations'; import { useState } from 'react'; import { Outlet } from 'react-router-dom'; import type { MembersDataApiResponse } from '../../../../../shared/productResponse'; import { isProduct, MembersDataApiAsyncLoader, } from '../../../../../shared/productResponse'; import type { ProductType, WithProductType, } from '../../../../../shared/productTypes'; import { GROUPED_PRODUCT_TYPES } from '../../../../../shared/productTypes'; import type { ContactIdToArrayOfProductDetailAndProductType } from '../../../../utilities/deliveryAddress'; import { addressChangeAffectedInfo, getValidDeliveryAddressChangeEffectiveDates, } from '../../../../utilities/deliveryAddress'; import { createProductDetailFetcher } from '../../../../utilities/productUtils'; import { NAV_LINKS } from '../../../shared/nav/NavConfig'; import { COUNTRIES } from '../../identity/models'; import { PageContainer } from '../../Page'; import { AddressChangedInformationContext, ContactIdContext, NewDeliveryAddressContext, } from './DeliveryAddressFormContext'; interface ContextAndOutletContainerProps { contactIdToArrayOfProductDetailAndProductType: ContactIdToArrayOfProductDetailAndProductType; productType: ProductType; } const renderContextAndOutletContainer = (productType: ProductType) => (mdapiResponse: MembersDataApiResponse) => { return ( <ContextAndOutletContainer contactIdToArrayOfProductDetailAndProductType={getValidDeliveryAddressChangeEffectiveDates( mdapiResponse.products .filter(isProduct) .filter((_) => _.subscription.readerType !== 'Gift'), )} productType={productType} /> ); }; const ContextAndOutletContainer = (props: ContextAndOutletContainerProps) => { const existingDeliveryAddress = Object.values( props.contactIdToArrayOfProductDetailAndProductType, )[0][0].productDetail.subscription.deliveryAddress; const [addressLine1, setAddressLine1] = useState( existingDeliveryAddress?.addressLine1 || '', ); const [addressLine2, setAddressLine2] = useState( existingDeliveryAddress?.addressLine2 || '', ); const [town, setTown] = useState(existingDeliveryAddress?.town || ''); const [region, setRegion] = useState(existingDeliveryAddress?.region || ''); const [postcode, setPostcode] = useState( existingDeliveryAddress?.postcode || '', ); const [country, setCountry] = useState( existingDeliveryAddress?.country ? COUNTRIES.find( (countryObj) => existingDeliveryAddress?.country === countryObj.iso, )?.name || existingDeliveryAddress?.country : '', ); const [instructions, setInstructions] = useState( existingDeliveryAddress?.instructions || '', ); const addressSetStateObject = { setAddressLine1, setAddressLine2, setTown, setRegion, setPostcode, setCountry, setInstructions, }; const addressStateObject = { addressLine1, addressLine2, town, region, postcode, country, instructions, }; return ( <NewDeliveryAddressContext.Provider value={{ addressStateObject, addressSetStateObject, }} > <AddressChangedInformationContext.Provider value={addressChangeAffectedInfo( props.contactIdToArrayOfProductDetailAndProductType, )} > <ContactIdContext.Provider value={props.contactIdToArrayOfProductDetailAndProductType} > <Outlet /> </ContactIdContext.Provider> </AddressChangedInformationContext.Provider> </NewDeliveryAddressContext.Provider> ); }; export const DeliveryAddressChangeContainer = ( props: WithProductType<ProductType>, ) => { return ( <PageContainer selectedNavItem={NAV_LINKS.accountOverview} pageTitle={ <span css={css` ::first-letter { text-transform: capitalize; } `} > <span css={css` display: none; ${from.tablet} { display: inline; } `} > Update{' '} </span> delivery details </span> } > <MembersDataApiAsyncLoader render={renderContextAndOutletContainer(props.productType)} fetch={createProductDetailFetcher( GROUPED_PRODUCT_TYPES.subscriptions .allProductsProductTypeFilterString, )} loadingMessage={'Loading delivery details...'} /> </PageContainer> ); };