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>
);
}