From 3dee9e75f9cf64f7841bf648652ea7b0b1561cfa Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 4 Dec 2025 16:18:00 -0600 Subject: [PATCH] Add derived flags, add back disabled adult content for users under 18 --- src/ageAssurance/index.tsx | 30 ++++++++++++++++++++----- src/ageAssurance/util.ts | 4 ++++ src/screens/Moderation/index.tsx | 38 +++++++++++++++++++++++++++----- 3 files changed, 61 insertions(+), 11 deletions(-) diff --git a/src/ageAssurance/index.tsx b/src/ageAssurance/index.tsx index 1c815a755b..9a0a9c9d51 100644 --- a/src/ageAssurance/index.tsx +++ b/src/ageAssurance/index.tsx @@ -3,6 +3,7 @@ import {createContext, useCallback, useContext, useEffect, useMemo} from 'react' import {useGetAndRegisterPushToken} from '#/lib/notifications/notifications' import {Provider as RedirectOverlayProvider} from '#/ageAssurance/components/RedirectOverlay' import {AgeAssuranceDataProvider} from '#/ageAssurance/data' +import {useAgeAssuranceDataContext} from '#/ageAssurance/data' import {logger} from '#/ageAssurance/logger' import { useAgeAssuranceState, @@ -13,6 +14,7 @@ import { type AgeAssuranceState, AgeAssuranceStatus, } from '#/ageAssurance/types' +import {isUserUnderAdultAge} from '#/ageAssurance/util' export { prefetchConfig as prefetchAgeAssuranceConfig, @@ -27,6 +29,10 @@ const AgeAssuranceStateContext = createContext<{ Access: typeof AgeAssuranceAccess Status: typeof AgeAssuranceStatus state: AgeAssuranceState + flags: { + adultContentDisabled: boolean + chatDisabled: boolean + } }>({ Access: AgeAssuranceAccess, Status: AgeAssuranceStatus, @@ -35,6 +41,10 @@ const AgeAssuranceStateContext = createContext<{ status: AgeAssuranceStatus.Unknown, access: AgeAssuranceAccess.Full, }, + flags: { + adultContentDisabled: false, + chatDisabled: false, + }, }) /** @@ -58,6 +68,7 @@ export function Provider({children}: {children: React.ReactNode}) { function InnerProvider({children}: {children: React.ReactNode}) { const state = useAgeAssuranceState() + const {data} = useAgeAssuranceDataContext() const getAndRegisterPushToken = useGetAndRegisterPushToken() const handleAccessUpdate = useCallback( @@ -76,14 +87,23 @@ function InnerProvider({children}: {children: React.ReactNode}) { return ( ({ + value={useMemo(() => { + const chatDisabled = state.access !== AgeAssuranceAccess.Full + const isUnderage = data?.birthdate + ? isUserUnderAdultAge(data.birthdate) + : true + const adultContentDisabled = + state.access !== AgeAssuranceAccess.Full || isUnderage + return { Access: AgeAssuranceAccess, Status: AgeAssuranceStatus, state, - }), - [state], - )}> + flags: { + adultContentDisabled, + chatDisabled, + }, + } + }, [state, data])}> {children} ) diff --git a/src/ageAssurance/util.ts b/src/ageAssurance/util.ts index bf1248fc19..1043283305 100644 --- a/src/ageAssurance/util.ts +++ b/src/ageAssurance/util.ts @@ -82,3 +82,7 @@ export function isLegacyBirthdateBug(birthDate: string) { export function isUserUnderMinimumAge(birthDate: string) { return getAge(new Date(birthDate)) < DEFAULT_MIN_AGE } + +export function isUserUnderAdultAge(birthDate: string) { + return getAge(new Date(birthDate)) < 18 +} diff --git a/src/screens/Moderation/index.tsx b/src/screens/Moderation/index.tsx index 6fed53c510..76667d44a2 100644 --- a/src/screens/Moderation/index.tsx +++ b/src/screens/Moderation/index.tsx @@ -12,6 +12,7 @@ import { } from '#/lib/routes/types' import {logger} from '#/logger' import {isIOS} from '#/platform/detection' +import {useIsBirthdateUpdateAllowed} from '#/state/birthdate' import { useMyLabelersQuery, usePreferencesQuery, @@ -21,6 +22,7 @@ import { import {isNonConfigurableModerationAuthority} from '#/state/session/additional-moderation-authorities' import {useSetMinimalShellMode} from '#/state/shell' import {atoms as a, useBreakpoints, useTheme, type ViewStyleProp} from '#/alf' +import {Admonition} from '#/components/Admonition' import {AgeAssuranceAdmonition} from '#/components/ageAssurance/AgeAssuranceAdmonition' import {Button} from '#/components/Button' import {useGlobalDialogsControlContext} from '#/components/dialogs/Context' @@ -164,6 +166,7 @@ export function ModerationScreenInner({ error: labelersError, } = useMyLabelersQuery() const aa = useAgeAssurance() + const isBirthdateUpdateAllowed = useIsBirthdateUpdateAllowed() useFocusEffect( useCallback(() => { @@ -173,10 +176,17 @@ export function ModerationScreenInner({ const {mutateAsync: setAdultContentPref, variables: optimisticAdultContent} = usePreferencesSetAdultContentMutation() - const adultContentEnabled = !!( + let adultContentEnabled = !!( (optimisticAdultContent && optimisticAdultContent.enabled) || (!optimisticAdultContent && preferences.moderationPrefs.adultContentEnabled) ) + const adultContentUIDisabledOnIOS = isIOS && !adultContentEnabled + let adultContentUIDisabled = adultContentUIDisabledOnIOS + + if (aa.flags.adultContentDisabled) { + adultContentEnabled = false + adultContentUIDisabled = true + } const onToggleAdultContentEnabled = useCallback( async (selected: boolean) => { @@ -193,10 +203,26 @@ export function ModerationScreenInner({ [setAdultContentPref], ) - const disabledOnIOS = isIOS && !adultContentEnabled - return ( + {aa.flags.adultContentDisabled && isBirthdateUpdateAllowed && ( + + + + Your declared age is under 18. Some settings below may be + disabled. If this was a mistake, you may edit your birthdate in + your{' '} + + account settings + + . + + + + )} + Enable adult content @@ -362,7 +388,7 @@ export function ModerationScreenInner({ - {disabledOnIOS && ( + {adultContentUIDisabledOnIOS && (