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)
+}