import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native'; import { Stack, router, useRootNavigationState, useSegments } from 'expo-router'; import * as SplashScreen from 'expo-splash-screen'; import { StatusBar } from 'expo-status-bar'; import { useEffect, useRef } from 'react'; // import 'react-native-reanimated'; // Often causes issues on web if not configured perfectly, optional here import { Platform, StyleSheet, View } from 'react-native'; import { LoadingSpinner } from '@/components/ui/LoadingSpinner'; import { ToastProvider } from '@/components/ui/Toast'; import { AuthProvider, useAuth } from '@/contexts/AuthContext'; import { BeneficiaryProvider } from '@/contexts/BeneficiaryContext'; import { useColorScheme } from '@/hooks/use-color-scheme'; // Polyfill for $ to prevent ReferenceError: Cannot access '$' before initialization // This is a workaround for some web-specific bundling issues in this project. if (Platform.OS === 'web' && typeof window !== 'undefined') { // @ts-ignore if (typeof window.$ === 'undefined') { // @ts-ignore window.$ = undefined; } } // Prevent auto-hide, ignore errors if splash not available SplashScreen.preventAutoHideAsync().catch(() => { }); let splashHidden = false; function RootLayoutNav() { const colorScheme = useColorScheme(); const { isAuthenticated, isInitializing, setToken } = useAuth(); const segments = useSegments(); const navigationState = useRootNavigationState(); // Track if initial redirect was done const hasInitialRedirect = useRef(false); useEffect(() => { // Check for token in URL query params (Web only feature) if (Platform.OS === 'web') { const url = new URL(window.location.href); const tokenParam = url.searchParams.get('token'); if (tokenParam) { console.log('[Layout] Found token in URL, attempting login...'); // Need a way to set token in AuthContext. // Since useAuth gives us setToken (assuming it does, or login logic), we can use it. // If AuthContext doesn't expose setToken directly, we might need to modify AuthContext // or use specific login method. Assuming 'api.setToken' works and then we refresh auth. // actually useAuth usually exposes a way. // Let's assume for a moment we can use the injected setToken (if I added it) or just use api. // For now, let's try to set it via API and reload user? // Actually, best is if AuthContext handles it. // But let's look at AuthContext later. For now I will try to use the api directly to verify constraint. const handleToken = async () => { await setToken(tokenParam); // Refresh the page to clear the token from URL window.location.href = window.location.origin + window.location.pathname; }; handleToken(); } } }, []); useEffect(() => { if (!navigationState?.key) return; if (isInitializing) return; if (!splashHidden) { splashHidden = true; SplashScreen.hideAsync().catch(() => { }); } const inAuthGroup = segments[0] === '(auth)'; if (!hasInitialRedirect.current) { hasInitialRedirect.current = true; // URL Param Auth Check (Simple version) if (Platform.OS === 'web') { const url = new URL(window.location.href); const token = url.searchParams.get('token'); if (token) { // If we have a token, we might be authenticated now (race condition with AuthProvider). // If isAuthenticated is true, good. If not, maybe we need to wait. // But for now, let's allow the flow. } } if (!isAuthenticated && !inAuthGroup) { router.replace('/(auth)/login'); return; } } }, [isAuthenticated, isInitializing, navigationState?.key]); if (isInitializing) { return ; } return ( ); } export default function RootLayout() { return ( ); } const styles = StyleSheet.create({ webContainer: { flex: 1, backgroundColor: '#e5e5e5', // Light gray background for desktop alignItems: 'center', justifyContent: 'center', }, mobileWrapper: { flex: 1, width: '100%', maxWidth: 430, // Mobile width constraint backgroundColor: '#fff', shadowColor: '#000', shadowOffset: { width: 0, height: 2, }, shadowOpacity: 0.25, shadowRadius: 3.84, elevation: 5, overflow: 'hidden', // Clip content to rounded corners if we want } });