diff --git a/src/components/ageAssurance/AgeAssuranceAccountCard.tsx b/src/components/ageAssurance/AgeAssuranceAccountCard.tsx
index 5e83b09383..cfa4ce2b0d 100644
--- a/src/components/ageAssurance/AgeAssuranceAccountCard.tsx
+++ b/src/components/ageAssurance/AgeAssuranceAccountCard.tsx
@@ -20,11 +20,11 @@ import {createStaticClick, InlineLinkText} from '#/components/Link'
import {Text} from '#/components/Typography'
export function AgeAssuranceAccountCard({style}: ViewStyleProp & {}) {
- const {isLoaded, assurance, declaredAge} = useAgeInfo()
+ const {isLoaded, mustCompleteAgeAssurance, isUnderage} = useAgeInfo()
if (!isLoaded) return null
- if (declaredAge && declaredAge < 18) return null
- if (!assurance.isAgeRestricted) return null
+ if (isUnderage) return null
+ if (!mustCompleteAgeAssurance) return null
return
}
diff --git a/src/components/ageAssurance/AgeAssuranceAdmonition.tsx b/src/components/ageAssurance/AgeAssuranceAdmonition.tsx
index 122da430fb..e30dfa8cf4 100644
--- a/src/components/ageAssurance/AgeAssuranceAdmonition.tsx
+++ b/src/components/ageAssurance/AgeAssuranceAdmonition.tsx
@@ -15,11 +15,11 @@ export function AgeAssuranceAdmonition({
style,
}: ViewStyleProp & {children: React.ReactNode}) {
const control = useDialogControl()
- const {isLoaded, isUnderage, assurance} = useAgeInfo()
+ const {isLoaded, isUnderage, mustCompleteAgeAssurance} = useAgeInfo()
if (!isLoaded) return null
if (isUnderage) return null
- if (!assurance.isAgeRestricted) return null
+ if (!mustCompleteAgeAssurance) return null
return (
diff --git a/src/components/ageAssurance/AgeAssuranceDismissableNotice.tsx b/src/components/ageAssurance/AgeAssuranceDismissableNotice.tsx
index 955c69aa75..9b7c29b30c 100644
--- a/src/components/ageAssurance/AgeAssuranceDismissableNotice.tsx
+++ b/src/components/ageAssurance/AgeAssuranceDismissableNotice.tsx
@@ -12,7 +12,8 @@ import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
export function AgeAssuranceDismissableNotice({style}: ViewStyleProp & {}) {
const {_} = useLingui()
- const {isLoaded, isUnderage, assurance} = useAgeInfo()
+ const {isLoaded, isUnderage, mustCompleteAgeAssurance, assurance} =
+ useAgeInfo()
const {nux} = useNux(Nux.AgeAssuranceDismissableNotice)
const copy = useAgeAssuranceCopy()
const {mutate: save, variables} = useSaveNux()
@@ -20,7 +21,7 @@ export function AgeAssuranceDismissableNotice({style}: ViewStyleProp & {}) {
if (!isLoaded) return null
if (isUnderage) return null
- if (!assurance.isAgeRestricted) return null
+ if (!mustCompleteAgeAssurance) return null
if (assurance.lastInitiatedAt) return null
if (hidden) return null
if (nux && nux.completed) return null
diff --git a/src/components/ageAssurance/AgeRestrictedScreen.tsx b/src/components/ageAssurance/AgeRestrictedScreen.tsx
index a8afd01fb8..35628b6698 100644
--- a/src/components/ageAssurance/AgeRestrictedScreen.tsx
+++ b/src/components/ageAssurance/AgeRestrictedScreen.tsx
@@ -24,7 +24,7 @@ export function AgeRestrictedScreen({
}) {
const {_} = useLingui()
const copy = useAgeAssuranceCopy()
- const {isLoaded, assurance} = useAgeInfo()
+ const {isLoaded, mustCompleteAgeAssurance} = useAgeInfo()
if (!isLoaded) {
return (
@@ -39,7 +39,7 @@ export function AgeRestrictedScreen({
)
}
- if (!assurance.isAgeRestricted) return children
+ if (!mustCompleteAgeAssurance) return children
return (
diff --git a/src/lib/notifications/notifications.ts b/src/lib/notifications/notifications.ts
index ee0dbed9ac..522c33ceb5 100644
--- a/src/lib/notifications/notifications.ts
+++ b/src/lib/notifications/notifications.ts
@@ -9,6 +9,7 @@ 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 {useAgeAssuranceContext} from '#/state/ageAssurance'
+import {useMustCompleteAgeAssurance} from '#/state/ageAssurance/useMustCompleteAgeAssurance'
import {type SessionAccount, useAgent, useSession} from '#/state/session'
import BackgroundNotificationHandler from '#/../modules/expo-background-notification-handler'
@@ -122,7 +123,7 @@ async function getPushToken() {
* @see https://github.com/bluesky-social/social-app/pull/4467
*/
export function useGetAndRegisterPushToken() {
- const {isAgeRestricted} = useAgeAssuranceContext()
+ const mustCompleteAgeAssurance = useMustCompleteAgeAssurance()
const registerPushToken = useRegisterPushToken()
return useCallback(
async ({
@@ -149,13 +150,13 @@ export function useGetAndRegisterPushToken() {
*/
registerPushToken({
token,
- isAgeRestricted: isAgeRestrictedOverride ?? isAgeRestricted,
+ isAgeRestricted: isAgeRestrictedOverride ?? mustCompleteAgeAssurance,
})
}
return token
},
- [registerPushToken, isAgeRestricted],
+ [registerPushToken, mustCompleteAgeAssurance],
)
}
@@ -170,8 +171,8 @@ export function useNotificationsRegistration() {
const {currentAccount} = useSession()
const registerPushToken = useRegisterPushToken()
const getAndRegisterPushToken = useGetAndRegisterPushToken()
- const {isLoaded: isAgeAssuranceLoaded, isAgeRestricted} =
- useAgeAssuranceContext()
+ const {isLoaded: isAgeAssuranceLoaded} = useAgeAssuranceContext()
+ const mustCompleteAgeAssurance = useMustCompleteAgeAssurance()
useEffect(() => {
/**
@@ -200,7 +201,7 @@ export function useNotificationsRegistration() {
* @see https://docs.expo.dev/versions/latest/sdk/notifications/#addpushtokenlistenerlistener
*/
const subscription = Notifications.addPushTokenListener(async token => {
- registerPushToken({token, isAgeRestricted})
+ registerPushToken({token, isAgeRestricted: mustCompleteAgeAssurance})
notyLogger.debug(`addPushTokenListener callback`, {token})
})
@@ -212,7 +213,7 @@ export function useNotificationsRegistration() {
getAndRegisterPushToken,
registerPushToken,
isAgeAssuranceLoaded,
- isAgeRestricted,
+ mustCompleteAgeAssurance,
])
}
diff --git a/src/screens/Moderation/index.tsx b/src/screens/Moderation/index.tsx
index 11292f9f98..baa0265d8e 100644
--- a/src/screens/Moderation/index.tsx
+++ b/src/screens/Moderation/index.tsx
@@ -160,7 +160,7 @@ export function ModerationScreenInner({
data: labelers,
error: labelersError,
} = useMyLabelersQuery()
- const {declaredAge, isUnderage, assurance: ageAssurance} = useAgeInfo()
+ const {declaredAge, isUnderage, mustCompleteAgeAssurance} = useAgeInfo()
useFocusEffect(
useCallback(() => {
@@ -316,7 +316,7 @@ export function ModerationScreenInner({
- {declaredAge === undefined && ageAssurance.isAgeRestricted && (
+ {declaredAge === undefined && (
<>
- {disabledOnIOS && !ageAssurance.isAgeRestricted && (
+ {disabledOnIOS && (
@@ -414,7 +414,7 @@ export function ModerationScreenInner({
>
)}
diff --git a/src/state/ageAssurance/index.tsx b/src/state/ageAssurance/index.tsx
index 5a5d69101b..4d79184539 100644
--- a/src/state/ageAssurance/index.tsx
+++ b/src/state/ageAssurance/index.tsx
@@ -55,7 +55,7 @@ export function Provider({children}: {children: React.ReactNode}) {
enabled: true,
queryKey: createAgeAssuranceQueryKey(agent.session?.did ?? 'never'),
staleTime: STALE.MINUTES.ONE,
- refetchOnWindowFocus: true,
+ refetchOnWindowFocus: geolocation?.isAgeRestrictedGeo === true,
async queryFn() {
if (!agent.session) return null
@@ -68,7 +68,7 @@ export function Provider({children}: {children: React.ReactNode}) {
// (() => ({
// data: {
// lastInitiatedAt: undefined,//new Date().toISOString(),
- // status: 'unknown',
+ // status: 'pending',
// } as AppBskyUnspeccedDefs.AgeAssuranceState,
// }))(),
// )
diff --git a/src/state/ageAssurance/useAgeInfo.ts b/src/state/ageAssurance/useAgeInfo.ts
index 8825b63819..80df8f96e5 100644
--- a/src/state/ageAssurance/useAgeInfo.ts
+++ b/src/state/ageAssurance/useAgeInfo.ts
@@ -1,25 +1,44 @@
import {useMemo} from 'react'
+import {Logger} from '#/logger'
import {useAgeAssuranceContext} from '#/state/ageAssurance'
+import {useMustCompleteAgeAssurance} from '#/state/ageAssurance/useMustCompleteAgeAssurance'
import {usePreferencesQuery} from '#/state/queries/preferences'
+const logger = Logger.create(Logger.Context.AgeAssurance)
+
+type AgeInfo = {
+ isLoaded: boolean
+ declaredAge: number | undefined
+ isUnderage: boolean
+ mustCompleteAgeAssurance: boolean
+ assurance: ReturnType
+}
+
/**
* Computed age information based on age assurance status and the user's
* declared age. Use this instead of {@link useAgeAssuranceContext} to get a
* more user-friendly interface.
*/
-export function useAgeInfo() {
+export function useAgeInfo(): AgeInfo {
+ const mustCompleteAgeAssurance = useMustCompleteAgeAssurance()
const ctx = useAgeAssuranceContext()
const {isFetched: preferencesLoaded, data: preferences} =
usePreferencesQuery()
- const declaredAge = useMemo(() => preferences?.userAge, [preferences])
+ const declaredAge = preferences?.userAge
return useMemo(() => {
- return {
- isLoaded: ctx.isLoaded && preferencesLoaded,
+ const isLoaded = ctx.isLoaded && preferencesLoaded
+ const isUnderage = (declaredAge || 0) < 18
+ const info: AgeInfo = {
+ isLoaded,
declaredAge,
- isUnderage: ctx.isAgeRestricted && (declaredAge || 0) < 18,
+ isUnderage,
+ mustCompleteAgeAssurance,
+
assurance: ctx,
}
- }, [ctx, preferencesLoaded, declaredAge])
+ logger.debug(`useAgeInfo`, info)
+ return info
+ }, [ctx, preferencesLoaded, declaredAge, mustCompleteAgeAssurance])
}
diff --git a/src/state/ageAssurance/useMaybeApplyAgeRestrictedModerationPrefs.ts b/src/state/ageAssurance/useMaybeApplyAgeRestrictedModerationPrefs.ts
deleted file mode 100644
index a90b39b897..0000000000
--- a/src/state/ageAssurance/useMaybeApplyAgeRestrictedModerationPrefs.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import {useCallback} from 'react'
-import {type ModerationPrefs} from '@atproto/api'
-
-import {useAgeAssuranceContext} from '#/state/ageAssurance'
-import {AGE_RESTRICTED_MODERATION_PREFS} from '#/state/ageAssurance/const'
-
-/**
- * Hook to conditionally apply age-restricted moderation preferences, if
- * needed. If not needed, the mod prefs passed to the callback will be used.
- */
-export function useMaybeApplyAgeRestrictedModerationPrefs() {
- const state = useAgeAssuranceContext()
- return useCallback(
- (prev: ModerationPrefs) => {
- if (state.isAgeRestricted) {
- return AGE_RESTRICTED_MODERATION_PREFS
- }
-
- return prev
- },
- [state],
- )
-}
diff --git a/src/state/ageAssurance/useMustCompleteAgeAssurance.ts b/src/state/ageAssurance/useMustCompleteAgeAssurance.ts
new file mode 100644
index 0000000000..552306bf96
--- /dev/null
+++ b/src/state/ageAssurance/useMustCompleteAgeAssurance.ts
@@ -0,0 +1,17 @@
+import {useMemo} from 'react'
+
+import {useGate} from '#/lib/statsig/statsig'
+import {useAgeAssuranceContext} from '#/state/ageAssurance'
+import {useGeolocation} from '#/state/geolocation'
+
+export function useMustCompleteAgeAssurance() {
+ const gate = useGate()
+ const {geolocation} = useGeolocation()
+ const {isLoaded, status: ageAssuranceStatus} = useAgeAssuranceContext()
+ return useMemo(() => {
+ if (!gate('age_assurance')) return false
+ if (!geolocation?.isAgeRestrictedGeo) return false
+ if (!isLoaded) return false
+ return ageAssuranceStatus !== 'assured'
+ }, [isLoaded, gate, geolocation, ageAssuranceStatus])
+}
diff --git a/src/state/queries/preferences/index.ts b/src/state/queries/preferences/index.ts
index 47f489fa56..5100f721e5 100644
--- a/src/state/queries/preferences/index.ts
+++ b/src/state/queries/preferences/index.ts
@@ -10,7 +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 {useMaybeApplyAgeRestrictedModerationPrefs} from '#/state/ageAssurance/useMaybeApplyAgeRestrictedModerationPrefs'
+import {AGE_RESTRICTED_MODERATION_PREFS} from '#/state/ageAssurance/const'
+import {useMustCompleteAgeAssurance} from '#/state/ageAssurance/useMustCompleteAgeAssurance'
import {STALE} from '#/state/queries'
import {
DEFAULT_HOME_FEED_PREFS,
@@ -33,7 +34,7 @@ export const preferencesQueryKey = [preferencesQueryKeyRoot]
export function usePreferencesQuery() {
const agent = useAgent()
- const maybeOverrideModPrefs = useMaybeApplyAgeRestrictedModerationPrefs()
+ const mustCompleteAgeAssurance = useMustCompleteAgeAssurance()
return useQuery({
staleTime: STALE.SECONDS.FIFTEEN,
@@ -74,10 +75,13 @@ export function usePreferencesQuery() {
},
select: useCallback(
(data: UsePreferencesQueryResponse) => {
- data.moderationPrefs = maybeOverrideModPrefs(data.moderationPrefs)
+ const isUnderage = (data.userAge || 0) < 18
+ if (isUnderage || mustCompleteAgeAssurance) {
+ data.moderationPrefs = AGE_RESTRICTED_MODERATION_PREFS
+ }
return data
},
- [maybeOverrideModPrefs],
+ [mustCompleteAgeAssurance],
),
})
}