client/components/mma/paymentUpdate/PaymentDetailUpdateContainer.tsx (116 lines of code) (raw):

import type { Context } from 'react'; import { createContext } from 'react'; import { Navigate, Outlet, useLocation, useSearchParams, } from 'react-router-dom'; import type { MembersDataApiResponse, ProductDetail, } from '../../../../shared/productResponse'; import { isProduct, MembersDataApiAsyncLoader, } from '../../../../shared/productResponse'; import type { ProductType, WithProductType, } from '../../../../shared/productTypes'; import { createProductDetailFetcher } from '../../../utilities/productUtils'; import { getNavItemFromFlowReferrer } from '../../shared/nav/NavConfig'; import { PageContainer } from '../Page'; export interface PaymentUpdateContextInterface { productDetail: ProductDetail; isFromApp?: boolean; } const renderContextAndOutletContainer = (isFromApp?: boolean, subscriptionId?: string) => (mdapiResponse: MembersDataApiResponse) => { const filteredProductDetails = mdapiResponse.products .filter(isProduct) .filter( (productDetail) => !productDetail.subscription.cancelledAt && productDetail.subscription.readerType !== 'Gift', ); if (filteredProductDetails.length === 1) { return ( <PaymentUpdateContext.Provider value={{ productDetail: filteredProductDetails[0], isFromApp, }} > <Outlet /> </PaymentUpdateContext.Provider> ); } else if (subscriptionId) { const filteredProductDetailsWithSubscriptionId = filteredProductDetails.filter( (productDetail) => productDetail.subscription.subscriptionId === subscriptionId, ); if (filteredProductDetailsWithSubscriptionId.length === 1) { return ( <PaymentUpdateContext.Provider value={{ productDetail: filteredProductDetailsWithSubscriptionId[0], isFromApp, }} > <Outlet /> </PaymentUpdateContext.Provider> ); } } return <Navigate to="/" />; }; export const PaymentUpdateContext: Context<PaymentUpdateContextInterface | null> = createContext<PaymentUpdateContextInterface | null>(null); export const PaymentDetailUpdateContainer = ( props: WithProductType<ProductType>, ) => { interface LocationState { productDetail: ProductDetail; flowReferrer?: { title: string; link: string; }; isFromApp?: boolean; } const [queryParameters] = useSearchParams(); const location = useLocation(); const routerState = location.state as LocationState; const productDetail = routerState?.productDetail; const isFromApp = routerState?.isFromApp; const navItemReferrer = getNavItemFromFlowReferrer( routerState?.flowReferrer?.title, ); return ( <PageContainer selectedNavItem={navItemReferrer} pageTitle="Manage payment method" > {productDetail ? ( <PaymentUpdateContext.Provider value={{ productDetail, isFromApp }} > <Outlet /> </PaymentUpdateContext.Provider> ) : ( <MembersDataApiAsyncLoader fetch={createProductDetailFetcher( props.productType.allProductsProductTypeFilterString, )} render={renderContextAndOutletContainer( isFromApp, queryParameters.get('subscriptionId') ?? undefined, // for internal links we use the context instead of query params )} loadingMessage={`Retrieving current payment details for your ${props.productType.friendlyName}...`} /> )} </PageContainer> ); };