- AW-2: Scope calendar events fetch to visible date range via start/end query params, leveraging existing backend support - AW-3: Reduce calendar events poll from 5s to 30s (personal organiser doesn't need 12 API calls/min) - AS-4: Gate shared-calendar polling on hasSharedCalendars — saves 12 wasted API calls/min for personal-only users - AS-2: Lazy-load all route components with React.lazy() — only AdminPortal was previously lazy, now all 10 routes are code-split - AS-1: Add Vite manualChunks to split FullCalendar (~400KB), React, TanStack Query, and UI libs into separate cacheable chunks - AS-3: Extract clockNow into isolated ClockDisplay memo component — prevents all 8 dashboard widgets from re-rendering every minute Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
91 lines
3.6 KiB
TypeScript
91 lines
3.6 KiB
TypeScript
import { lazy, Suspense } from 'react';
|
|
import { Routes, Route, Navigate } from 'react-router-dom';
|
|
import { useAuth } from '@/hooks/useAuth';
|
|
import LockScreen from '@/components/auth/LockScreen';
|
|
import AppLayout from '@/components/layout/AppLayout';
|
|
|
|
// AS-2: Lazy-load all route components to reduce initial bundle parse time
|
|
const DashboardPage = lazy(() => import('@/components/dashboard/DashboardPage'));
|
|
const TodosPage = lazy(() => import('@/components/todos/TodosPage'));
|
|
const CalendarPage = lazy(() => import('@/components/calendar/CalendarPage'));
|
|
const RemindersPage = lazy(() => import('@/components/reminders/RemindersPage'));
|
|
const ProjectsPage = lazy(() => import('@/components/projects/ProjectsPage'));
|
|
const ProjectDetail = lazy(() => import('@/components/projects/ProjectDetail'));
|
|
const PeoplePage = lazy(() => import('@/components/people/PeoplePage'));
|
|
const LocationsPage = lazy(() => import('@/components/locations/LocationsPage'));
|
|
const SettingsPage = lazy(() => import('@/components/settings/SettingsPage'));
|
|
const NotificationsPage = lazy(() => import('@/components/notifications/NotificationsPage'));
|
|
const AdminPortal = lazy(() => import('@/components/admin/AdminPortal'));
|
|
|
|
const RouteFallback = () => (
|
|
<div className="flex h-full items-center justify-center text-muted-foreground">Loading...</div>
|
|
);
|
|
|
|
function ProtectedRoute({ children }: { children: React.ReactNode }) {
|
|
const { authStatus, isLoading } = useAuth();
|
|
|
|
if (isLoading) {
|
|
return <div className="h-dvh bg-background" />;
|
|
}
|
|
|
|
if (!authStatus?.authenticated) {
|
|
return <Navigate to="/login" replace />;
|
|
}
|
|
|
|
return <>{children}</>;
|
|
}
|
|
|
|
function AdminRoute({ children }: { children: React.ReactNode }) {
|
|
const { authStatus, isLoading } = useAuth();
|
|
|
|
if (isLoading) {
|
|
return <div className="h-dvh bg-background" />;
|
|
}
|
|
|
|
if (!authStatus?.authenticated || authStatus?.role !== 'admin') {
|
|
return <Navigate to="/dashboard" replace />;
|
|
}
|
|
|
|
return <>{children}</>;
|
|
}
|
|
|
|
function App() {
|
|
return (
|
|
<Routes>
|
|
<Route path="/login" element={<LockScreen />} />
|
|
<Route
|
|
path="/"
|
|
element={
|
|
<ProtectedRoute>
|
|
<AppLayout />
|
|
</ProtectedRoute>
|
|
}
|
|
>
|
|
<Route index element={<Navigate to="/dashboard" replace />} />
|
|
<Route path="dashboard" element={<Suspense fallback={<RouteFallback />}><DashboardPage /></Suspense>} />
|
|
<Route path="todos" element={<Suspense fallback={<RouteFallback />}><TodosPage /></Suspense>} />
|
|
<Route path="calendar" element={<Suspense fallback={<RouteFallback />}><CalendarPage /></Suspense>} />
|
|
<Route path="reminders" element={<Suspense fallback={<RouteFallback />}><RemindersPage /></Suspense>} />
|
|
<Route path="projects" element={<Suspense fallback={<RouteFallback />}><ProjectsPage /></Suspense>} />
|
|
<Route path="projects/:id" element={<Suspense fallback={<RouteFallback />}><ProjectDetail /></Suspense>} />
|
|
<Route path="people" element={<Suspense fallback={<RouteFallback />}><PeoplePage /></Suspense>} />
|
|
<Route path="locations" element={<Suspense fallback={<RouteFallback />}><LocationsPage /></Suspense>} />
|
|
<Route path="notifications" element={<Suspense fallback={<RouteFallback />}><NotificationsPage /></Suspense>} />
|
|
<Route path="settings" element={<Suspense fallback={<RouteFallback />}><SettingsPage /></Suspense>} />
|
|
<Route
|
|
path="admin/*"
|
|
element={
|
|
<AdminRoute>
|
|
<Suspense fallback={<RouteFallback />}>
|
|
<AdminPortal />
|
|
</Suspense>
|
|
</AdminRoute>
|
|
}
|
|
/>
|
|
</Route>
|
|
</Routes>
|
|
);
|
|
}
|
|
|
|
export default App;
|