Fix 18 UX issues: confirmations, undo, drawer nav, empty states, and polish
Build and push image / build (push) Successful in 54s
Build and push image / build (push) Successful in 54s
Comprehensive UX audit covering modals, drawers, dashboard, and inventory. Key changes: confirmation steps before destructive actions, undo via toast for consume/gone/checkout, back-navigation across entity drawers, optional ratings, discrete item count field, audit progress bar, and sortable column affordance. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,7 @@ archiveLegacyIfPresent();
|
||||
archiveV1IfPresent();
|
||||
migrateAddCheckoutDate();
|
||||
migrateAddContainerWeight();
|
||||
migrateAddPrevBinId();
|
||||
|
||||
const schema = readFileSync(join(__dirname, "schema.sql"), "utf8");
|
||||
db.exec(schema);
|
||||
@@ -35,6 +36,14 @@ function migrateAddContainerWeight(): void {
|
||||
db.exec(`ALTER TABLE inventory_items ADD COLUMN container_weight REAL`);
|
||||
}
|
||||
|
||||
function migrateAddPrevBinId(): void {
|
||||
const cols = db
|
||||
.prepare(`PRAGMA table_info(inventory_items)`)
|
||||
.all() as { name: string }[];
|
||||
if (cols.length === 0 || cols.some((c) => c.name === "prev_bin_id")) return;
|
||||
db.exec(`ALTER TABLE inventory_items ADD COLUMN prev_bin_id TEXT REFERENCES bins(id)`);
|
||||
}
|
||||
|
||||
// One-shot migration: the original schema put per-instance fields (weight,
|
||||
// bin_id, etc.) directly on `products`. The split schema separates products
|
||||
// (catalog) from inventory_items (instance). When we detect the old shape,
|
||||
|
||||
@@ -34,6 +34,7 @@ type InventoryRow = {
|
||||
consumed_date: string | null;
|
||||
gone_date: string | null;
|
||||
checkout_date: string | null;
|
||||
prev_bin_id: string | null;
|
||||
rating: number | null;
|
||||
notes: string | null;
|
||||
};
|
||||
@@ -112,6 +113,7 @@ bootstrapRouter.get("/bootstrap", (_req, res) => {
|
||||
consumedDate: i.consumed_date,
|
||||
goneDate: i.gone_date,
|
||||
checkoutDate: i.checkout_date,
|
||||
prevBinId: i.prev_bin_id,
|
||||
rating: i.rating,
|
||||
notes: i.notes,
|
||||
audits: (auditsByInventory.get(i.id) ?? []).map((a) => ({
|
||||
|
||||
@@ -223,7 +223,7 @@ function doCheckout(id: string, date: string): void {
|
||||
const result = db
|
||||
.prepare(
|
||||
`UPDATE inventory_items
|
||||
SET status = 'checked-out', checkout_date = ?, bin_id = NULL
|
||||
SET status = 'checked-out', checkout_date = ?, prev_bin_id = bin_id, bin_id = NULL
|
||||
WHERE id = ? AND status = 'active'`,
|
||||
)
|
||||
.run(date, id);
|
||||
@@ -249,7 +249,7 @@ function doCheckin(id: string, date: string, binId: string, remainingWeight?: nu
|
||||
|
||||
db.prepare(
|
||||
`UPDATE inventory_items
|
||||
SET status = 'active', bin_id = ?, checkout_date = NULL
|
||||
SET status = 'active', bin_id = ?, checkout_date = NULL, prev_bin_id = NULL
|
||||
WHERE id = ?`,
|
||||
).run(binId, id);
|
||||
|
||||
@@ -355,6 +355,30 @@ inventoryRouter.post("/inventory/:id/gone", (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
inventoryRouter.post("/inventory/:id/reactivate", (req, res) => {
|
||||
const { binId } = req.body as { binId: string };
|
||||
try {
|
||||
const result = db
|
||||
.prepare(
|
||||
`UPDATE inventory_items
|
||||
SET status = 'active',
|
||||
bin_id = ?,
|
||||
consumed_date = NULL,
|
||||
gone_date = NULL,
|
||||
checkout_date = NULL,
|
||||
prev_bin_id = NULL
|
||||
WHERE id = ? AND status IN ('consumed', 'gone', 'checked-out')`,
|
||||
)
|
||||
.run(binId, req.params.id);
|
||||
if (result.changes === 0) {
|
||||
return res.status(404).json({ error: "not found or already active" });
|
||||
}
|
||||
res.json({ ok: true });
|
||||
} catch (e: any) {
|
||||
res.status(400).json({ error: e.message });
|
||||
}
|
||||
});
|
||||
|
||||
inventoryRouter.post("/inventory/:id/audit", (req, res) => {
|
||||
const { id } = req.params;
|
||||
const { date, mode, value, confirmedBy } = req.body as {
|
||||
|
||||
@@ -74,6 +74,7 @@ CREATE TABLE IF NOT EXISTS inventory_items (
|
||||
consumed_date TEXT,
|
||||
gone_date TEXT,
|
||||
checkout_date TEXT,
|
||||
prev_bin_id TEXT REFERENCES bins(id),
|
||||
rating INTEGER,
|
||||
notes TEXT
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user