diff --git a/src/lib/notifications/notifications.ts b/src/lib/notifications/notifications.ts index 78eef3b104..348cc4082c 100644 --- a/src/lib/notifications/notifications.ts +++ b/src/lib/notifications/notifications.ts @@ -8,7 +8,7 @@ import debounce from 'lodash.debounce' import {PUBLIC_APPVIEW_DID, PUBLIC_STAGING_APPVIEW_DID} from '#/lib/constants' import {logger as notyLogger} from '#/lib/notifications/util' import {isNative} from '#/platform/detection' -import {useIsAgeRestricted} from '#/state/ageAssurance/useIsAgeRestricted' +import {useAgeAssuranceContext} from '#/state/ageAssurance' import {type SessionAccount, useAgent, useSession} from '#/state/session' import BackgroundNotificationHandler from '#/../modules/expo-background-notification-handler' @@ -122,7 +122,7 @@ async function getPushToken() { * @see https://github.com/bluesky-social/social-app/pull/4467 */ export function useGetAndRegisterPushToken() { - const {isAgeRestricted} = useIsAgeRestricted() + const {isAgeRestricted} = useAgeAssuranceContext() const registerPushToken = useRegisterPushToken() return useCallback( async ({ @@ -170,7 +170,8 @@ export function useNotificationsRegistration() { const {currentAccount} = useSession() const registerPushToken = useRegisterPushToken() const getAndRegisterPushToken = useGetAndRegisterPushToken() - const {isReady: isAgeRestrictionReady, isAgeRestricted} = useIsAgeRestricted() + const {isReady: isAgeRestrictionReady, isAgeRestricted} = + useAgeAssuranceContext() useEffect(() => { /** diff --git a/src/state/ageAssurance/index.tsx b/src/state/ageAssurance/index.tsx index 633b68af9f..f3d7de6f36 100644 --- a/src/state/ageAssurance/index.tsx +++ b/src/state/ageAssurance/index.tsx @@ -12,6 +12,7 @@ import { type AgeAssuranceAPIContextType, type AgeAssuranceContextType, } from '#/state/ageAssurance/types' +import {useIsAgeAssuranceEnabled} from '#/state/ageAssurance/useIsAgeAssuranceEnabled' import {useGeolocation} from '#/state/geolocation' import {useAgent} from '#/state/session' @@ -26,6 +27,7 @@ const AgeAssuranceContext = createContext({ status: 'unknown', isReady: false, lastInitiatedAt: undefined, + isAgeRestricted: false, }) const AgeAssuranceAPIContext = createContext({ // @ts-ignore @@ -38,11 +40,11 @@ const AgeAssuranceAPIContext = createContext({ * performance. */ export function Provider({children}: {children: React.ReactNode}) { + const gate = useGate() const agent = useAgent() const {geolocation} = useGeolocation() + const isAgeAssuranceEnabled = useIsAgeAssuranceEnabled() const getAndRegisterPushToken = useGetAndRegisterPushToken() - const isAgeRestrictedGeo = !!geolocation?.isAgeRestrictedGeo - const gate = useGate() const {data, isFetched, refetch} = useQuery({ /** @@ -50,7 +52,7 @@ export function Provider({children}: {children: React.ReactNode}) { * "fetched" state, even if we fall back to defaults. This lets the rest of * the app know that we've at least attempted to load the AA state. */ - enabled: true, + enabled: isAgeAssuranceEnabled, queryKey: createAgeAssuranceQueryKey(agent.session?.did ?? 'never'), async queryFn() { if (!agent.session) return null @@ -76,9 +78,8 @@ export function Provider({children}: {children: React.ReactNode}) { if (gate('age_assurance')) { await getAndRegisterPushToken({ - isAgeRestricted: Boolean( - isAgeRestrictedGeo && data.status !== 'assured', - ), + isAgeRestricted: + !!geolocation?.isAgeRestrictedGeo && data.status !== 'assured', }) } @@ -99,13 +100,14 @@ export function Provider({children}: {children: React.ReactNode}) { const ageAssuranceContext = useMemo(() => { const {status, lastInitiatedAt} = data || DEFAULT_AGE_ASSURANCE_STATE const ctx: AgeAssuranceContextType = { - isReady: isFetched, + isReady: isFetched || !isAgeAssuranceEnabled, status, lastInitiatedAt, + isAgeRestricted: isAgeAssuranceEnabled ? status !== 'assured' : false, } logger.debug(`context`, ctx) return ctx - }, [isFetched, data]) + }, [isFetched, data, isAgeAssuranceEnabled]) const ageAssuranceAPIContext = useMemo( () => ({ diff --git a/src/state/ageAssurance/types.ts b/src/state/ageAssurance/types.ts index 1152e39f54..63febb3cff 100644 --- a/src/state/ageAssurance/types.ts +++ b/src/state/ageAssurance/types.ts @@ -3,7 +3,9 @@ import {type QueryObserverBaseResult} from '@tanstack/react-query' export type AgeAssuranceContextType = { /** - * Whether the age assurance state has been fetched from the server. + * Whether the age assurance state has been fetched from the server. If user + * is not in a region that requires AA, or AA is otherwise disabled, this + * will always be `true`. */ isReady: boolean /** @@ -14,6 +16,13 @@ export type AgeAssuranceContextType = { * The last time the age assurance state was attempted by the user. */ lastInitiatedAt: AppBskyUnspeccedDefs.AgeAssuranceState['lastInitiatedAt'] + /** + * Indicates the user is age restricted based on the requirements of their + * region, and their server-provided age assurance status. Does not factor in + * the user's declared age. If AA is otherise disabled, this will always be + * `false`. + */ + isAgeRestricted: boolean } export type AgeAssuranceAPIContextType = { diff --git a/src/state/ageAssurance/useAgeAssurance.ts b/src/state/ageAssurance/useAgeAssurance.ts index 1359782b31..455f38c926 100644 --- a/src/state/ageAssurance/useAgeAssurance.ts +++ b/src/state/ageAssurance/useAgeAssurance.ts @@ -2,18 +2,11 @@ import {useMemo} from 'react' import {Logger} from '#/logger' import {useAgeAssuranceContext} from '#/state/ageAssurance' -import {useIsAgeRestricted} from '#/state/ageAssurance/useIsAgeRestricted' import {usePreferencesQuery} from '#/state/queries/preferences' const logger = Logger.create(Logger.Context.AgeAssurance) type AgeAssurance = ReturnType & { - /** - * Indicates the user is age restricted based on the requirements of their - * region, and their server-provided age assurance status. Does not factor in - * the user's declared age. - */ - isAgeRestricted: boolean /** * The age the user has declared in their preferences, if any. */ @@ -30,24 +23,23 @@ type AgeAssurance = ReturnType & { * more user-friendly interface. */ export function useAgeAssurance(): AgeAssurance { - const ctx = useAgeAssuranceContext() - const {isAgeRestricted} = useIsAgeRestricted() + const aa = useAgeAssuranceContext() const {isFetched: preferencesLoaded, data: preferences} = usePreferencesQuery() const declaredAge = preferences?.userAge return useMemo(() => { - const isReady = ctx.isReady && preferencesLoaded + const isReady = aa.isReady && preferencesLoaded const isDeclaredUnderage = (declaredAge || 0) < 18 const state: AgeAssurance = { isReady, - status: ctx.status, - lastInitiatedAt: ctx.lastInitiatedAt, - isAgeRestricted, + status: aa.status, + lastInitiatedAt: aa.lastInitiatedAt, + isAgeRestricted: aa.isAgeRestricted, declaredAge, isDeclaredUnderage, } logger.debug(`state`, state) return state - }, [ctx, preferencesLoaded, declaredAge, isAgeRestricted]) + }, [aa, preferencesLoaded, declaredAge]) } diff --git a/src/state/ageAssurance/useIsAgeAssuranceEnabled.ts b/src/state/ageAssurance/useIsAgeAssuranceEnabled.ts new file mode 100644 index 0000000000..5c1a7b1c48 --- /dev/null +++ b/src/state/ageAssurance/useIsAgeAssuranceEnabled.ts @@ -0,0 +1,13 @@ +import {useMemo} from 'react' + +import {useGate} from '#/lib/statsig/statsig' +import {useGeolocation} from '#/state/geolocation' + +export function useIsAgeAssuranceEnabled() { + const gate = useGate() + const {geolocation} = useGeolocation() + + return useMemo(() => { + return gate('age_assurance') && !!geolocation?.isAgeRestrictedGeo + }, [geolocation, gate]) +} diff --git a/src/state/ageAssurance/useIsAgeRestricted.ts b/src/state/ageAssurance/useIsAgeRestricted.ts deleted file mode 100644 index 0bdef9f493..0000000000 --- a/src/state/ageAssurance/useIsAgeRestricted.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {useMemo} from 'react' - -import {useGate} from '#/lib/statsig/statsig' -import {useAgeAssuranceContext} from '#/state/ageAssurance' -import {useGeolocation} from '#/state/geolocation' - -export function useIsAgeRestricted() { - const {isReady, status} = useAgeAssuranceContext() - const {geolocation} = useGeolocation() - const gate = useGate() - - return useMemo(() => { - if (!gate('age_assurance') || !geolocation?.isAgeRestrictedGeo) { - return { - isReady: true, - isAgeRestricted: false, - } - } - return { - isReady, - isAgeRestricted: status !== 'assured', - } - }, [isReady, status, geolocation, gate]) -} diff --git a/src/state/queries/preferences/index.ts b/src/state/queries/preferences/index.ts index ae6013624b..bb68742c2f 100644 --- a/src/state/queries/preferences/index.ts +++ b/src/state/queries/preferences/index.ts @@ -10,8 +10,8 @@ import {PROD_DEFAULT_FEED} from '#/lib/constants' import {replaceEqualDeep} from '#/lib/functions' import {getAge} from '#/lib/strings/time' import {logger} from '#/logger' +import {useAgeAssuranceContext} from '#/state/ageAssurance' import {AGE_RESTRICTED_MODERATION_PREFS} from '#/state/ageAssurance/const' -import {useIsAgeRestricted} from '#/state/ageAssurance/useIsAgeRestricted' import {STALE} from '#/state/queries' import { DEFAULT_HOME_FEED_PREFS, @@ -34,7 +34,8 @@ export const preferencesQueryKey = [preferencesQueryKeyRoot] export function usePreferencesQuery() { const agent = useAgent() - const {isReady: isAgeRestrictionReady, isAgeRestricted} = useIsAgeRestricted() + const {isReady: isAgeRestrictionReady, isAgeRestricted} = + useAgeAssuranceContext() return useQuery({ staleTime: STALE.SECONDS.FIFTEEN,