Edit existing products

Adds PATCH /products/:id and an EditProductFlow modal opened from the
product drawer. Editable fields cover name, brand, shop, bin, asset tag,
price, purchase date, size (weight or count + unit weight), and the
cannabinoid profile. SKU, type, kind, and status-derived dates stay
locked because changing them would invalidate audit history math; type
changes are surfaced as "mark gone, add new" in the modal.

The strain row is re-resolved on name or brand change so analytics stay
aligned, and the last-audit mirror (last_audit_weight / count_last_audit)
only syncs with the original size when there are no audits yet.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-03 21:42:33 -04:00
parent 8ef8859c7d
commit 592bb28740
5 changed files with 586 additions and 0 deletions
+11
View File
@@ -15,6 +15,7 @@ import { SettingsView } from "./views/SettingsView.js";
import type { ThemeKey } from "./views/SettingsView.js";
import { ProductDetail } from "./components/ProductDetail.js";
import { AddProductFlow } from "./components/modals/AddProductFlow.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";
@@ -29,6 +30,7 @@ import {
type ModalKey =
| "add"
| "edit"
| "consume"
| "gone"
| "audit"
@@ -93,6 +95,11 @@ export function App() {
setModalProduct(p ?? null);
setModal("audit");
};
const openEdit = (p: Product) => {
setModalProduct(p);
setSelected(null);
setModal("edit");
};
if (isLoading) {
return (
@@ -181,10 +188,14 @@ export function App() {
onConsume={openConsume}
onMarkGone={openMarkGone}
onAudit={openAudit}
onEdit={openEdit}
/>
)}
{modal === "add" && <AddProductFlow data={data} onClose={() => setModal(null)} />}
{modal === "edit" && modalProduct && (
<EditProductFlow data={data} product={modalProduct} onClose={() => setModal(null)} />
)}
{modal === "consume" && (
<ConsumeFlow data={data} onClose={() => setModal(null)} product={modalProduct} />
)}