Require asset ID scan in audit and consume modals
Build and push image / build (push) Successful in 47s
Build and push image / build (push) Successful in 47s
No default item selection — modals open with a scan prompt. Form fields appear only after scanning an asset ID. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -39,7 +39,7 @@ export function AuditFlow({
|
|||||||
.filter((i) => i.status === "active")
|
.filter((i) => i.status === "active")
|
||||||
.sort((a, b) => helpers.daysSinceCheck(b) - helpers.daysSinceCheck(a));
|
.sort((a, b) => helpers.daysSinceCheck(b) - helpers.daysSinceCheck(a));
|
||||||
|
|
||||||
const [itemId, setItemId] = useState(initialItem?.id ?? overdueFirst[0]?.id ?? "");
|
const [itemId, setItemId] = useState(initialItem?.id ?? "");
|
||||||
const [date, setDate] = useState(TODAY_STR);
|
const [date, setDate] = useState(TODAY_STR);
|
||||||
const [confirmedBy, setConfirmedBy] = useState<"asset" | "SKU" | "visual">("asset");
|
const [confirmedBy, setConfirmedBy] = useState<"asset" | "SKU" | "visual">("asset");
|
||||||
|
|
||||||
@@ -82,17 +82,17 @@ export function AuditFlow({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!item) return null;
|
|
||||||
const auditMode = cfg?.auditMode ?? "weigh";
|
const auditMode = cfg?.auditMode ?? "weigh";
|
||||||
const ml = AUDIT_MODE_LABELS[auditMode] ?? AUDIT_MODE_LABELS.weigh!;
|
const ml = AUDIT_MODE_LABELS[auditMode] ?? AUDIT_MODE_LABELS.weigh!;
|
||||||
|
|
||||||
const last = helpers.lastAudit(item);
|
const last = item ? helpers.lastAudit(item) : null;
|
||||||
const prevValue =
|
const prevValue = item
|
||||||
item.kind === "discrete"
|
? item.kind === "discrete"
|
||||||
? item.countLastAudit ?? item.countOriginal
|
? item.countLastAudit ?? item.countOriginal
|
||||||
: last
|
: last
|
||||||
? last.value
|
? last.value
|
||||||
: item.weight;
|
: item.weight
|
||||||
|
: 0;
|
||||||
|
|
||||||
const delta = Number(value) - prevValue;
|
const delta = Number(value) - prevValue;
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ export function AuditFlow({
|
|||||||
boxShadow: "var(--shadow-lg)",
|
boxShadow: "var(--shadow-lg)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ModalHeader title={ml.title} eyebrow="" onClose={onClose} />
|
<ModalHeader title={item ? ml.title : "Audit"} eyebrow="" onClose={onClose} />
|
||||||
|
|
||||||
<div style={{ padding: 32 }}>
|
<div style={{ padding: 32 }}>
|
||||||
<ScanField
|
<ScanField
|
||||||
@@ -118,6 +118,12 @@ export function AuditFlow({
|
|||||||
onMatch={handleScan}
|
onMatch={handleScan}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{!item ? (
|
||||||
|
<div style={{ marginTop: 24, textAlign: "center", color: "var(--ink-3)", fontSize: 13, fontStyle: "italic", padding: "24px 0" }}>
|
||||||
|
Scan an asset ID to continue.
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
marginTop: 16,
|
marginTop: 16,
|
||||||
@@ -226,6 +232,8 @@ export function AuditFlow({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
<div style={{ marginTop: 14, fontSize: 12, color: "var(--terracotta)" }}>{error}</div>
|
<div style={{ marginTop: 14, fontSize: 12, color: "var(--terracotta)" }}>{error}</div>
|
||||||
@@ -234,14 +242,14 @@ export function AuditFlow({
|
|||||||
|
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<div style={{ fontSize: 12, color: "var(--ink-3)" }}>
|
<div style={{ fontSize: 12, color: "var(--ink-3)" }}>
|
||||||
Next audit due in {cfg?.cadenceDays}d
|
{item ? `Next audit due in ${cfg?.cadenceDays}d` : ""}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: "flex", gap: 8 }}>
|
<div style={{ display: "flex", gap: 8 }}>
|
||||||
<Btn variant="ghost" onClick={onClose}>Cancel</Btn>
|
<Btn variant="ghost" onClick={onClose}>Cancel</Btn>
|
||||||
<Btn
|
<Btn
|
||||||
variant="primary"
|
variant="primary"
|
||||||
icon="check"
|
icon="check"
|
||||||
disabled={audit.isPending}
|
disabled={audit.isPending || !item}
|
||||||
onClick={() => audit.mutate()}
|
onClick={() => audit.mutate()}
|
||||||
>
|
>
|
||||||
{audit.isPending ? "Saving…" : "Save audit"}
|
{audit.isPending ? "Saving…" : "Save audit"}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export function ConsumeFlow({
|
|||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const allItems = enrichItems(data);
|
const allItems = enrichItems(data);
|
||||||
const active = allItems.filter((i) => i.status === "active");
|
const active = allItems.filter((i) => i.status === "active");
|
||||||
const [itemId, setItemId] = useState(initialItem?.id ?? active[0]?.id ?? "");
|
const [itemId, setItemId] = useState(initialItem?.id ?? "");
|
||||||
const [rating, setRating] = useState(4);
|
const [rating, setRating] = useState(4);
|
||||||
const [notes, setNotes] = useState("");
|
const [notes, setNotes] = useState("");
|
||||||
const [date, setDate] = useState(TODAY_STR);
|
const [date, setDate] = useState(TODAY_STR);
|
||||||
@@ -46,9 +46,8 @@ export function ConsumeFlow({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!item) return null;
|
const bin = item ? data.bins.find((b) => b.id === item.binId) : undefined;
|
||||||
const bin = data.bins.find((b) => b.id === item.binId);
|
const lifespan = item ? Math.round((+new Date(date) - +new Date(item.purchaseDate)) / 86_400_000) : 0;
|
||||||
const lifespan = Math.round((+new Date(date) - +new Date(item.purchaseDate)) / 86_400_000);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalBackdrop onClose={onClose}>
|
<ModalBackdrop onClose={onClose}>
|
||||||
@@ -72,6 +71,12 @@ export function ConsumeFlow({
|
|||||||
onMatch={handleScan}
|
onMatch={handleScan}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{!item ? (
|
||||||
|
<div style={{ marginTop: 24, textAlign: "center", color: "var(--ink-3)", fontSize: 13, fontStyle: "italic", padding: "24px 0" }}>
|
||||||
|
Scan an asset ID to continue.
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
marginTop: 16,
|
marginTop: 16,
|
||||||
@@ -150,6 +155,8 @@ export function ConsumeFlow({
|
|||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
<div style={{ marginTop: 14, fontSize: 12, color: "var(--terracotta)" }}>{error}</div>
|
<div style={{ marginTop: 14, fontSize: 12, color: "var(--terracotta)" }}>{error}</div>
|
||||||
@@ -163,7 +170,7 @@ export function ConsumeFlow({
|
|||||||
<Btn
|
<Btn
|
||||||
variant="primary"
|
variant="primary"
|
||||||
icon="check"
|
icon="check"
|
||||||
disabled={finish.isPending}
|
disabled={finish.isPending || !item}
|
||||||
onClick={() => finish.mutate()}
|
onClick={() => finish.mutate()}
|
||||||
>
|
>
|
||||||
{finish.isPending ? "Saving…" : "Mark consumed"}
|
{finish.isPending ? "Saving…" : "Mark consumed"}
|
||||||
|
|||||||
Reference in New Issue
Block a user