client/components/mma/identity/emailAndMarketing/EmailAndMarketing.tsx (226 lines of code) (raw):

import { createRef, useEffect, useState } from 'react'; import { featureSwitches } from '../../../../../shared/featureSwitches'; import type { AppSubscription, MPAPIResponse, } from '../../../../../shared/mpapiResponse'; import { AppSubscriptionSoftOptInIds, isValidAppSubscription, SingleContributionSoftOptInIds, } from '../../../../../shared/mpapiResponse'; import type { MembersDataApiResponse, ProductDetail, SingleProductDetail, } from '../../../../../shared/productResponse'; import { getSpecificProductType } from '../../../../../shared/productResponse'; import { fetchWithDefaultParameters } from '../../../../utilities/fetch'; import { allRecurringProductsDetailFetcher, allSingleProductsDetailFetcher, } from '../../../../utilities/productUtils'; import { NAV_LINKS } from '../../../shared/nav/NavConfig'; import { Spinner } from '../../../shared/Spinner'; import { WithStandardTopMargin } from '../../../shared/WithStandardTopMargin'; import { PageContainer } from '../../Page'; import type { GenericErrorMessageRef } from '../GenericErrorMessage'; import { GenericErrorMessage } from '../GenericErrorMessage'; import { ConsentOptions, Users } from '../identity'; import { IdentityLocations } from '../IdentityLocations'; import { Lines } from '../Lines'; import type { ConsentOption } from '../models'; import { Actions, useConsentOptions } from '../useConsentOptions'; import { ConsentSection } from './ConsentSection'; import { EmailSettingsSection } from './EmailSettingsSection'; import { NewsletterSection } from './NewsletterSection'; import { OptOutSection } from './OptOutSection'; export const EmailAndMarketing = (_: { path?: string }) => { const { options, error, subscribe, unsubscribe, unsubscribeAll } = Actions; const [email, setEmail] = useState<string>(''); const [removed, setRemoved] = useState(false); const [state, dispatch] = useConsentOptions(); const toggleSubscription = async (id: string) => { const option = ConsentOptions.findById(state.options, id); try { if (option === undefined) { throw Error('Id not found'); } if (option.subscribed) { await ConsentOptions.unsubscribe(option); dispatch(unsubscribe(id)); } else { await ConsentOptions.subscribe(option); dispatch(subscribe(id)); } } catch (e) { dispatch(error(e)); } }; const setRemoveAllEmailConsents = async () => { try { await ConsentOptions.unsubscribeAll(); setRemoved(true); dispatch(unsubscribeAll()); } catch (e) { dispatch(error(e)); } }; useEffect(() => { const makeInitialAPICalls = async () => { try { const user = await Users.getCurrentUser(); if (!user.validated) { window.location.assign(IdentityLocations.VERIFY_EMAIL); return; } const allRecurringProductsDetailFetcherPromise = allRecurringProductsDetailFetcher(); const mpapiFetchPromise = fetchWithDefaultParameters( '/mpapi/user/mobile-subscriptions', ); const allSingleProductsDetailFetcherPromise = allSingleProductsDetailFetcher(); const [ mdapiResponseRaw, mpapiResponseRaw, singleContributionsRaw, ] = await Promise.all( [ allRecurringProductsDetailFetcherPromise, mpapiFetchPromise, allSingleProductsDetailFetcherPromise, ].map((responsePromise) => responsePromise.then((response) => response.json()), ), ); const mdapiResponse: MembersDataApiResponse = mdapiResponseRaw; const productDetails = mdapiResponse.products as ProductDetail[]; const mpapiResponse = mpapiResponseRaw as MPAPIResponse; const singleContributions: SingleProductDetail[] = singleContributionsRaw; const appSubscriptions = mpapiResponse.subscriptions.filter( isValidAppSubscription, ); const consentOptions = await ConsentOptions.getAll(); const consentsWithFilteredSoftOptIns = consentOptions.filter( (consent: ConsentOption) => consent.isProduct ? userHasProductWithConsent( productDetails, consent, ) || (userHasAppSubscriptionWithConsent( appSubscriptions, consent, ) && featureSwitches.appSubscriptions) || userHasSingleContributionWithConsent( singleContributions, consent, ) : true, ); setEmail(user.primaryEmailAddress); dispatch(options(consentsWithFilteredSoftOptIns)); } catch (e) { dispatch(error(e)); } }; makeInitialAPICalls(); }, [dispatch, error, options]); const newsletters = ConsentOptions.newsletters(state.options); const consents = ConsentOptions.consents(state.options); const loading = newsletters.length === 0 && consents.length === 0; const errorRef = createRef<GenericErrorMessageRef>(); useEffect(() => { if (state.error && errorRef.current) { window.scrollTo(0, errorRef.current.offsetTop - 20); } }, [state.error, errorRef]); const errorMessage = ( <WithStandardTopMargin> <GenericErrorMessage ref={errorRef} /> </WithStandardTopMargin> ); const content = ( <> <WithStandardTopMargin> <NewsletterSection newsletters={newsletters} clickHandler={toggleSubscription} /> </WithStandardTopMargin> <WithStandardTopMargin> <Lines n={4} /> </WithStandardTopMargin> <WithStandardTopMargin> <ConsentSection consents={consents} clickHandler={toggleSubscription} /> </WithStandardTopMargin> <WithStandardTopMargin> <Lines n={1} /> </WithStandardTopMargin> <WithStandardTopMargin> <EmailSettingsSection email={email} actionHandler={setRemoveAllEmailConsents} removed={removed} /> </WithStandardTopMargin> <WithStandardTopMargin> <Lines n={4} /> </WithStandardTopMargin> <WithStandardTopMargin> <OptOutSection consents={consents} clickHandler={toggleSubscription} /> </WithStandardTopMargin> </> ); const loader = ( <WithStandardTopMargin> <Spinner loadingMessage="Loading your email preferences..." /> </WithStandardTopMargin> ); return ( <PageContainer selectedNavItem={NAV_LINKS.emailPrefs} pageTitle="Emails &amp; marketing" > {state.error ? errorMessage : null} {loading ? (!state.error ? loader : null) : content} </PageContainer> ); }; function userHasProductWithConsent( productDetails: ProductDetail[], consent: ConsentOption, ) { return productDetails.some((productDetail) => { const specificProductType = getSpecificProductType(productDetail.tier); return specificProductType.softOptInIDs.includes(consent.id); }); } function userHasAppSubscriptionWithConsent( appSubscriptions: AppSubscription[], consent: ConsentOption, ) { return ( appSubscriptions.length > 0 && AppSubscriptionSoftOptInIds.includes(consent.id) ); } function userHasSingleContributionWithConsent( singleContributions: SingleProductDetail[], consent: ConsentOption, ) { return ( singleContributions.length > 0 && SingleContributionSoftOptInIds.includes(consent.id) ); }