From 5ef52f708f7db6e435d49df288e297c597bcb875 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 25 Jun 2025 17:25:24 -0500 Subject: [PATCH] Add prelim fetch --- src/App.native.tsx | 59 ++++++++++++---------- src/App.web.tsx | 48 ++++++++++-------- src/logger/types.ts | 1 + src/state/ageAssurance.tsx | 100 +++++++++++++++++++++++++++++++++++++ 4 files changed, 162 insertions(+), 46 deletions(-) create mode 100644 src/state/ageAssurance.tsx diff --git a/src/App.native.tsx b/src/App.native.tsx index 2278b73de6..49fd13529e 100644 --- a/src/App.native.tsx +++ b/src/App.native.tsx @@ -26,6 +26,10 @@ import I18nProvider from '#/locale/i18nProvider' import {logger} from '#/logger' import {isAndroid, isIOS} from '#/platform/detection' import {Provider as A11yProvider} from '#/state/a11y' +import { + Provider as AgeAssuranceProvider, + useAgeAssuranceAPIContext, +} from '#/state/ageAssurance' import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes' import {Provider as DialogStateProvider} from '#/state/dialogs' import {listenSessionDropped} from '#/state/events' @@ -95,8 +99,8 @@ function InnerApp() { const {resumeSession} = useSessionApi() const theme = useColorModeTheme() const {_} = useLingui() - const hasCheckedReferrer = useStarterPackEntry() + const {refresh: refreshAgeAssurance} = useAgeAssuranceAPIContext() // init useEffect(() => { @@ -104,6 +108,7 @@ function InnerApp() { try { if (account) { await resumeSession(account) + await refreshAgeAssurance() } else { await tryFetchGates(undefined, 'prefer-fresh-gates') } @@ -115,7 +120,7 @@ function InnerApp() { } const account = readLastActiveAccount() onLaunch(account) - }, [resumeSession]) + }, [resumeSession, refreshAgeAssurance]) useEffect(() => { return listenSessionDropped(() => { @@ -211,30 +216,32 @@ function App() { - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/App.web.tsx b/src/App.web.tsx index b706774fdc..487721dd40 100644 --- a/src/App.web.tsx +++ b/src/App.web.tsx @@ -15,6 +15,10 @@ import {ThemeProvider} from '#/lib/ThemeContext' import I18nProvider from '#/locale/i18nProvider' import {logger} from '#/logger' import {Provider as A11yProvider} from '#/state/a11y' +import { + Provider as AgeAssuranceProvider, + useAgeAssuranceAPIContext, +} from '#/state/ageAssurance' import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes' import {Provider as DialogStateProvider} from '#/state/dialogs' import {listenSessionDropped} from '#/state/events' @@ -75,6 +79,7 @@ function InnerApp() { const theme = useColorModeTheme() const {_} = useLingui() const hasCheckedReferrer = useStarterPackEntry() + const {refresh: refreshAgeAssurance} = useAgeAssuranceAPIContext() // init useEffect(() => { @@ -82,6 +87,7 @@ function InnerApp() { try { if (account) { await resumeSession(account) + await refreshAgeAssurance() } } catch (e) { logger.error(`session: resumeSession failed`, {message: e}) @@ -91,7 +97,7 @@ function InnerApp() { } const account = readLastActiveAccount() onLaunch(account) - }, [resumeSession]) + }, [resumeSession, refreshAgeAssurance]) useEffect(() => { return listenSessionDropped(() => { @@ -186,25 +192,27 @@ function App() { - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/src/logger/types.ts b/src/logger/types.ts index 88d8d9d93d..4743e866c4 100644 --- a/src/logger/types.ts +++ b/src/logger/types.ts @@ -12,6 +12,7 @@ export enum LogContext { ReportDialog = 'report-dialog', FeedFeedback = 'feed-feedback', PostSource = 'post-source', + AgeAssurance = 'age-assurance', /** * METRIC IS FOR INTERNAL USE ONLY, don't create any other loggers using this diff --git a/src/state/ageAssurance.tsx b/src/state/ageAssurance.tsx new file mode 100644 index 0000000000..14f8f60507 --- /dev/null +++ b/src/state/ageAssurance.tsx @@ -0,0 +1,100 @@ +import {createContext, useCallback, useContext, useMemo, useState} from 'react' + +import {wait} from '#/lib/async/wait' +import {isNetworkError} from '#/lib/strings/errors' +import {Logger} from '#/logger' +// import {useAgent} from '#/state/session' +import {useGeolocation} from '#/state/geolocation' + +const logger = Logger.create(Logger.Context.AgeAssurance) + +type TempAgeAssuranceState = { + updatedAt?: string + status: 'unknown' | 'pending' | 'assured' +} + +export type AgeAssuranceContextType = { + required: boolean + status: TempAgeAssuranceState['status'] +} + +export type AgeAssuranceAPIContextType = { + refresh: () => Promise +} + +const AgeAssuranceContext = createContext({ + required: false, + status: 'unknown', +}) + +const AgeAssuranceAPIContext = createContext({ + refresh: () => Promise.resolve(), +}) + +export function Provider({children}: {children: React.ReactNode}) { + // const agent = useAgent() + const {geolocation} = useGeolocation() + const [ageAssuranceState, setAgeAssuranceState] = + useState({ + status: 'unknown', + }) + + const refresh = useCallback(async () => { + try { + const {data} = await wait( + 200, + (() => ({ + data: { + updatedAt: undefined, + status: 'pending', + } as TempAgeAssuranceState, + }))(), + ) + + logger.debug(`refresh`, {data}) + + setAgeAssuranceState(data) + } catch (e) { + if (!isNetworkError(e)) { + logger.error(`ageAssurance: failed to refresh`, {safeMessage: e}) + } + } + }, [setAgeAssuranceState]) + + const ageAssuranceContext = useMemo(() => { + const {status} = ageAssuranceState + const ctx: AgeAssuranceContextType = { + required: Boolean( + geolocation?.isAgeRestrictedGeo && status !== 'assured', + ), + status, + } + + logger.debug(`context`, ctx) + + return ctx + }, [geolocation, ageAssuranceState]) + + const ageAssuranceAPIContext = useMemo( + () => ({ + refresh, + }), + [refresh], + ) + + return ( + + + {children} + + + ) +} + +export function useAgeAssuranceContext() { + return useContext(AgeAssuranceContext) +} + +export function useAgeAssuranceAPIContext() { + return useContext(AgeAssuranceAPIContext) +}