import React, { useEffect, useRef, useState } from 'react'; import { AppState, AppStateStatus, Platform, View, ActivityIndicator } from 'react-native'; import { Stack, useRouter } from 'expo-router'; import { StatusBar } from 'expo-status-bar'; import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { SafeAreaProvider } from 'react-native-safe-area-context'; import { PaperProvider } from 'react-native-paper'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import * as Notifications from 'expo-notifications'; import * as SystemUI from 'expo-system-ui'; import { registerNotificationPresentationHandler } from '../src/services/notificationPreferences'; import { ThemeBootstrap, useAppColors, usePaperThemeFromStore, useResolvedColorScheme, } from '../src/theme'; import { AppBackButton } from '../src/components/common'; import AppPromptBar from '../src/components/common/AppPromptBar'; import AppDialogHost from '../src/components/common/AppDialogHost'; import { installAlertOverride } from '../src/services/alertOverride'; import { useAuthStore } from '../src/stores'; registerNotificationPresentationHandler(); const queryClient = new QueryClient({ defaultOptions: { queries: { retry: 2, staleTime: 5 * 60 * 1000, }, }, }); installAlertOverride(); if (Platform.OS === 'web' && typeof document !== 'undefined') { const style = document.createElement('style'); style.textContent = ` input:focus, textarea:focus, select:focus { outline: none !important; outline-width: 0 !important; box-shadow: none !important; } input:focus-visible, textarea:focus-visible { outline: none !important; } *:focus { outline: none !important; } *:focus-visible { outline: none !important; } `; document.head.appendChild(style); } function SystemChrome() { const colors = useAppColors(); useEffect(() => { void SystemUI.setBackgroundColorAsync(colors.background.default); if (Platform.OS === 'web' && typeof document !== 'undefined') { const meta = document.querySelector('meta[name="theme-color"]'); if (meta) { meta.setAttribute('content', colors.background.default); } } }, [colors.background.default]); return null; } function SessionGate({ children }: { children: React.ReactNode }) { const [ready, setReady] = useState(false); const fetchCurrentUser = useAuthStore((s) => s.fetchCurrentUser); const colors = useAppColors(); useEffect(() => { fetchCurrentUser().finally(() => setReady(true)); }, [fetchCurrentUser]); if (!ready) { return ( ); } return <>{children}; } function NotificationBootstrap() { const appState = useRef(AppState.currentState); const notificationResponseListener = useRef(null); useEffect(() => { const initNotifications = async () => { const { loadNotificationPreferences } = await import('../src/services/notificationPreferences'); await loadNotificationPreferences(); const { systemNotificationService } = await import('../src/services/systemNotificationService'); await systemNotificationService.initialize(); const { initBackgroundService } = await import('../src/services/backgroundService'); await initBackgroundService(); const subscription = AppState.addEventListener('change', (nextAppState) => { if (appState.current.match(/inactive|background/) && nextAppState === 'active') { systemNotificationService.clearBadge(); } appState.current = nextAppState; }); notificationResponseListener.current = Notifications.addNotificationResponseReceivedListener( (response) => { void response.notification.request.content.data; } ); const notificationReceivedSubscription = Notifications.addNotificationReceivedListener( (notification) => { void notification; } ); return () => { subscription.remove(); notificationResponseListener.current?.remove(); notificationReceivedSubscription.remove(); }; }; initNotifications(); }, []); return null; } function ThemedStack() { const router = useRouter(); const colors = useAppColors(); const resolved = useResolvedColorScheme(); return ( <> router.back()} />, }} /> router.back()} />, }} /> ); } function ThemedProviders({ children }: { children: React.ReactNode }) { const theme = usePaperThemeFromStore(); return {children}; } export default function RootLayout() { return ( ); }