import { useEffect, useMemo, useState } from "react"; import { useQuery } from "@tanstack/react-query"; import { api } from "./api.js"; import type { Bin, Bootstrap, Brand, Item, Product, Shop } from "./types.js"; import { enrichItems } from "./types.js"; import { computeStats } from "./stats.js"; import { Sidebar } from "./components/Sidebar.js"; import type { ViewKey } from "./components/Sidebar.js"; import { Dashboard } from "./views/Dashboard.js"; import { Inventory } from "./views/Inventory.js"; import { BinsView } from "./views/BinsView.js"; import { BrandsView } from "./views/BrandsView.js"; import { ShopsView } from "./views/ShopsView.js"; import { ChartsView } from "./views/ChartsView.js"; import { SettingsView } from "./views/SettingsView.js"; import type { ThemeKey } from "./views/SettingsView.js"; import { ProductDetail } from "./components/ProductDetail.js"; import { AddInventoryFlow } from "./components/modals/AddInventoryFlow.js"; import { EditInventoryFlow } from "./components/modals/EditInventoryFlow.js"; import { EditProductFlow } from "./components/modals/EditProductFlow.js"; import { ConsumeFlow } from "./components/modals/ConsumeFlow.js"; import { MarkGoneFlow } from "./components/modals/MarkGoneFlow.js"; import { AuditFlow } from "./components/modals/AuditFlow.js"; import { AddBinModal, AddBrandModal, AddShopModal, EditBinModal, EditBrandModal, EditShopModal, } from "./components/modals/CatalogModals.js"; type ModalKey = | "add" | "edit" | "editProduct" | "consume" | "gone" | "audit" | "addBrand" | "addShop" | "addBin" | "editBin" | "editBrand" | "editShop" | null; export function App() { const [view, setView] = useState("dashboard"); const [selected, setSelected] = useState(null); const [modal, setModal] = useState(null); const [modalItem, setModalItem] = useState(null); const [modalProduct, setModalProduct] = useState(null); const [modalBin, setModalBin] = useState(null); const [modalBrand, setModalBrand] = useState(null); const [modalShop, setModalShop] = useState(null); const [theme, setTheme] = useState( () => (localStorage.getItem("apothecary.theme") as ThemeKey | null) ?? "light", ); useEffect(() => { document.documentElement.dataset.theme = theme; localStorage.setItem("apothecary.theme", theme); }, [theme]); const { data, isLoading, error } = useQuery({ queryKey: ["bootstrap"], queryFn: api.bootstrap, }); const stats = useMemo(() => (data ? computeStats(data) : null), [data]); const items = useMemo(() => (data ? enrichItems(data) : []), [data]); // Re-sync the selected item reference whenever bootstrap refetches // — otherwise the drawer keeps showing stale audit history after a // mutation invalidates the cache. useEffect(() => { if (selected && data) { const fresh = items.find((i) => i.id === selected.id); if (fresh && fresh !== selected) setSelected(fresh); } }, [data, items]); // eslint-disable-line react-hooks/exhaustive-deps const openAdd = () => { setModalItem(null); setModal("add"); }; const openConsume = (i?: Item) => { setModalItem(i ?? null); setSelected(null); setModal("consume"); }; const openMarkGone = (i?: Item) => { setModalItem(i ?? null); setSelected(null); setModal("gone"); }; const openAudit = (i?: Item) => { setModalItem(i ?? null); setModal("audit"); }; const openEdit = (i: Item) => { setModalItem(i); setSelected(null); setModal("edit"); }; const openEditProduct = (p: Product) => { setModalProduct(p); setSelected(null); setModal("editProduct"); }; if (isLoading) { return (
Loading…
); } if (error || !data || !stats) { return (
Failed to load: {String(error ?? "no data")}
); } return (
openConsume()} onAudit={() => openAudit()} />
{view === "dashboard" && ( )} {view === "inventory" && ( openAudit()} /> )} {view === "bins" && ( setModal("addBin")} onEditBin={(bin) => { setModalBin(bin); setModal("editBin"); }} /> )} {view === "shops" && ( setModal("addShop")} onEditShop={(shop) => { setModalShop(shop); setModal("editShop"); }} /> )} {view === "brands" && ( setModal("addBrand")} onEditBrand={(brand) => { setModalBrand(brand); setModal("editBrand"); }} /> )} {view === "charts" && } {view === "settings" && ( )}
{selected && ( setSelected(null)} onConsume={openConsume} onMarkGone={openMarkGone} onAudit={openAudit} onEdit={openEdit} onEditProduct={openEditProduct} /> )} {modal === "add" && setModal(null)} />} {modal === "edit" && modalItem && ( setModal(null)} /> )} {modal === "editProduct" && modalProduct && ( setModal(null)} /> )} {modal === "consume" && ( setModal(null)} item={modalItem} /> )} {modal === "gone" && ( setModal(null)} item={modalItem} /> )} {modal === "audit" && ( setModal(null)} item={modalItem} /> )} {modal === "addBrand" && setModal(null)} />} {modal === "addShop" && setModal(null)} />} {modal === "addBin" && setModal(null)} />} {modal === "editBin" && modalBin && ( setModal(null)} /> )} {modal === "editBrand" && modalBrand && ( setModal(null)} /> )} {modal === "editShop" && modalShop && ( setModal(null)} /> )}
); }