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
|
import React, { useEffect } from 'react';
import { Stack, useRouter, useSegments } from 'expo-router';
import { StatusBar } from 'expo-status-bar';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useColorScheme } from 'react-native';
import { Colors } from '../constants/Colors';
import { useAuthStore, setupAuthListener } from '../stores/authStore';
import { LoadingScreen } from '../components/LoadingScreen';
// Create a client
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 5000, // Data is fresh for 5 seconds
retry: 2, // Retry failed requests twice
refetchOnWindowFocus: false, // Don't refetch on app focus (mobile)
},
mutations: {
retry: 1,
},
},
});
/**
* Auth state handler component
* Redirects users based on authentication status
*/
function AuthStateHandler({ children }: { children: React.ReactNode }) {
const router = useRouter();
const segments = useSegments();
const session = useAuthStore((state) => state.session);
const isInitialized = useAuthStore((state) => state.isInitialized);
const initialize = useAuthStore((state) => state.initialize);
// Initialize auth state on mount
useEffect(() => {
initialize();
}, [initialize]);
// Setup auth listener on mount
useEffect(() => {
const unsubscribe = setupAuthListener();
return unsubscribe;
}, []);
// Handle auth-based routing
useEffect(() => {
if (!isInitialized) return;
const inAuthGroup = segments[0] === '(auth)';
const isAuthenticated = session !== null;
if (!isAuthenticated && !inAuthGroup) {
// Redirect to login if not authenticated and not already on auth screens
router.replace('/(auth)/login');
} else if (isAuthenticated && inAuthGroup) {
// Redirect to main app if authenticated and on auth screens
router.replace('/(tabs)');
}
}, [session, segments, isInitialized, router]);
// Show loading screen while initializing
if (!isInitialized) {
return <LoadingScreen message="Checking authentication..." />;
}
return <>{children}</>;
}
export default function RootLayout() {
const colorScheme = useColorScheme() ?? 'light';
const colors = Colors[colorScheme];
return (
<QueryClientProvider client={queryClient}>
<StatusBar style={colorScheme === 'dark' ? 'light' : 'dark'} />
<AuthStateHandler>
<Stack
screenOptions={{
headerStyle: {
backgroundColor: colors.background,
},
headerTintColor: colors.text,
headerTitleStyle: {
fontWeight: '600',
},
contentStyle: {
backgroundColor: colors.background,
},
}}
>
<Stack.Screen
name="(auth)"
options={{ headerShown: false }}
/>
<Stack.Screen
name="(tabs)"
options={{ headerShown: false }}
/>
<Stack.Screen
name="task/[id]"
options={{
presentation: 'card',
headerBackTitle: 'Back',
}}
/>
</Stack>
</AuthStateHandler>
</QueryClientProvider>
);
}
|