Add checkout/custody feature for tracking items in personal possession
Build and push image / build (push) Successful in 1m8s

Items can now be checked out of their bin into "my custody" and later
checked back in or marked consumed. Adds checkout/checkin API endpoints,
a My Custody sidebar page, CheckoutFlow and CheckinFlow modals, and
updates ProductDetail, Inventory, ConsumeFlow, and MarkGoneFlow to
handle the new checked-out status. Bulk items prompt for remaining
weight on check-in.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-07 20:49:58 -04:00
parent 04bf009a83
commit e7fd9af62c
17 changed files with 689 additions and 18 deletions
+4 -3
View File
@@ -1,4 +1,4 @@
export type ProductStatus = "active" | "consumed" | "gone";
export type ProductStatus = "active" | "consumed" | "gone" | "checked-out";
export type ProductKind = "bulk" | "discrete";
export type AuditMode = "weigh" | "estimate" | "presence";
@@ -46,6 +46,7 @@ export interface InventoryItem {
status: ProductStatus;
consumedDate: string | null;
goneDate: string | null;
checkoutDate: string | null;
rating: number | null;
notes: string | null;
audits: Audit[];
@@ -197,13 +198,13 @@ export const helpers = {
return Math.floor((+new Date(today) - +new Date(last)) / 86_400_000);
},
auditOverdue(p: Item, today = TODAY_STR): boolean {
if (p.status !== "active") return false;
if (p.status !== "active" && p.status !== "checked-out") return false;
const cfg = TYPES.find((t) => t.id === p.type);
if (!cfg) return false;
return this.daysSinceCheck(p, today) >= cfg.cadenceDays;
},
estimatedRemaining(p: Item, today = TODAY_STR): number {
if (p.status !== "active") return 0;
if (p.status !== "active" && p.status !== "checked-out") return 0;
if (p.kind === "discrete") {
return p.countLastAudit ?? p.countOriginal;
}