/** * @ai-summary Main app component with routing and mobile navigation */ import React, { useState, useEffect, useTransition, useCallback, lazy } from 'react'; import { useQueryClient } from '@tanstack/react-query'; import { Routes, Route, Navigate, useLocation } from 'react-router-dom'; import { useAuth0 } from '@auth0/auth0-react'; import { useIsAuthInitialized } from './core/auth/auth-gate'; import { motion, AnimatePresence } from 'framer-motion'; import { ThemeProvider } from './shared-minimal/theme/ThemeContext'; import { Layout } from './components/Layout'; import { UnitsProvider } from './core/units/UnitsContext'; // Lazy load route components for better initial bundle size const VehiclesPage = lazy(() => import('./features/vehicles/pages/VehiclesPage').then(m => ({ default: m.VehiclesPage }))); const VehicleDetailPage = lazy(() => import('./features/vehicles/pages/VehicleDetailPage').then(m => ({ default: m.VehicleDetailPage }))); const SettingsPage = lazy(() => import('./pages/SettingsPage').then(m => ({ default: m.SettingsPage }))); const SecuritySettingsPage = lazy(() => import('./pages/SecuritySettingsPage').then(m => ({ default: m.SecuritySettingsPage }))); const FuelLogsPage = lazy(() => import('./features/fuel-logs/pages/FuelLogsPage').then(m => ({ default: m.FuelLogsPage }))); const DocumentsPage = lazy(() => import('./features/documents/pages/DocumentsPage').then(m => ({ default: m.DocumentsPage }))); const DocumentDetailPage = lazy(() => import('./features/documents/pages/DocumentDetailPage').then(m => ({ default: m.DocumentDetailPage }))); const MaintenancePage = lazy(() => import('./features/maintenance/pages/MaintenancePage').then(m => ({ default: m.MaintenancePage }))); const StationsPage = lazy(() => import('./features/stations/pages/StationsPage').then(m => ({ default: m.StationsPage }))); const StationsMobileScreen = lazy(() => import('./features/stations/mobile/StationsMobileScreen').then(m => ({ default: m.default }))); const VehiclesMobileScreen = lazy(() => import('./features/vehicles/mobile/VehiclesMobileScreen').then(m => ({ default: m.VehiclesMobileScreen }))); const VehicleDetailMobile = lazy(() => import('./features/vehicles/mobile/VehicleDetailMobile').then(m => ({ default: m.VehicleDetailMobile }))); const DocumentsMobileScreen = lazy(() => import('./features/documents/mobile/DocumentsMobileScreen')); // Admin pages (lazy-loaded) const AdminUsersPage = lazy(() => import('./pages/admin/AdminUsersPage').then(m => ({ default: m.AdminUsersPage }))); const AdminCatalogPage = lazy(() => import('./pages/admin/AdminCatalogPage').then(m => ({ default: m.AdminCatalogPage }))); const AdminEmailTemplatesPage = lazy(() => import('./pages/admin/AdminEmailTemplatesPage').then(m => ({ default: m.AdminEmailTemplatesPage }))); const AdminBackupPage = lazy(() => import('./pages/admin/AdminBackupPage').then(m => ({ default: m.AdminBackupPage }))); // Admin mobile screens (lazy-loaded) const AdminUsersMobileScreen = lazy(() => import('./features/admin/mobile/AdminUsersMobileScreen').then(m => ({ default: m.AdminUsersMobileScreen }))); const AdminCatalogMobileScreen = lazy(() => import('./features/admin/mobile/AdminCatalogMobileScreen').then(m => ({ default: m.AdminCatalogMobileScreen }))); const AdminEmailTemplatesMobileScreen = lazy(() => import('./features/admin/mobile/AdminEmailTemplatesMobileScreen')); const AdminBackupMobileScreen = lazy(() => import('./features/admin/mobile/AdminBackupMobileScreen')); // Admin Community Stations (lazy-loaded) const AdminCommunityStationsPage = lazy(() => import('./features/admin/pages/AdminCommunityStationsPage').then(m => ({ default: m.AdminCommunityStationsPage }))); const AdminCommunityStationsMobileScreen = lazy(() => import('./features/admin/mobile/AdminCommunityStationsMobileScreen').then(m => ({ default: m.AdminCommunityStationsMobileScreen }))); // Auth pages (lazy-loaded) const SignupPage = lazy(() => import('./features/auth/pages/SignupPage').then(m => ({ default: m.SignupPage }))); const VerifyEmailPage = lazy(() => import('./features/auth/pages/VerifyEmailPage').then(m => ({ default: m.VerifyEmailPage }))); const CallbackPage = lazy(() => import('./features/auth/pages/CallbackPage').then(m => ({ default: m.CallbackPage }))); const SignupMobileScreen = lazy(() => import('./features/auth/mobile/SignupMobileScreen').then(m => ({ default: m.SignupMobileScreen }))); const VerifyEmailMobileScreen = lazy(() => import('./features/auth/mobile/VerifyEmailMobileScreen').then(m => ({ default: m.VerifyEmailMobileScreen }))); const CallbackMobileScreen = lazy(() => import('./features/auth/mobile/CallbackMobileScreen').then(m => ({ default: m.CallbackMobileScreen }))); // Onboarding pages (lazy-loaded) const OnboardingPage = lazy(() => import('./features/onboarding/pages/OnboardingPage').then(m => ({ default: m.OnboardingPage }))); const OnboardingMobileScreen = lazy(() => import('./features/onboarding/mobile/OnboardingMobileScreen').then(m => ({ default: m.OnboardingMobileScreen }))); import { HomePage } from './pages/HomePage'; import { BottomNavigation } from './shared-minimal/components/mobile/BottomNavigation'; import { QuickAction } from './shared-minimal/components/mobile/quickActions'; import { HamburgerDrawer } from './shared-minimal/components/mobile/HamburgerDrawer'; import { GlassCard } from './shared-minimal/components/mobile/GlassCard'; import { RouteSuspense } from './components/SuspenseWrappers'; import { Vehicle } from './features/vehicles/types/vehicles.types'; import { FuelLogForm } from './features/fuel-logs/components/FuelLogForm'; import { FuelLogsList } from './features/fuel-logs/components/FuelLogsList'; import { FuelLogEditDialog } from './features/fuel-logs/components/FuelLogEditDialog'; import { useFuelLogs } from './features/fuel-logs/hooks/useFuelLogs'; import { FuelLogResponse, UpdateFuelLogRequest } from './features/fuel-logs/types/fuel-logs.types'; import { fuelLogsApi } from './features/fuel-logs/api/fuel-logs.api'; import { VehicleForm } from './features/vehicles/components/VehicleForm'; import { useOptimisticVehicles } from './features/vehicles/hooks/useOptimisticVehicles'; import { CreateVehicleRequest } from './features/vehicles/types/vehicles.types'; import { MobileSettingsScreen } from './features/settings/mobile/MobileSettingsScreen'; import { SecurityMobileScreen } from './features/settings/mobile/SecurityMobileScreen'; import { useNavigationStore, useUserStore } from './core/store'; import { useDataSync } from './core/hooks/useDataSync'; import { MobileDebugPanel } from './core/debug/MobileDebugPanel'; import { MobileErrorBoundary } from './core/error-boundaries/MobileErrorBoundary'; import { useLoginNotifications } from './features/notifications/hooks/useLoginNotifications'; // Hoisted mobile screen components to stabilize identity and prevent remounts const DashboardScreen: React.FC = () => (

