Move provider inside query provider

This commit is contained in:
Eric Bailey
2025-06-26 18:24:32 -05:00
parent 9144f61208
commit 13daf12c0c
4 changed files with 181 additions and 171 deletions
+69 -74
View File
@@ -26,10 +26,7 @@ import I18nProvider from '#/locale/i18nProvider'
import {logger} from '#/logger' import {logger} from '#/logger'
import {isAndroid, isIOS} from '#/platform/detection' import {isAndroid, isIOS} from '#/platform/detection'
import {Provider as A11yProvider} from '#/state/a11y' import {Provider as A11yProvider} from '#/state/a11y'
import { import {Provider as AgeAssuranceProvider} from '#/state/ageAssurance'
Provider as AgeAssuranceProvider,
useAgeAssuranceAPIContext,
} from '#/state/ageAssurance'
import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes' import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes'
import {Provider as DialogStateProvider} from '#/state/dialogs' import {Provider as DialogStateProvider} from '#/state/dialogs'
import {listenSessionDropped} from '#/state/events' import {listenSessionDropped} from '#/state/events'
@@ -100,7 +97,6 @@ function InnerApp() {
const theme = useColorModeTheme() const theme = useColorModeTheme()
const {_} = useLingui() const {_} = useLingui()
const hasCheckedReferrer = useStarterPackEntry() const hasCheckedReferrer = useStarterPackEntry()
const {refresh: refreshAgeAssurance} = useAgeAssuranceAPIContext()
// init // init
useEffect(() => { useEffect(() => {
@@ -108,7 +104,6 @@ function InnerApp() {
try { try {
if (account) { if (account) {
await resumeSession(account) await resumeSession(account)
await refreshAgeAssurance()
} else { } else {
await tryFetchGates(undefined, 'prefer-fresh-gates') await tryFetchGates(undefined, 'prefer-fresh-gates')
} }
@@ -120,7 +115,7 @@ function InnerApp() {
} }
const account = readLastActiveAccount() const account = readLastActiveAccount()
onLaunch(account) onLaunch(account)
}, [resumeSession, refreshAgeAssurance]) }, [resumeSession])
useEffect(() => { useEffect(() => {
return listenSessionDropped(() => { return listenSessionDropped(() => {
@@ -142,47 +137,49 @@ function InnerApp() {
// Resets the entire tree below when it changes: // Resets the entire tree below when it changes:
key={currentAccount?.did}> key={currentAccount?.did}>
<QueryProvider currentDid={currentAccount?.did}> <QueryProvider currentDid={currentAccount?.did}>
<ComposerProvider> <AgeAssuranceProvider>
<StatsigProvider> <ComposerProvider>
<MessagesProvider> <StatsigProvider>
{/* LabelDefsProvider MUST come before ModerationOptsProvider */} <MessagesProvider>
<LabelDefsProvider> {/* LabelDefsProvider MUST come before ModerationOptsProvider */}
<ModerationOptsProvider> <LabelDefsProvider>
<LoggedOutViewProvider> <ModerationOptsProvider>
<SelectedFeedProvider> <LoggedOutViewProvider>
<HiddenRepliesProvider> <SelectedFeedProvider>
<HomeBadgeProvider> <HiddenRepliesProvider>
<UnreadNotifsProvider> <HomeBadgeProvider>
<BackgroundNotificationPreferencesProvider> <UnreadNotifsProvider>
<MutedThreadsProvider> <BackgroundNotificationPreferencesProvider>
<ProgressGuideProvider> <MutedThreadsProvider>
<ServiceAccountManager> <ProgressGuideProvider>
<HideBottomBarBorderProvider> <ServiceAccountManager>
<GestureHandlerRootView <HideBottomBarBorderProvider>
style={s.h100pct}> <GestureHandlerRootView
<GlobalGestureEventsProvider> style={s.h100pct}>
<IntentDialogProvider> <GlobalGestureEventsProvider>
<TestCtrls /> <IntentDialogProvider>
<Shell /> <TestCtrls />
<NuxDialogs /> <Shell />
</IntentDialogProvider> <NuxDialogs />
</GlobalGestureEventsProvider> </IntentDialogProvider>
</GestureHandlerRootView> </GlobalGestureEventsProvider>
</HideBottomBarBorderProvider> </GestureHandlerRootView>
</ServiceAccountManager> </HideBottomBarBorderProvider>
</ProgressGuideProvider> </ServiceAccountManager>
</MutedThreadsProvider> </ProgressGuideProvider>
</BackgroundNotificationPreferencesProvider> </MutedThreadsProvider>
</UnreadNotifsProvider> </BackgroundNotificationPreferencesProvider>
</HomeBadgeProvider> </UnreadNotifsProvider>
</HiddenRepliesProvider> </HomeBadgeProvider>
</SelectedFeedProvider> </HiddenRepliesProvider>
</LoggedOutViewProvider> </SelectedFeedProvider>
</ModerationOptsProvider> </LoggedOutViewProvider>
</LabelDefsProvider> </ModerationOptsProvider>
</MessagesProvider> </LabelDefsProvider>
</StatsigProvider> </MessagesProvider>
</ComposerProvider> </StatsigProvider>
</ComposerProvider>
</AgeAssuranceProvider>
</QueryProvider> </QueryProvider>
</React.Fragment> </React.Fragment>
</VideoVolumeProvider> </VideoVolumeProvider>
@@ -216,32 +213,30 @@ function App() {
<A11yProvider> <A11yProvider>
<KeyboardControllerProvider> <KeyboardControllerProvider>
<SessionProvider> <SessionProvider>
<AgeAssuranceProvider> <PrefsStateProvider>
<PrefsStateProvider> <I18nProvider>
<I18nProvider> <ShellStateProvider>
<ShellStateProvider> <InvitesStateProvider>
<InvitesStateProvider> <ModalStateProvider>
<ModalStateProvider> <DialogStateProvider>
<DialogStateProvider> <LightboxStateProvider>
<LightboxStateProvider> <PortalProvider>
<PortalProvider> <BottomSheetProvider>
<BottomSheetProvider> <StarterPackProvider>
<StarterPackProvider> <SafeAreaProvider
<SafeAreaProvider initialMetrics={initialWindowMetrics}>
initialMetrics={initialWindowMetrics}> <InnerApp />
<InnerApp /> </SafeAreaProvider>
</SafeAreaProvider> </StarterPackProvider>
</StarterPackProvider> </BottomSheetProvider>
</BottomSheetProvider> </PortalProvider>
</PortalProvider> </LightboxStateProvider>
</LightboxStateProvider> </DialogStateProvider>
</DialogStateProvider> </ModalStateProvider>
</ModalStateProvider> </InvitesStateProvider>
</InvitesStateProvider> </ShellStateProvider>
</ShellStateProvider> </I18nProvider>
</I18nProvider> </PrefsStateProvider>
</PrefsStateProvider>
</AgeAssuranceProvider>
</SessionProvider> </SessionProvider>
</KeyboardControllerProvider> </KeyboardControllerProvider>
</A11yProvider> </A11yProvider>
+59 -62
View File
@@ -17,7 +17,6 @@ import {logger} from '#/logger'
import {Provider as A11yProvider} from '#/state/a11y' import {Provider as A11yProvider} from '#/state/a11y'
import { import {
Provider as AgeAssuranceProvider, Provider as AgeAssuranceProvider,
useAgeAssuranceAPIContext,
} from '#/state/ageAssurance' } from '#/state/ageAssurance'
import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes' import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes'
import {Provider as DialogStateProvider} from '#/state/dialogs' import {Provider as DialogStateProvider} from '#/state/dialogs'
@@ -79,7 +78,6 @@ function InnerApp() {
const theme = useColorModeTheme() const theme = useColorModeTheme()
const {_} = useLingui() const {_} = useLingui()
const hasCheckedReferrer = useStarterPackEntry() const hasCheckedReferrer = useStarterPackEntry()
const {refresh: refreshAgeAssurance} = useAgeAssuranceAPIContext()
// init // init
useEffect(() => { useEffect(() => {
@@ -87,7 +85,6 @@ function InnerApp() {
try { try {
if (account) { if (account) {
await resumeSession(account) await resumeSession(account)
await refreshAgeAssurance()
} }
} catch (e) { } catch (e) {
logger.error(`session: resumeSession failed`, {message: e}) logger.error(`session: resumeSession failed`, {message: e})
@@ -97,7 +94,7 @@ function InnerApp() {
} }
const account = readLastActiveAccount() const account = readLastActiveAccount()
onLaunch(account) onLaunch(account)
}, [resumeSession, refreshAgeAssurance]) }, [resumeSession])
useEffect(() => { useEffect(() => {
return listenSessionDropped(() => { return listenSessionDropped(() => {
@@ -122,43 +119,45 @@ function InnerApp() {
// Resets the entire tree below when it changes: // Resets the entire tree below when it changes:
key={currentAccount?.did}> key={currentAccount?.did}>
<QueryProvider currentDid={currentAccount?.did}> <QueryProvider currentDid={currentAccount?.did}>
<ComposerProvider> <AgeAssuranceProvider>
<StatsigProvider> <ComposerProvider>
<MessagesProvider> <StatsigProvider>
{/* LabelDefsProvider MUST come before ModerationOptsProvider */} <MessagesProvider>
<LabelDefsProvider> {/* LabelDefsProvider MUST come before ModerationOptsProvider */}
<ModerationOptsProvider> <LabelDefsProvider>
<LoggedOutViewProvider> <ModerationOptsProvider>
<SelectedFeedProvider> <LoggedOutViewProvider>
<HiddenRepliesProvider> <SelectedFeedProvider>
<HomeBadgeProvider> <HiddenRepliesProvider>
<UnreadNotifsProvider> <HomeBadgeProvider>
<BackgroundNotificationPreferencesProvider> <UnreadNotifsProvider>
<MutedThreadsProvider> <BackgroundNotificationPreferencesProvider>
<SafeAreaProvider> <MutedThreadsProvider>
<ProgressGuideProvider> <SafeAreaProvider>
<ServiceConfigProvider> <ProgressGuideProvider>
<HideBottomBarBorderProvider> <ServiceConfigProvider>
<IntentDialogProvider> <HideBottomBarBorderProvider>
<Shell /> <IntentDialogProvider>
<NuxDialogs /> <Shell />
</IntentDialogProvider> <NuxDialogs />
</HideBottomBarBorderProvider> </IntentDialogProvider>
</ServiceConfigProvider> </HideBottomBarBorderProvider>
</ProgressGuideProvider> </ServiceConfigProvider>
</SafeAreaProvider> </ProgressGuideProvider>
</MutedThreadsProvider> </SafeAreaProvider>
</BackgroundNotificationPreferencesProvider> </MutedThreadsProvider>
</UnreadNotifsProvider> </BackgroundNotificationPreferencesProvider>
</HomeBadgeProvider> </UnreadNotifsProvider>
</HiddenRepliesProvider> </HomeBadgeProvider>
</SelectedFeedProvider> </HiddenRepliesProvider>
</LoggedOutViewProvider> </SelectedFeedProvider>
</ModerationOptsProvider> </LoggedOutViewProvider>
</LabelDefsProvider> </ModerationOptsProvider>
</MessagesProvider> </LabelDefsProvider>
</StatsigProvider> </MessagesProvider>
</ComposerProvider> </StatsigProvider>
</ComposerProvider>
</AgeAssuranceProvider>
</QueryProvider> </QueryProvider>
<ToastContainer /> <ToastContainer />
</React.Fragment> </React.Fragment>
@@ -192,27 +191,25 @@ function App() {
<GeolocationProvider> <GeolocationProvider>
<A11yProvider> <A11yProvider>
<SessionProvider> <SessionProvider>
<AgeAssuranceProvider> <PrefsStateProvider>
<PrefsStateProvider> <I18nProvider>
<I18nProvider> <ShellStateProvider>
<ShellStateProvider> <InvitesStateProvider>
<InvitesStateProvider> <ModalStateProvider>
<ModalStateProvider> <DialogStateProvider>
<DialogStateProvider> <LightboxStateProvider>
<LightboxStateProvider> <PortalProvider>
<PortalProvider> <StarterPackProvider>
<StarterPackProvider> <InnerApp />
<InnerApp /> </StarterPackProvider>
</StarterPackProvider> </PortalProvider>
</PortalProvider> </LightboxStateProvider>
</LightboxStateProvider> </DialogStateProvider>
</DialogStateProvider> </ModalStateProvider>
</ModalStateProvider> </InvitesStateProvider>
</InvitesStateProvider> </ShellStateProvider>
</ShellStateProvider> </I18nProvider>
</I18nProvider> </PrefsStateProvider>
</PrefsStateProvider>
</AgeAssuranceProvider>
</SessionProvider> </SessionProvider>
</A11yProvider> </A11yProvider>
</GeolocationProvider> </GeolocationProvider>
@@ -1,13 +1,13 @@
import {useAgeAssuranceContext} from '#/state/ageAssurance' import {useAgeAssuranceContext} from '#/state/ageAssurance'
export function True({children}: {children: React.ReactNode}) { export function True({children}: {children: React.ReactNode}) {
const {isAgeRestricted} = useAgeAssuranceContext() const {isLoaded, isAgeRestricted} = useAgeAssuranceContext()
return isAgeRestricted ? children : null return isLoaded && isAgeRestricted ? children : null
} }
export function False({children}: {children: React.ReactNode}) { export function False({children}: {children: React.ReactNode}) {
const {isAgeRestricted} = useAgeAssuranceContext() const {isLoaded, isAgeRestricted} = useAgeAssuranceContext()
return !isAgeRestricted ? children : null return isLoaded && !isAgeRestricted ? children : null
} }
export const IsAgeRestricted = { export const IsAgeRestricted = {
+49 -31
View File
@@ -1,12 +1,21 @@
import {createContext, useCallback, useContext, useMemo, useState} from 'react' import {createContext, useContext, useMemo} from 'react'
import {
// useQueryClient,
type QueryObserverBaseResult,
useQuery,
} from '@tanstack/react-query'
import {wait} from '#/lib/async/wait' import {wait} from '#/lib/async/wait'
import {isNetworkError} from '#/lib/strings/errors' import {isNetworkError} from '#/lib/strings/errors'
import {Logger} from '#/logger' import {Logger} from '#/logger'
// import {useAgent} from '#/state/session'
import {useGeolocation} from '#/state/geolocation' import {useGeolocation} from '#/state/geolocation'
import {useAgent} from '#/state/session'
const logger = Logger.create(Logger.Context.AgeAssurance) const logger = Logger.create(Logger.Context.AgeAssurance)
const ageAssuranceQueryKey = ['ageAssurance'] as const
const DEFAULT_AGE_ASSURANCE_STATE: TempAgeAssuranceState = {
status: 'unknown',
}
type TempAgeAssuranceState = { type TempAgeAssuranceState = {
lastInitiatedAt?: string lastInitiatedAt?: string
@@ -14,6 +23,7 @@ type TempAgeAssuranceState = {
} }
export type AgeAssuranceContextType = { export type AgeAssuranceContextType = {
isLoaded: boolean
/** /**
* Whether the current user is age-restricted based on their geolocation and * Whether the current user is age-restricted based on their geolocation and
* age assurance state retrieved from the server. * age assurance state retrieved from the server.
@@ -37,10 +47,11 @@ export type AgeAssuranceAPIContextType = {
/** /**
* Refreshes the age assurance state by fetching it from the server. * Refreshes the age assurance state by fetching it from the server.
*/ */
refresh: () => Promise<void> refetch: QueryObserverBaseResult['refetch']
} }
const AgeAssuranceContext = createContext<AgeAssuranceContextType>({ const AgeAssuranceContext = createContext<AgeAssuranceContextType>({
isLoaded: false,
isAgeRestricted: false, isAgeRestricted: false,
status: 'unknown', status: 'unknown',
lastInitiatedAt: undefined, lastInitiatedAt: undefined,
@@ -48,42 +59,49 @@ const AgeAssuranceContext = createContext<AgeAssuranceContextType>({
}) })
const AgeAssuranceAPIContext = createContext<AgeAssuranceAPIContextType>({ const AgeAssuranceAPIContext = createContext<AgeAssuranceAPIContextType>({
refresh: () => Promise.resolve(), // @ts-ignore
refetch: () => Promise.resolve(),
}) })
export function Provider({children}: {children: React.ReactNode}) { export function Provider({children}: {children: React.ReactNode}) {
// const agent = useAgent() // const qc = useQueryClient()
const agent = useAgent()
const {geolocation} = useGeolocation() const {geolocation} = useGeolocation()
const [ageAssuranceState, setAgeAssuranceState] =
useState<TempAgeAssuranceState>({
status: 'unknown',
})
const refresh = useCallback(async () => { const {data, refetch} = useQuery({
try { queryKey: ageAssuranceQueryKey,
const {data} = await wait( async queryFn() {
200, try {
(() => ({ const {data} = await wait(
data: { 1e3,
lastInitiatedAt: undefined, (() => ({
status: 'unknown', data: {
} as TempAgeAssuranceState, lastInitiatedAt: new Date().toISOString(),
}))(), status: 'assured',
) } as TempAgeAssuranceState,
}))(),
)
logger.debug(`refresh`, {data}) logger.debug(`fetch`, {
data,
account: agent.session?.did,
})
setAgeAssuranceState(data) return data
} catch (e) { } catch (e) {
if (!isNetworkError(e)) { if (!isNetworkError(e)) {
logger.error(`ageAssurance: failed to refresh`, {safeMessage: e}) logger.error(`ageAssurance: failed to fetch`, {safeMessage: e})
}
return DEFAULT_AGE_ASSURANCE_STATE
} }
} },
}, [setAgeAssuranceState]) })
const ageAssuranceContext = useMemo<AgeAssuranceContextType>(() => { const ageAssuranceContext = useMemo<AgeAssuranceContextType>(() => {
const {status, lastInitiatedAt} = ageAssuranceState const {status, lastInitiatedAt} = data || DEFAULT_AGE_ASSURANCE_STATE
const ctx: AgeAssuranceContextType = { const ctx: AgeAssuranceContextType = {
isLoaded: !!data,
status, status,
lastInitiatedAt, lastInitiatedAt,
hasInitiated: !!lastInitiatedAt, hasInitiated: !!lastInitiatedAt,
@@ -95,13 +113,13 @@ export function Provider({children}: {children: React.ReactNode}) {
logger.debug(`context`, ctx) logger.debug(`context`, ctx)
return ctx return ctx
}, [geolocation, ageAssuranceState]) }, [geolocation, data])
const ageAssuranceAPIContext = useMemo<AgeAssuranceAPIContextType>( const ageAssuranceAPIContext = useMemo<AgeAssuranceAPIContextType>(
() => ({ () => ({
refresh, refetch,
}), }),
[refresh], [refetch],
) )
return ( return (