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' && (
+
+
+
+ )}
+