Dashboard

Coming soon - Vehicle insights and analytics

); const LogFuelScreen: React.FC = () => { const queryClient = useQueryClient(); const [editingLog, setEditingLog] = useState(null); const { goBack, canGoBack, navigateToScreen } = useNavigationStore(); useEffect(() => { console.log('[LogFuelScreen] Mounted'); return () => console.log('[LogFuelScreen] Unmounted'); }, []); let fuelLogs: FuelLogResponse[] | undefined, isLoading: boolean | undefined, error: any; try { const hookResult = useFuelLogs(); fuelLogs = hookResult.fuelLogs; isLoading = hookResult.isLoading; error = hookResult.error; } catch (hookError) { console.error('[LogFuelScreen] Hook error:', hookError); error = hookError; } const handleEdit = (log: FuelLogResponse) => { if (!log || !log.id) { console.error('[LogFuelScreen] Invalid log data for edit:', log); return; } try { setEditingLog(log); } catch (error) { console.error('[LogFuelScreen] Error setting editing log:', error); } }; const handleDelete = async (_logId: string) => { try { queryClient.invalidateQueries({ queryKey: ['fuelLogs'] }); queryClient.invalidateQueries({ queryKey: ['fuelLogsStats'] }); } catch (error) { console.error('Failed to refresh fuel logs after delete:', error); } }; const handleSaveEdit = async (id: string, data: UpdateFuelLogRequest) => { try { await fuelLogsApi.update(id, data); queryClient.invalidateQueries({ queryKey: ['fuelLogs'] }); queryClient.invalidateQueries({ queryKey: ['fuelLogsStats'] }); setEditingLog(null); } catch (error) { console.error('Failed to update fuel log:', error); throw error; } }; const handleCloseEdit = () => setEditingLog(null); if (error) { return (

Failed to load fuel logs

); } if (isLoading === undefined) { return (
Initializing fuel logs...
); } return (
{ // Refresh dependent data try { queryClient.invalidateQueries({ queryKey: ['fuelLogs'] }); queryClient.invalidateQueries({ queryKey: ['fuelLogsStats'] }); } catch (error) { // Silently ignore cache invalidation errors } // Navigate back if we have history; otherwise go to Vehicles if (canGoBack()) { goBack(); } else { navigateToScreen('Vehicles', { source: 'fuel-log-added' }); } }} />
{isLoading ? (
Loading fuel logs...
) : ( )}
); }; interface AddVehicleScreenProps { onBack: () => void; onAdded: () => void; } const AddVehicleScreen: React.FC = ({ onBack, onAdded }) => { const { optimisticCreateVehicle } = useOptimisticVehicles([]); const handleCreateVehicle = async (data: CreateVehicleRequest) => { try { await optimisticCreateVehicle(data); onAdded(); } catch (error) { console.error('Failed to create vehicle:', error); } }; return (

Add Vehicle

); }; function App() { const { isLoading, isAuthenticated, user } = useAuth0(); const location = useLocation(); const isAuthGateReady = useIsAuthInitialized(); const [_isPending, startTransition] = useTransition(); console.log('[DEBUG App] Render check - isLoading:', isLoading, 'isAuthenticated:', isAuthenticated, 'isAuthGateReady:', isAuthGateReady); // Initialize data synchronization const { prefetchForNavigation } = useDataSync(); // Initialize login notifications useLoginNotifications(); // Enhanced navigation and user state management const { activeScreen, vehicleSubScreen, navigateToScreen, navigateToVehicleSubScreen, goBack, canGoBack, } = useNavigationStore(); const { setUserProfile } = useUserStore(); // Mobile mode detection - detect mobile screen size with responsive updates const [mobileMode, setMobileMode] = useState(() => { if (typeof window !== 'undefined') { return window.innerWidth <= 768; } return false; }); const [selectedVehicle, setSelectedVehicle] = useState(null); const [showAddVehicle, setShowAddVehicle] = useState(false); // Update mobile mode on window resize useEffect(() => { const checkMobileMode = () => { const isMobile = window.innerWidth <= 768 || /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); console.log('Window width:', window.innerWidth, 'User agent mobile:', /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent), 'Mobile mode:', isMobile); setMobileMode(isMobile); }; // Check on mount checkMobileMode(); window.addEventListener('resize', checkMobileMode); return () => window.removeEventListener('resize', checkMobileMode); }, []); // Global error suppression for Google Maps DOM conflicts useEffect(() => { const handleGlobalError = (event: ErrorEvent) => { const errorMsg = event.error?.message || event.message || ''; const isDomError = errorMsg.includes('removeChild') || errorMsg.includes('insertBefore') || errorMsg.includes('replaceChild') || event.error?.name === 'NotFoundError' || (event.error instanceof DOMException); if (isDomError) { // Suppress Google Maps DOM manipulation errors event.preventDefault(); event.stopPropagation(); console.debug('[App] Suppressed harmless Google Maps DOM error'); } }; const handleGlobalRejection = (event: PromiseRejectionEvent) => { const errorMsg = event.reason?.message || String(event.reason) || ''; const isDomError = errorMsg.includes('removeChild') || errorMsg.includes('insertBefore') || errorMsg.includes('replaceChild') || event.reason?.name === 'NotFoundError' || (event.reason instanceof DOMException); if (isDomError) { event.preventDefault(); console.debug('[App] Suppressed harmless Google Maps promise rejection'); } }; window.addEventListener('error', handleGlobalError, true); // Use capture phase window.addEventListener('unhandledrejection', handleGlobalRejection); return () => { window.removeEventListener('error', handleGlobalError, true); window.removeEventListener('unhandledrejection', handleGlobalRejection); }; }, []); // Update user profile when authenticated useEffect(() => { if (isAuthenticated && user) { setUserProfile(user); } }, [isAuthenticated, user, setUserProfile]); // Handle mobile back button and navigation errors useEffect(() => { const handlePopState = (event: PopStateEvent) => { event.preventDefault(); if (canGoBack() && mobileMode) { goBack(); } }; if (mobileMode) { window.addEventListener('popstate', handlePopState); return () => window.removeEventListener('popstate', handlePopState); } return undefined; }, [goBack, canGoBack, mobileMode]); // Menu state const [hamburgerOpen, setHamburgerOpen] = useState(false); // Quick action handler const handleQuickAction = useCallback((action: QuickAction) => { switch (action) { case 'log-fuel': navigateToScreen('Log Fuel', { source: 'quick-action' }); break; case 'add-vehicle': setShowAddVehicle(true); navigateToScreen('Vehicles', { source: 'quick-action' }); navigateToVehicleSubScreen('add', undefined, { source: 'quick-action' }); break; case 'add-document': navigateToScreen('Documents', { source: 'quick-action' }); break; case 'add-maintenance': // Navigate to maintenance or open form (future implementation) navigateToScreen('Vehicles', { source: 'quick-action' }); break; } }, [navigateToScreen, navigateToVehicleSubScreen]); console.log('MotoVaultPro status:', { isLoading, isAuthenticated, mobileMode, activeScreen, vehicleSubScreen, userAgent: navigator.userAgent }); const isGarageRoute = location.pathname === '/garage' || location.pathname.startsWith('/garage/'); const isCallbackRoute = location.pathname === '/callback'; const isSignupRoute = location.pathname === '/signup'; const isVerifyEmailRoute = location.pathname === '/verify-email'; const isOnboardingRoute = location.pathname === '/onboarding'; const isAuthRoute = isSignupRoute || isVerifyEmailRoute || isOnboardingRoute; const shouldShowHomePage = !isGarageRoute && !isCallbackRoute && !isAuthRoute; // Enhanced navigation handlers for mobile const handleVehicleSelect = useCallback((vehicle: Vehicle) => { setSelectedVehicle(vehicle); navigateToVehicleSubScreen('detail', vehicle.id, { source: 'vehicle-list' }); }, [navigateToVehicleSubScreen]); const handleAddVehicle = useCallback(() => { setShowAddVehicle(true); navigateToVehicleSubScreen('add', undefined, { source: 'vehicle-list' }); }, [navigateToVehicleSubScreen]); const handleBackToList = useCallback(() => { setSelectedVehicle(null); setShowAddVehicle(false); navigateToVehicleSubScreen('list', undefined, { source: 'back-navigation' }); }, [navigateToVehicleSubScreen]); const handleVehicleAdded = useCallback(() => { setShowAddVehicle(false); navigateToVehicleSubScreen('list', undefined, { source: 'vehicle-added' }); }, [navigateToVehicleSubScreen]); // Enhanced debug component const DebugInfo = () => ( ); // Mobile settings now uses the dedicated MobileSettingsScreen component const SettingsScreen = MobileSettingsScreen; if (isLoading) { if (mobileMode) { return (
Loading...
); } return (
Loading...
); } // Callback route requires authentication - handled by CallbackPage component if (isCallbackRoute && isAuthenticated) { return (
Processing login...
}> {mobileMode ? : }
); } if (shouldShowHomePage) { return ( ); } // Signup route is public - no authentication required if (isSignupRoute) { return (
Loading...
}> {mobileMode ? : }
); } // Verify email is public - shown after signup before user can login // (Auth0 blocks unverified users from logging in) if (isVerifyEmailRoute) { return (
Loading...
}> {mobileMode ? : }
); } if (!isAuthenticated) { return ; } if (isOnboardingRoute) { return (
Loading...
}> {mobileMode ? : }
); } // Wait for auth gate to be ready before rendering protected routes // This prevents a race condition where the page renders before the auth token is ready if (!isAuthGateReady) { console.log('[DEBUG App] Auth gate not ready yet, showing loading state'); if (mobileMode) { return (
Initializing session...
); } return (
Initializing session...
); } // Mobile app rendering if (mobileMode) { return ( {activeScreen === "Dashboard" && ( )} {activeScreen === "Vehicles" && ( {vehicleSubScreen === 'add' || showAddVehicle ? ( ) : selectedVehicle && (vehicleSubScreen === 'detail') ? ( navigateToScreen("Log Fuel")} /> ) : ( )} )} {activeScreen === "Log Fuel" && ( )} {activeScreen === "Settings" && ( )} {activeScreen === "Security" && ( )} {activeScreen === "Documents" && (
{(() => { console.log('[App] Documents Suspense fallback triggered'); return 'Loading documents screen...'; })()}
}>
)} {activeScreen === "Stations" && (
Loading stations screen...
}>
)} {activeScreen === "AdminUsers" && (
Loading admin users...
}>
)} {activeScreen === "AdminCatalog" && (
Loading vehicle catalog...
}>
)} {activeScreen === "AdminCommunityStations" && (
Loading community station reviews...
}>
)} {activeScreen === "AdminEmailTemplates" && (
Loading email templates...
}>
)} {activeScreen === "AdminBackup" && (
Loading backup management...
}>
)}
startTransition(() => { // Prefetch data for the target screen prefetchForNavigation(screen); // Reset states first, then navigate to prevent race conditions if (screen !== 'Vehicles') { setSelectedVehicle(null); // Reset selected vehicle when leaving Vehicles } if (screen !== 'Vehicles' || vehicleSubScreen !== 'add') { setShowAddVehicle(false); // Reset add vehicle form when appropriate } // Navigate after state cleanup navigateToScreen(screen, { source: 'bottom-navigation' }); })} onQuickAction={handleQuickAction} onHamburgerPress={() => setHamburgerOpen(true)} /> setHamburgerOpen(false)} onNavigate={(screen) => { setHamburgerOpen(false); startTransition(() => { prefetchForNavigation(screen); if (screen !== 'Vehicles') { setSelectedVehicle(null); } if (screen !== 'Vehicles' || vehicleSubScreen !== 'add') { setShowAddVehicle(false); } navigateToScreen(screen, { source: 'hamburger-menu' }); }); }} activeScreen={activeScreen} />
); } // Desktop app rendering (fallback) return ( } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> ); } export default App;