fix(api): correlation ID survives HMR; fix endpoint template literal typos
- client.ts: store correlation ID in sessionStorage so HMR (module re-eval) does not generate a new ID mid-session; add clearSessionCorrelationId() - endpoints.ts: fix 3 template literal trailing-quote bugs (missing ')' chars); replace template literals with string concat for encodeURIComponent calls - AuthProvider.tsx: call clearSessionCorrelationId() on logout - App.tsx: reorder ThemeProvider import before AuthProvider per PROVIDER_ORDER.md; indent Routes inside AuthProvider to match expected tree structure - Tasks.md: update task status - providerTreeOrder.test.tsx: add integration tests for provider nesting order Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
* 3. `NotificationProvider` — provides notification service to all descendants
|
||||
* 4. `ErrorBoundary` — catches catastrophic errors
|
||||
* 5. `BrowserRouter` — enables client-side routing via React Router
|
||||
* 6. `NavigationCancellationProvider` — manages route-aware request cancellation
|
||||
* 6. `NavigationCancellationProvider` — manages route-aware request cancellation
|
||||
* 7. `AuthProvider` — manages session state; validates on mount; uses useNavigate()
|
||||
* 8. `TimezoneProvider` — INNERMOST (inside protected routes); fetches timezone after auth
|
||||
*
|
||||
@@ -35,8 +35,8 @@ import { lazy, Suspense, useEffect } from "react";
|
||||
import { FluentProvider, Spinner } from "@fluentui/react-components";
|
||||
import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom";
|
||||
import { darkTheme, lightTheme } from "./theme/customTheme";
|
||||
import { AuthProvider } from "./providers/AuthProvider";
|
||||
import { ThemeProvider, useThemeMode } from "./providers/ThemeProvider";
|
||||
import { AuthProvider } from "./providers/AuthProvider";
|
||||
import { TimezoneProvider } from "./providers/TimezoneProvider";
|
||||
import { NavigationCancellationProvider } from "./providers/NavigationCancellationProvider";
|
||||
import { NotificationProvider } from "./services/notificationService";
|
||||
@@ -67,9 +67,9 @@ const BlocklistsPage = lazy(() => import("./pages/BlocklistsPage").then((m) => (
|
||||
* - NotificationProvider (3) — provides notification service
|
||||
* - ErrorBoundary (4) — catches catastrophic errors
|
||||
* - BrowserRouter (5) — enables routing
|
||||
* - NavigationCancellationProvider (6) — manages route-aware request cancellation
|
||||
* - AuthProvider (7) — session validation; uses useNavigate()
|
||||
* - TimezoneProvider (8) — inside protected routes only
|
||||
* - NavigationCancellationProvider (6) — manages route-aware request cancellation
|
||||
* - AuthProvider (7) — session validation; uses useNavigate()
|
||||
* - TimezoneProvider (8) — inside protected routes only
|
||||
*/
|
||||
function AppContents(): React.JSX.Element {
|
||||
const { colorMode } = useThemeMode();
|
||||
@@ -103,105 +103,105 @@ function AppContents(): React.JSX.Element {
|
||||
<Suspense fallback={<Spinner size="large" label="Loading…" />}>
|
||||
{/* 7. AuthProvider — validates session on mount; must be inside BrowserRouter */}
|
||||
<AuthProvider>
|
||||
<Routes>
|
||||
{/* Setup wizard — always accessible; redirects to /login if already done */}
|
||||
<Route
|
||||
path="/setup"
|
||||
element={
|
||||
<PageErrorBoundary pageName="Setup">
|
||||
<SetupPage />
|
||||
</PageErrorBoundary>
|
||||
}
|
||||
/>
|
||||
<Routes>
|
||||
{/* Setup wizard — always accessible; redirects to /login if already done */}
|
||||
<Route
|
||||
path="/setup"
|
||||
element={
|
||||
<PageErrorBoundary pageName="Setup">
|
||||
<SetupPage />
|
||||
</PageErrorBoundary>
|
||||
}
|
||||
/>
|
||||
|
||||
{/* Login — requires setup to be complete */}
|
||||
<Route
|
||||
path="/login"
|
||||
element={
|
||||
<PageErrorBoundary pageName="Login">
|
||||
{/* Login — requires setup to be complete */}
|
||||
<Route
|
||||
path="/login"
|
||||
element={
|
||||
<PageErrorBoundary pageName="Login">
|
||||
<SetupGuard>
|
||||
<LoginPage />
|
||||
</SetupGuard>
|
||||
</PageErrorBoundary>
|
||||
}
|
||||
/>
|
||||
|
||||
{/* Protected routes — require setup AND authentication */}
|
||||
<Route
|
||||
element={
|
||||
<SetupGuard>
|
||||
<LoginPage />
|
||||
<RequireAuth>
|
||||
{/* 8. TimezoneProvider — INNERMOST; fetches timezone after auth validation */}
|
||||
<TimezoneProvider>
|
||||
<MainLayout />
|
||||
</TimezoneProvider>
|
||||
</RequireAuth>
|
||||
</SetupGuard>
|
||||
</PageErrorBoundary>
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Route
|
||||
index
|
||||
element={
|
||||
<PageErrorBoundary pageName="Dashboard">
|
||||
<DashboardPage />
|
||||
</PageErrorBoundary>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/map"
|
||||
element={
|
||||
<PageErrorBoundary pageName="Map">
|
||||
<MapPage />
|
||||
</PageErrorBoundary>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/jails"
|
||||
element={
|
||||
<PageErrorBoundary pageName="Jails">
|
||||
<JailsPage />
|
||||
</PageErrorBoundary>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/jails/:name"
|
||||
element={
|
||||
<PageErrorBoundary pageName="Jail Details">
|
||||
<JailDetailPage />
|
||||
</PageErrorBoundary>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/config"
|
||||
element={
|
||||
<PageErrorBoundary pageName="Configuration">
|
||||
<ConfigPage />
|
||||
</PageErrorBoundary>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/history"
|
||||
element={
|
||||
<PageErrorBoundary pageName="History">
|
||||
<HistoryPage />
|
||||
</PageErrorBoundary>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/blocklists"
|
||||
element={
|
||||
<PageErrorBoundary pageName="Blocklists">
|
||||
<BlocklistsPage />
|
||||
</PageErrorBoundary>
|
||||
}
|
||||
/>
|
||||
</Route>
|
||||
|
||||
{/* Protected routes — require setup AND authentication */}
|
||||
<Route
|
||||
element={
|
||||
<SetupGuard>
|
||||
<RequireAuth>
|
||||
{/* 7. TimezoneProvider — INNERMOST; fetches timezone after auth validation */}
|
||||
<TimezoneProvider>
|
||||
<MainLayout />
|
||||
</TimezoneProvider>
|
||||
</RequireAuth>
|
||||
</SetupGuard>
|
||||
}
|
||||
>
|
||||
<Route
|
||||
index
|
||||
element={
|
||||
<PageErrorBoundary pageName="Dashboard">
|
||||
<DashboardPage />
|
||||
</PageErrorBoundary>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/map"
|
||||
element={
|
||||
<PageErrorBoundary pageName="Map">
|
||||
<MapPage />
|
||||
</PageErrorBoundary>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/jails"
|
||||
element={
|
||||
<PageErrorBoundary pageName="Jails">
|
||||
<JailsPage />
|
||||
</PageErrorBoundary>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/jails/:name"
|
||||
element={
|
||||
<PageErrorBoundary pageName="Jail Details">
|
||||
<JailDetailPage />
|
||||
</PageErrorBoundary>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/config"
|
||||
element={
|
||||
<PageErrorBoundary pageName="Configuration">
|
||||
<ConfigPage />
|
||||
</PageErrorBoundary>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/history"
|
||||
element={
|
||||
<PageErrorBoundary pageName="History">
|
||||
<HistoryPage />
|
||||
</PageErrorBoundary>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/blocklists"
|
||||
element={
|
||||
<PageErrorBoundary pageName="Blocklists">
|
||||
<BlocklistsPage />
|
||||
</PageErrorBoundary>
|
||||
}
|
||||
/>
|
||||
</Route>
|
||||
|
||||
{/* Fallback — redirect unknown paths to dashboard */}
|
||||
<Route path="*" element={<Navigate to="/" replace />} />
|
||||
</Routes>
|
||||
</AuthProvider>
|
||||
</Suspense>
|
||||
{/* Fallback — redirect unknown paths to dashboard */}
|
||||
<Route path="*" element={<Navigate to="/" replace />} />
|
||||
</Routes>
|
||||
</AuthProvider>
|
||||
</Suspense>
|
||||
</NavigationCancellationProvider>
|
||||
</BrowserRouter>
|
||||
</ErrorBoundary>
|
||||
|
||||
Reference in New Issue
Block a user