import { useCallback, useEffect, useState } from "react"; import { InlineNotification, Loading, Theme } from "@carbon/react"; import { api } from "./lib/api"; import type { Settings } from "./lib/types"; import { AppShell, type AppView } from "./components/AppShell"; import Onboarding from "./views/Onboarding"; import NewInvoice from "./views/NewInvoice"; import InvoiceHistory from "./views/InvoiceHistory"; import SeriesSettings from "./views/SeriesSettings"; import AppSettings from "./views/AppSettings"; export default function App() { const [settings, setSettings] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [view, setView] = useState("new"); const refreshSettings = useCallback(async () => { try { const next = await api.getSettings(); setSettings(next); setError(null); } catch (e) { setError(String(e)); } finally { setLoading(false); } }, []); useEffect(() => { void refreshSettings(); }, [refreshSettings]); if (loading) { return (
); } if (error) { return (
); } if (!settings) return null; const theme = settings.theme === "g100" ? "g100" : "g10"; if (!settings.onboarded) { return ( { setSettings(next); setView("new"); }} /> ); } const toggleTheme = async () => { const next: Settings = { ...settings, theme: settings.theme === "g100" ? "g10" : "g100" }; setSettings(next); try { await api.saveSettings(next); } catch (e) { setError(String(e)); } }; return ( {/* Main views stay mounted so a half-typed invoice survives switching tabs. */} setView("new")} /> {view === "settings" && } ); }