Browse Source

no message

reset-do-picking-order
[email protected] 2 weeks ago
parent
commit
435d041f5c
1 changed files with 83 additions and 29 deletions
  1. +83
    -29
      src/components/PutAwayScan/PutAwayCamScan.tsx

+ 83
- 29
src/components/PutAwayScan/PutAwayCamScan.tsx View File

@@ -1,7 +1,8 @@
"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { Box, Paper, Typography } from "@mui/material";
import type { Result } from "@zxing/library";
import ReactQrCodeScanner, {
ScannerConfig,
defaultScannerConfig,
@@ -14,6 +15,15 @@ import PutAwayReviewGrid from "./PutAwayReviewGrid";
import type { PutAwayRecord } from ".";
import type { QrCodeScanner as QrCodeScannerType } from "../QrCodeScannerProvider/QrCodeScannerProvider";

/** Find first number after a keyword in a string (e.g. "StockInLine" or "warehouseId"). */
function findIdByRoughMatch(inputString: string, keyword: string): number | null {
const idx = inputString.indexOf(keyword);
if (idx === -1) return null;
const after = inputString.slice(idx + keyword.length);
const match = after.match(/\d+/);
return match ? parseInt(match[0], 10) : null;
}

type Props = {
warehouse: WarehouseResult[];
};
@@ -51,45 +61,86 @@ const PutAwayCamScan: React.FC<Props> = ({ warehouse }) => {
}
}, [scannedWareHouseId]);

// Refs so the scanner (which only gets config on mount) always calls the latest handler and we throttle duplicates
const handleScanRef = useRef<(rawText: string) => void>(() => {});
const lastScannedRef = useRef({ text: "", at: 0 });
const THROTTLE_MS = 2000;

const handleScan = useCallback(
(rawText: string) => {
if (!rawText) return;
const trimmed = (rawText || "").trim();
if (!trimmed) return;
const now = Date.now();
if (
lastScannedRef.current.text === trimmed &&
now - lastScannedRef.current.at < THROTTLE_MS
) {
return;
}

setScanStatus("scanning");

const trySetNumeric = (value: unknown) => {
const num = Number(value);
const done = () => {
lastScannedRef.current = { text: trimmed, at: now };
};

const trySetSilId = (num: number): boolean => {
if (!Number.isFinite(num) || num <= 0) return false;
if (scannedSilId === 0) {
setScannedSilId(num);
} else if (scannedWareHouseId === 0) {
setScannedWareHouseId(num);
}
setScannedSilId(num);
done();
return true;
};
const trySetWarehouseId = (num: number): boolean => {
if (!Number.isFinite(num) || num <= 0) return false;
setScannedWareHouseId(num);
done();
return true;
};

const isFirstScan = scannedSilId === 0;
const isSecondScan = scannedSilId > 0 && scannedWareHouseId === 0;

// 1) Try JSON payload first
// 1) Try JSON
try {
const data = JSON.parse(rawText) as any;
if (data) {
if (scannedSilId === 0) {
if (data.stockInLineId && trySetNumeric(data.stockInLineId)) return;
if (data.value && trySetNumeric(data.value)) return;
} else {
if (data.warehouseId && trySetNumeric(data.warehouseId)) return;
if (data.value && trySetNumeric(data.value)) return;
const data = JSON.parse(trimmed) as Record<string, unknown>;
if (data && typeof data === "object") {
if (isFirstScan) {
if (data.stockInLineId != null && trySetSilId(Number(data.stockInLineId))) return;
if (data.value != null && trySetSilId(Number(data.value))) return;
}
if (isSecondScan) {
if (data.warehouseId != null && trySetWarehouseId(Number(data.warehouseId))) return;
if (data.value != null && trySetWarehouseId(Number(data.value))) return;
}
}
} catch {
// Not JSON – fall through to numeric parsing
// not JSON
}

// 2) Fallback: plain numeric content
if (trySetNumeric(rawText)) return;
// 2) Rough match: "StockInLine" or "warehouseId" + number (same as barcode scanner)
if (isFirstScan) {
const sil =
findIdByRoughMatch(trimmed, "StockInLine") ??
findIdByRoughMatch(trimmed, "stockInLineId");
if (sil != null && trySetSilId(sil)) return;
}
if (isSecondScan) {
const wh =
findIdByRoughMatch(trimmed, "warehouseId") ??
findIdByRoughMatch(trimmed, "WarehouseId");
if (wh != null && trySetWarehouseId(wh)) return;
}

// 3) Plain number
const num = Number(trimmed);
if (isFirstScan && trySetSilId(num)) return;
if (isSecondScan && trySetWarehouseId(num)) return;
},
[scannedSilId, scannedWareHouseId],
);

handleScanRef.current = handleScan;

// Open modal only after both stock-in-line and location (warehouse) are scanned
useEffect(() => {
if (scannedSilId > 0 && scannedWareHouseId > 0) {
@@ -118,14 +169,17 @@ const PutAwayCamScan: React.FC<Props> = ({ warehouse }) => {
return t("Pending scan");
}, [scanStatus, scannedSilId, scannedWareHouseId, t]);

const scannerConfig: ScannerConfig = {
...defaultScannerConfig,
onUpdate: (_err, result) => {
if (result) {
handleScan(result.getText());
}
},
};
const scannerConfig: ScannerConfig = useMemo(
() => ({
...defaultScannerConfig,
onUpdate: (_err: unknown, result?: Result): void => {
if (result) {
handleScanRef.current(result.getText());
}
},
}),
[],
);

return (
<>


Loading…
Cancel
Save