From 723b597cf99efa1351fc7adc272476d475543350 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 8 Jan 2026 12:08:17 -0600 Subject: [PATCH] Add error state in case of config failure --- src/ageAssurance/state.ts | 5 +++-- src/ageAssurance/types.ts | 1 + .../ageAssurance/AgeAssuranceAccountCard.tsx | 8 ++++++++ .../ageAssurance/AgeAssuranceAdmonition.tsx | 4 ++++ .../AgeAssuranceDismissibleFeedBanner.tsx | 1 + .../ageAssurance/AgeAssuranceErrors.tsx | 16 ++++++++++++++++ .../ageAssurance/AgeRestrictedScreen.tsx | 7 +++++++ 7 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/components/ageAssurance/AgeAssuranceErrors.tsx diff --git a/src/ageAssurance/state.ts b/src/ageAssurance/state.ts index 7ba86fe695..f4d1e41e3a 100644 --- a/src/ageAssurance/state.ts +++ b/src/ageAssurance/state.ts @@ -35,13 +35,14 @@ export function useAgeAssuranceState(): AgeAssuranceState { * The query handler will try it again, but if it continues to fail, of * course we won't have config. * - * In this case, fail open (unknown status/access) to avoid blocking users. + * In this case, fail open to avoid blocking users. */ if (!config) { logger.warn('useAgeAssuranceState: missing config') return { status: AgeAssuranceStatus.Unknown, - access: AgeAssuranceAccess.Unknown, + access: AgeAssuranceAccess.Safe, + error: 'config', } } diff --git a/src/ageAssurance/types.ts b/src/ageAssurance/types.ts index 9f83975d3e..f34ed10aea 100644 --- a/src/ageAssurance/types.ts +++ b/src/ageAssurance/types.ts @@ -18,6 +18,7 @@ export type AgeAssuranceState = { lastInitiatedAt?: string status: AgeAssuranceStatus access: AgeAssuranceAccess + error?: 'config' // maybe other specific cases in the future } export function parseStatusFromString(raw: string) { diff --git a/src/components/ageAssurance/AgeAssuranceAccountCard.tsx b/src/components/ageAssurance/AgeAssuranceAccountCard.tsx index a75e75d133..ecdff5b381 100644 --- a/src/components/ageAssurance/AgeAssuranceAccountCard.tsx +++ b/src/components/ageAssurance/AgeAssuranceAccountCard.tsx @@ -8,6 +8,7 @@ import {atoms as a, useBreakpoints, useTheme, type ViewStyleProp} from '#/alf' import {Admonition} from '#/components/Admonition' import {AgeAssuranceAppealDialog} from '#/components/ageAssurance/AgeAssuranceAppealDialog' import {AgeAssuranceBadge} from '#/components/ageAssurance/AgeAssuranceBadge' +import {AgeAssuranceConfigUnavailableError} from '#/components/ageAssurance/AgeAssuranceErrors' import { AgeAssuranceInitDialog, useDialogControl, @@ -27,6 +28,13 @@ import {useDeviceGeolocationApi} from '#/geolocation' export function AgeAssuranceAccountCard({style}: ViewStyleProp & {}) { const aa = useAgeAssurance() if (aa.state.access === aa.Access.Full) return null + if (aa.state.error === 'config') { + return ( + + + + ) + } return } diff --git a/src/components/ageAssurance/AgeAssuranceAdmonition.tsx b/src/components/ageAssurance/AgeAssuranceAdmonition.tsx index 7889070c09..570ed3b4fb 100644 --- a/src/components/ageAssurance/AgeAssuranceAdmonition.tsx +++ b/src/components/ageAssurance/AgeAssuranceAdmonition.tsx @@ -3,6 +3,7 @@ import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {atoms as a, select, useTheme, type ViewStyleProp} from '#/alf' +import {AgeAssuranceConfigUnavailableError} from '#/components/ageAssurance/AgeAssuranceErrors' import {useDialogControl} from '#/components/ageAssurance/AgeAssuranceInitDialog' import type * as Dialog from '#/components/Dialog' import {ShieldCheck_Stroke2_Corner0_Rounded as Shield} from '#/components/icons/Shield' @@ -19,6 +20,9 @@ export function AgeAssuranceAdmonition({ const aa = useAgeAssurance() if (aa.state.access === aa.Access.Full) return null + if (aa.state.error === 'config') { + return + } return ( diff --git a/src/components/ageAssurance/AgeAssuranceDismissibleFeedBanner.tsx b/src/components/ageAssurance/AgeAssuranceDismissibleFeedBanner.tsx index 3471393451..aa1d527f62 100644 --- a/src/components/ageAssurance/AgeAssuranceDismissibleFeedBanner.tsx +++ b/src/components/ageAssurance/AgeAssuranceDismissibleFeedBanner.tsx @@ -23,6 +23,7 @@ export function useInternalState() { const visible = useMemo(() => { if (aa.state.access === aa.Access.Full) return false if (aa.state.lastInitiatedAt) return false + if (aa.state.error === 'config') return false if (hidden) return false if (nux && nux.completed) return false return true diff --git a/src/components/ageAssurance/AgeAssuranceErrors.tsx b/src/components/ageAssurance/AgeAssuranceErrors.tsx new file mode 100644 index 0000000000..3c35ca7b2e --- /dev/null +++ b/src/components/ageAssurance/AgeAssuranceErrors.tsx @@ -0,0 +1,16 @@ +import {Trans} from '@lingui/macro' + +import {type ViewStyleProp} from '#/alf' +import {Admonition} from '#/components/Admonition' + +export function AgeAssuranceConfigUnavailableError(props: ViewStyleProp) { + return ( + + + We were unable to load age assurance configuration for your region, + probably due to a network error. Some content and features may be + unavailable temporarily. Please try again later. + + + ) +} diff --git a/src/components/ageAssurance/AgeRestrictedScreen.tsx b/src/components/ageAssurance/AgeRestrictedScreen.tsx index 85881a3ada..9f9c4c4d5b 100644 --- a/src/components/ageAssurance/AgeRestrictedScreen.tsx +++ b/src/components/ageAssurance/AgeRestrictedScreen.tsx @@ -5,6 +5,7 @@ import {useLingui} from '@lingui/react' import {atoms as a} from '#/alf' import {Admonition} from '#/components/Admonition' import {AgeAssuranceBadge} from '#/components/ageAssurance/AgeAssuranceBadge' +import {AgeAssuranceConfigUnavailableError} from '#/components/ageAssurance/AgeAssuranceErrors' import {useAgeAssuranceCopy} from '#/components/ageAssurance/useAgeAssuranceCopy' import {ButtonIcon, ButtonText} from '#/components/Button' import {ChevronRight_Stroke2_Corner0_Rounded as ChevronRight} from '#/components/icons/Chevron' @@ -44,6 +45,12 @@ export function AgeRestrictedScreen({ + {aa.state.error === 'config' && ( + + + + )} +