Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | 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 } = useAuth();
const segments = useSegments();
const navigationState = useRootNavigationState();
// Track if initial redirect was done
const hasInitialRedirect = useRef(false);
// Note: Token URL login feature not yet implemented
// Would need api.setToken() method and AuthContext.refreshAuth() call
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 <LoadingSpinner fullScreen message="Loading..." />;
}
return (
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
<View style={styles.webContainer}>
<View style={styles.mobileWrapper}>
<Stack screenOptions={{ headerShown: false }}>
<Stack.Screen name="(auth)" />
<Stack.Screen name="(tabs)" />
<Stack.Screen name="modal" options={{ presentation: 'modal', title: 'Modal' }} />
</Stack>
<StatusBar style="auto" />
</View>
</View>
</ThemeProvider>
);
}
export default function RootLayout() {
return (
<AuthProvider>
<BeneficiaryProvider>
<ToastProvider>
<RootLayoutNav />
</ToastProvider>
</BeneficiaryProvider>
</AuthProvider>
);
}
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
}
});
|