managarten/picture/apps/mobile/app/_layout.tsx
Till-JS c712a2504a feat: integrate uload and picture, unify package naming
- Add uload project with apps/web structure
  - Reorganize from flat to monorepo structure
  - Remove PocketBase binary and local data
  - Update to pnpm and @uload/web namespace

- Add picture project to monorepo
  - Remove embedded git repository

- Unify all package names to @{project}/{app} schema:
  - @maerchenzauber/* (was @storyteller/*)
  - @manacore/* (was manacore-*, manacore)
  - @manadeck/* (was web, backend, manadeck)
  - @memoro/* (was memoro-web, landing, memoro)
  - @picture/* (already unified)
  - @uload/web

- Add convenient dev scripts for all apps:
  - pnpm dev:{project}:web
  - pnpm dev:{project}:landing
  - pnpm dev:{project}:mobile
  - pnpm dev:{project}:backend

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 04:00:36 +01:00

120 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import '../global.css';
import { useEffect, useState } from 'react';
import { Platform, View, AppState } from 'react-native';
import { Stack, useRouter, useSegments } from 'expo-router';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { AuthProvider, useAuth } from '~/contexts/AuthContext';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { preloadModels } from '~/store/modelStore';
import { ErrorBoundary } from '~/components/ErrorBoundary';
import { ThemeProvider } from '~/contexts/ThemeContext';
import { logger } from '~/utils/logger';
export const unstable_settings = {
// Ensure that reloading on `/modal` keeps a back button present.
initialRouteName: '(tabs)',
};
function RootLayoutNav() {
const { user, loading } = useAuth();
const segments = useSegments();
const router = useRouter();
const [isNavigating, setIsNavigating] = useState(false);
useEffect(() => {
// Prevent navigation during loading or if already navigating
if (loading || isNavigating) {
console.log('⏳ Skipping navigation:', { loading, isNavigating });
return;
}
const inAuthGroup = segments[0] === '(auth)';
console.log('🔄 Auth routing check:', {
hasUser: !!user,
userId: user?.id,
currentSegment: segments[0],
inAuthGroup
});
// Use requestAnimationFrame to defer navigation and prevent timing issues
const navigationTimeout = requestAnimationFrame(() => {
try {
if (!user && !inAuthGroup) {
// Redirect to login if not authenticated
console.log('🔒 Redirecting to login...');
setIsNavigating(true);
router.replace('/(auth)/login');
setIsNavigating(false);
} else if (user && inAuthGroup) {
// Redirect to main app if authenticated
console.log('✅ Redirecting to tabs...');
setIsNavigating(true);
router.replace('/(tabs)');
setIsNavigating(false);
// TEMPORARY FIX: Disabled preload to debug crash
// TODO: Re-enable with proper error handling after navigation completes
// setTimeout(() => {
// preloadModels().catch(err => {
// logger.error('Failed to preload models:', err);
// });
// }, 1000);
} else {
console.log(' No navigation needed');
}
} catch (error) {
logger.error('Navigation error:', error);
setIsNavigating(false);
}
});
return () => {
cancelAnimationFrame(navigationTimeout);
};
}, [user, segments, loading, isNavigating]);
return (
<Stack>
<Stack.Screen name="(auth)/login" options={{ headerShown: false }} />
<Stack.Screen name="(auth)/register" options={{ headerShown: false }} />
<Stack.Screen name="(auth)/reset-password" options={{ headerShown: false }} />
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
<Stack.Screen name="modal" options={{ presentation: 'modal' }} />
</Stack>
);
}
export default function RootLayout() {
// For web, ensure the app fills the viewport
if (Platform.OS === 'web') {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<ThemeProvider>
<ErrorBoundary>
<View style={{ flex: 1, backgroundColor: '#000000' }}>
<AuthProvider>
<RootLayoutNav />
</AuthProvider>
</View>
</ErrorBoundary>
</ThemeProvider>
</GestureHandlerRootView>
);
}
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<ThemeProvider>
<ErrorBoundary>
<SafeAreaProvider>
<AuthProvider>
<RootLayoutNav />
</AuthProvider>
</SafeAreaProvider>
</ErrorBoundary>
</ThemeProvider>
</GestureHandlerRootView>
);
}