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 InvoiceDetail from "./views/InvoiceDetail"; import Clients from "./views/Clients"; import { ToastProvider, useToast } from "./components/ToastProvider"; import AppSettings from "./views/AppSettings"; export default function App() { return ( ); } function AppInner() { const toast = useToast(); const [settings, setSettings] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [view, setView] = useState("new"); const [detailId, setDetailId] = useState(null); // A draft made by "Duplicate" that the New invoice form should open once it is shown. const [openDraftId, setOpenDraftId] = useState(null); 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) { toast.error("Could not save the theme", String(e)); } }; return ( {/* Main views stay mounted so a half-typed invoice survives switching tabs. */} setView("new")} openDraftId={openDraftId} onDraftOpened={() => setOpenDraftId(null)} /> {view === "invoice" && detailId !== null ? ( setView("invoices")} onDuplicated={(draftId) => { setOpenDraftId(draftId); setView("new"); }} /> ) : null} {view === "settings" && } ); }