client/components/shared/CallCenterEmailAndNumbers.tsx (263 lines of code) (raw):

import { css } from '@emotion/react'; import { from, palette, space, textSans17, textSansBold17, } from '@guardian/source/foundations'; import { useState } from 'react'; import type { PhoneRegionKey } from '@/shared/productResponse'; import { customerHelpEmailAddress, phoneData } from './callCentreData'; import type { CallCentreNumbersProps } from './CallCentreNumbers'; const contactUsStyles = { margin: '0 0 10px', paddingRight: '5px', }; const callCenterStyles = css({ display: 'flex', flexWrap: 'wrap', textAlign: 'left', fontWeight: 'normal', }); export interface CallCentreEmailAndNumbersProps extends CallCentreNumbersProps { hideEmailAddress?: boolean; phoneRegionFilterKeys?: PhoneRegionKey[]; compactLayout?: boolean; collapsed?: boolean; openPhoneRegion?: PhoneRegionKey; } export const CallCentreEmailAndNumbers = ( props: CallCentreEmailAndNumbersProps, ) => { const filteredPhoneData = phoneData.filter( (phoneRegion) => !props.phoneRegionFilterKeys || props.phoneRegionFilterKeys.includes(phoneRegion.key), ); const openPhoneRegionIndex = filteredPhoneData.findIndex( (region) => region.key === props.openPhoneRegion, ); const initialIndex = props.collapsed ? -1 : props.openPhoneRegion ? openPhoneRegionIndex : 0; const [indexOfOpenSection, setIndexOfOpenSection] = useState<number>(initialIndex); const sectionTitleCss = (isOpen: boolean, isNotFirstOption: boolean) => ` ${textSans17}; margin: 0; padding: ${space[4]}px ${space[4] * 2 + 15}px ${space[4]}px ${space[4]}px; position: relative; cursor: pointer; ${ isOpen ? ` font-weight: bold; background-color: ${palette.neutral['97']}; border-bottom: 1px solid ${palette.neutral['86']}; ` : '' } :after { content: ""; display: block; width: 7px; height: 7px; border-top: 2px solid ${palette.neutral['7']}; border-right: 2px solid ${palette.neutral['7']}; position: absolute; top: 50%; transform: ${ isOpen ? 'translateY(-1px) rotate(-45deg)' : 'translateY(-3.5px) rotate(135deg)' }; transition: transform 0.4s; right: 17px; } ${ isNotFirstOption && ` :before { content: ""; display: block; position: absolute; top: 0; left: 0; width: 100%; height: 1px; background-color: ${palette.neutral['86']} } ` } `; const showHideSpanCss = css` display: none; user-select: none; `; const showHideSpanWideCss = css` ${from.desktop} { display: block; position: absolute; top: 50%; transform: translateY(-50%); right: 32px; font-weight: normal; font-size: 0.75rem; } `; const innerSectionCss = (isOpen: boolean) => ` display: ${isOpen ? 'block' : 'none'}; background-color: ${palette.neutral['97']}; padding: ${space[4]}px; `; const innerSectionPCss = ` ${textSans17}; margin-bottom: 0; & + p { margin-top: ${space[4]}px; } `; const innerSectionBlockSpanCss = ` display: block; margin-bottom: 4px; font-weight: bold; `; const innerSectionTitleCss = ` ${textSans17}; margin: 6px 0 4px; `; const handleSectionClick = (sectionNum: number) => () => { setIndexOfOpenSection( indexOfOpenSection === sectionNum ? -1 : sectionNum, ); }; return ( <div css={callCenterStyles}> {props.prefixText && ( <p css={contactUsStyles}>{props.prefixText}</p> )} <div css={css` width: 100%; border: 1px solid ${palette.neutral['86']}; `} > {filteredPhoneData.map((phoneRegion, index) => { const isOpen = index === indexOfOpenSection; const isNotFirstOption = index > 0; return ( <div key={phoneRegion.key}> <h2 css={css` ${sectionTitleCss(isOpen, isNotFirstOption)} `} onClick={handleSectionClick(index)} > {phoneRegion.title} <span css={[ showHideSpanCss, !props.compactLayout && showHideSpanWideCss, ]} aria-hidden="true" > {isOpen ? 'Hide' : 'Show'} </span> </h2> <div css={css` ${innerSectionCss(isOpen)} `} > {!props.hideEmailAddress && ( <> <h4 css={css` ${innerSectionTitleCss} `} > Email: </h4> <span css={css` ${textSansBold17}; word-break: break-word; `} > {customerHelpEmailAddress} </span> </> )} {!props.hideEmailAddress && ( <h4 css={css` ${innerSectionTitleCss} `} > Phone: </h4> )} <p css={css` ${innerSectionPCss} `} > {phoneRegion.phoneNumbers.map( ({ phoneNumber, suffix }) => ( <span key={phoneNumber} css={css` ${innerSectionBlockSpanCss} `} > {phoneNumber} {suffix && ( <span css={css` font-weight: normal; `} > {' '} {suffix} </span> )} </span> ), )} {phoneRegion.openingHours.map( ( openingHourLine, openingHoursLineKey, ) => ( <span key={openingHoursLineKey} css={css` display: block; `} > {openingHourLine} </span> ), )} </p> {phoneRegion.additionalOpeningHoursInfo && ( <p css={css` ${innerSectionPCss} `} > {phoneRegion.additionalOpeningHoursInfo} </p> )} </div> </div> ); })} </div> </div> ); };