Simpl-Resultat/src/App.tsx
le king fu 3882df772b fix(startup): clear the startup error when the profile opens after the delay
The 10 s startup delay of App.tsx sets the error page while the profile
is still opening; a connection that succeeded afterwards set dbReady but
left the error, so the error page stayed. The startup logic moves to
src/utils/startupConnection.ts (startProfileConnection), which clears the
error on success and is tested with fake timers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 20:18:18 -04:00

126 lines
5.6 KiB
TypeScript

import { BrowserRouter, Routes, Route } from "react-router-dom";
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useProfile } from "./contexts/ProfileContext";
import AppShell from "./components/layout/AppShell";
import DashboardPage from "./pages/DashboardPage";
import ImportPage from "./pages/ImportPage";
import TransactionsPage from "./pages/TransactionsPage";
import CategoriesPage from "./pages/CategoriesPage";
import AdjustmentsPage from "./pages/AdjustmentsPage";
import BudgetPage from "./pages/BudgetPage";
import ReportsPage from "./pages/ReportsPage";
import ReportsHighlightsPage from "./pages/ReportsHighlightsPage";
import ReportsTrendsPage from "./pages/ReportsTrendsPage";
import ReportsComparePage from "./pages/ReportsComparePage";
import ReportsCategoryPage from "./pages/ReportsCategoryPage";
import ReportsCartesPage from "./pages/ReportsCartesPage";
import SettingsLayout from "./pages/settings/SettingsLayout";
import SettingsHomePage from "./pages/settings/SettingsHomePage";
import UsersSettingsPage from "./pages/settings/UsersSettingsPage";
import DataSettingsPage from "./pages/settings/DataSettingsPage";
import SystemsSettingsPage from "./pages/settings/SystemsSettingsPage";
import AccountsPage from "./pages/AccountsPage";
import BalancePage from "./pages/BalancePage";
import SnapshotEditPage from "./pages/SnapshotEditPage";
import CategoriesStandardGuidePage from "./pages/CategoriesStandardGuidePage";
import CategoriesMigrationPage from "./pages/CategoriesMigrationPage";
import DocsPage from "./pages/DocsPage";
import ChangelogPage from "./pages/ChangelogPage";
import ProfileSelectionPage from "./pages/ProfileSelectionPage";
import ErrorPage from "./components/shared/ErrorPage";
import RequireFeature from "./components/shared/RequireFeature";
import { startProfileConnection } from "./utils/startupConnection";
export default function App() {
const { t } = useTranslation();
const { activeProfile, isLoading, refreshKey, connectActiveProfile } = useProfile();
const [dbReady, setDbReady] = useState(false);
const [startupError, setStartupError] = useState<string | null>(null);
useEffect(() => {
if (!activeProfile || isLoading) return;
return startProfileConnection({
connect: connectActiveProfile,
setDbReady,
setStartupError,
timeoutMessage: t("error.startupTimeout"),
});
}, [activeProfile, isLoading, connectActiveProfile, t]);
if (isLoading) {
return (
<div className="flex items-center justify-center h-screen bg-[var(--background)]">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-[var(--primary)]" />
</div>
);
}
if (startupError) {
return <ErrorPage error={startupError} />;
}
if (!activeProfile) {
return <ProfileSelectionPage />;
}
if (!dbReady) {
return (
<div className="flex items-center justify-center h-screen bg-[var(--background)]">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-[var(--primary)]" />
</div>
);
}
return (
<BrowserRouter key={refreshKey}>
<Routes>
<Route element={<AppShell />}>
<Route path="/" element={<DashboardPage />} />
<Route path="/import" element={<ImportPage />} />
<Route path="/transactions" element={<TransactionsPage />} />
<Route path="/categories" element={<CategoriesPage />} />
{/* Gated routes (soft paywall): pathless layout-routes render
RequireFeature's <Outlet/> — one group per feature, mirroring the
SettingsLayout convention. The /reports hub and /reports/trends
stay Free and OUTSIDE any gate. */}
<Route element={<RequireFeature feature="adjustments" />}>
<Route path="/adjustments" element={<AdjustmentsPage />} />
</Route>
<Route element={<RequireFeature feature="budget" />}>
<Route path="/budget" element={<BudgetPage />} />
</Route>
<Route path="/reports" element={<ReportsPage />} />
<Route path="/reports/trends" element={<ReportsTrendsPage />} />
<Route element={<RequireFeature feature="reports-advanced" />}>
<Route path="/reports/highlights" element={<ReportsHighlightsPage />} />
<Route path="/reports/compare" element={<ReportsComparePage />} />
<Route path="/reports/category" element={<ReportsCategoryPage />} />
<Route path="/reports/cartes" element={<ReportsCartesPage />} />
</Route>
<Route path="/settings" element={<SettingsLayout />}>
<Route index element={<SettingsHomePage />} />
<Route path="users" element={<UsersSettingsPage />} />
<Route path="data" element={<DataSettingsPage />} />
<Route path="systems" element={<SystemsSettingsPage />} />
</Route>
<Route element={<RequireFeature feature="balance" />}>
<Route path="/balance" element={<BalancePage />} />
<Route path="/balance/accounts" element={<AccountsPage />} />
<Route path="/balance/snapshot" element={<SnapshotEditPage />} />
</Route>
<Route
path="/settings/categories/standard"
element={<CategoriesStandardGuidePage />}
/>
<Route
path="/settings/categories/migrate"
element={<CategoriesMigrationPage />}
/>
<Route path="/docs" element={<DocsPage />} />
<Route path="/changelog" element={<ChangelogPage />} />
</Route>
</Routes>
</BrowserRouter>
);
}