Scope ScanField by mode: asset ID only for audit/consume, SKU only for add inventory
Build and push image / build (push) Successful in 57s

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-04 20:32:52 -04:00
parent c031058d1d
commit 04bf009a83
4 changed files with 26 additions and 14 deletions
+22 -12
View File
@@ -16,6 +16,7 @@ export function ScanField({
onMatch,
onScanNoMatch,
matchedLabel,
mode = "both",
}: {
items: Item[];
products?: Product[];
@@ -25,6 +26,7 @@ export function ScanField({
// open a "create new product" form prefilled with the scanned SKU).
onScanNoMatch?: (raw: string) => void;
matchedLabel: string | null;
mode?: "both" | "assetId" | "sku";
}) {
const [scan, setScan] = useState("");
const [feedback, setFeedback] = useState<{ type: "matched" | "miss"; text: string } | null>(null);
@@ -35,7 +37,7 @@ export function ScanField({
setFeedback(null);
return;
}
const hit = lookup(trimmed, items, products);
const hit = lookup(trimmed, items, products, mode);
if (hit) {
const label = hit.kind === "item" ? hit.item.name : hit.product.sku;
onMatch(hit);
@@ -50,13 +52,16 @@ export function ScanField({
if (!scan.trim() || feedback?.type === "matched") return;
const timer = setTimeout(() => {
const raw = scan.trim();
if (!lookup(raw.toLowerCase(), items, products)) {
if (!lookup(raw.toLowerCase(), items, products, mode)) {
if (onScanNoMatch) {
onScanNoMatch(raw);
setScan("");
setFeedback(null);
} else {
setFeedback({ type: "miss", text: "No asset id or SKU matches that." });
const missText = mode === "assetId" ? "No item matches that asset ID."
: mode === "sku" ? "No product matches that SKU."
: "No asset id or SKU matches that.";
setFeedback({ type: "miss", text: missText });
}
}
}, 400);
@@ -64,7 +69,7 @@ export function ScanField({
}, [scan, items, products]); // eslint-disable-line react-hooks/exhaustive-deps
return (
<Field label="Scan asset id or SKU">
<Field label={mode === "assetId" ? "Scan asset ID" : mode === "sku" ? "Scan SKU" : "Scan asset id or SKU"}>
<div
style={{
display: "flex",
@@ -80,7 +85,7 @@ export function ScanField({
value={scan}
onChange={(e) => setScan(e.target.value)}
onFocus={(e) => e.currentTarget.select()}
placeholder="K3F9X2 or SKU-XXXXXX"
placeholder={mode === "assetId" ? "123456" : mode === "sku" ? "SKU-XXXXXX" : "123456 or SKU-XXXXXX"}
style={{
border: "none",
outline: "none",
@@ -124,14 +129,19 @@ function lookup(
trimmed: string,
items: Item[],
products?: Product[],
mode: "both" | "assetId" | "sku" = "both",
): ScanResult | null {
const itemHit = items.find((i) => i.assetId.toLowerCase() === trimmed);
if (itemHit) return { kind: "item", item: itemHit };
const skuHitItem = items.find((i) => i.sku.toLowerCase() === trimmed);
if (skuHitItem) return { kind: "item", item: skuHitItem };
if (products) {
const productHit = products.find((p) => p.sku.toLowerCase() === trimmed);
if (productHit) return { kind: "product", product: productHit };
if (mode !== "sku") {
const itemHit = items.find((i) => i.assetId.toLowerCase() === trimmed);
if (itemHit) return { kind: "item", item: itemHit };
}
if (mode !== "assetId") {
const skuHitItem = items.find((i) => i.sku.toLowerCase() === trimmed);
if (skuHitItem) return { kind: "item", item: skuHitItem };
if (products) {
const productHit = products.find((p) => p.sku.toLowerCase() === trimmed);
if (productHit) return { kind: "product", product: productHit };
}
}
return null;
}