From 3b33e17cff502e076ba95eea8251fa628997e45c Mon Sep 17 00:00:00 2001 From: kelvinsuen Date: Wed, 17 Sep 2025 11:33:27 +0800 Subject: [PATCH] update qr code scan modal --- src/app/api/qrcode/index.ts | 3 +- src/components/PutAwayScan/PutAwayScan.tsx | 88 ++--------- .../QrCodeScannerProvider.tsx | 140 +++++++++++++++--- 3 files changed, 136 insertions(+), 95 deletions(-) diff --git a/src/app/api/qrcode/index.ts b/src/app/api/qrcode/index.ts index 2a09982..9e5dfcf 100644 --- a/src/app/api/qrcode/index.ts +++ b/src/app/api/qrcode/index.ts @@ -6,10 +6,11 @@ import { serverFetchJson } from "../../utils/fetchUtil"; import { BASE_API_URL } from "../../../config/api"; export interface QrCodeInfo { + value: string; // warehouse qrcode warehouseId?: number; // item qrcode stockInLineId?: number; - itemId: number; + itemId?: number; lotNo?: string; } diff --git a/src/components/PutAwayScan/PutAwayScan.tsx b/src/components/PutAwayScan/PutAwayScan.tsx index 7c53514..a4d21b5 100644 --- a/src/components/PutAwayScan/PutAwayScan.tsx +++ b/src/components/PutAwayScan/PutAwayScan.tsx @@ -52,10 +52,8 @@ const PutAwayScan: React.FC = ({ warehouse }) => { useEffect(() => { if (!scanner.isScanning) { scanner.startScan(); - console.log("%c Scanning started ", "color:cyan"); } else if (scanner.isScanning) { scanner.stopScan(); - console.log("%c Scanning stopped ", "color:cyan"); } }, []); @@ -87,37 +85,6 @@ const PutAwayScan: React.FC = ({ warehouse }) => { setOpenPutAwayModal(false); } - - const findIdByRoughMatch = (inputString : string, keyword : string) => { - const keywordIndex = inputString.indexOf(keyword); - - if (keywordIndex === -1) { - return { - keywordFound: false, - number: null, - message: `${keyword} not found in the input`, - }; - } - - const substringAfterKeyword = inputString.slice(keywordIndex + keyword.length); - - const numberMatch = substringAfterKeyword.match(/\d+/); - - if (!numberMatch) { - return { - keywordFound: true, - number: null, - message: `No valid number found after ${keyword}`, - }; - } - - return { - keywordFound: true, - number: parseInt(numberMatch[0], 10), - message: `Found ${keyword} at index ${keywordIndex}, first number found after is: ${numberMatch[0]}`, - }; - } - const addPutAwayHistory = (putAwayData: PutAwayRecord) => { console.log("%c Added new data to Putaway history: ", "color:orange", putAwayData); const newPutaway = { ...putAwayData, id: putAwayHistory.length + 1 }; @@ -133,51 +100,22 @@ const PutAwayScan: React.FC = ({ warehouse }) => { // Get Scanned Values useEffect(() => { - if (scanner.values.length > 0) {//} && !Boolean(itemDetail)) { - const scannedValues = scanner.values[0]; - console.log("%c Scanned: ", "color:cyan", scannedValues); - - if (scannedValues.substring(0, 8) == "{2fitest") { // DEBUGGING - const number = scannedValues.substring(8, scannedValues.length - 1); - if (/^\d+$/.test(number)) { // Check if number contains only digits - console.log("%c DEBUG: Testing SIL ID: ", "color:cyan", number); - if (scannedSilId === 0) { - setScannedSilId(Number(number)); - } else setScannedWareHouseId(Number(number)); - } else { - console.error("%c DEBUG: Invalid number format: ", "color:red", number); - resetScan(); - } - return; - } - try { - const data: QrCodeInfo = JSON.parse(scannedValues); - console.log("%c Scanned with data", "color:green", data); - - if (scannedSilId == 0) { // Initial State - if (data.stockInLineId !== undefined) { - setScannedSilId(Number(data.stockInLineId)); - } else resetScan("Cannot read Stock In Line Id"); - } else { // Processing - if (data.warehouseId !== undefined) { - setScannedWareHouseId(Number(data.warehouseId)); - } else resetScan("Cannot read Warehouse Id"); - } - } catch (error) { // Rought match for other scanner -- Pending Review - if (scannedSilId == 0) { - const silId = findIdByRoughMatch(scannedValues, "StockInLine").number ?? 0; - setScannedSilId(silId); - - } else { - const whId = findIdByRoughMatch(scannedValues, "warehouseId").number ?? 0; - setScannedWareHouseId(whId); - } - - resetScan(String(error)); + if (scanner.result) { + const data = scanner.result; + if (scannedSilId == 0) { // Initial State + if (!isNaN(Number(data.value))) { setScannedSilId(Number(data.value)); } + else if (data.stockInLineId) { + setScannedSilId(Number(data.stockInLineId)); + } else resetScan("Cannot read Stock In Line Id"); + } else { // Processing + if (!isNaN(Number(data.value))) { setScannedWareHouseId(Number(data.value)); } + else if (data.warehouseId) { + setScannedWareHouseId(Number(data.warehouseId)); + } else resetScan("Cannot read Warehouse Id"); } scanner.resetScan(); } - }, [scanner.values]); + }, [scanner.result]); return (<> void; stopScan: () => void; resetScan: () => void; + result: QrCodeInfo | undefined; } interface QrCodeScannerProviderProps { @@ -32,19 +34,73 @@ const QrCodeScannerProvider: React.FC = ({ const [keys, setKeys] = useState([]); const [leftCurlyBraceCount, setLeftCurlyBraceCount] = useState(0); const [rightCurlyBraceCount, setRightCurlyBraceCount] = useState(0); - const resetQrCodeScanner = useCallback(() => { + const [scanResult, setScanResult] = useState() + + const resetScannerInput = useCallback(() => { + setKeys(() => []); + setLeftCurlyBraceCount(() => 0); + setRightCurlyBraceCount(() => 0); + }, []); + + const resetQrCodeScanner = useCallback((error : string = "") => { setQrCodeScannerValues(() => []); + setScanResult(undefined); + resetScannerInput(); + + console.log("%c Scanner Reset", "color:cyan"); + + if (error.length > 0) { + console.log("%c Error:", "color:red", error); + } }, []); const startQrCodeScanner = useCallback(() => { resetQrCodeScanner(); setIsScanning(() => true); + console.log("%c Scanning started ", "color:cyan"); }, []); const endQrCodeScanner = useCallback(() => { setIsScanning(() => false); + console.log("%c Scanning stopped ", "color:cyan"); }, []); + // Find by rough match, return 0 if not found + const findIdByRoughMatch = (inputString : string, keyword : string) => { + console.log(`%c Performed rough match for ${keyword} within ${inputString}`, "color:brown"); + + const keywordIndex = inputString.indexOf(keyword); + + let result : {keywordFound: boolean; number: number | null; message: string} = { + keywordFound: false, + number: null, + message: `${keyword} not found in the input`, + }; + + if (keywordIndex !== -1) { + const substringAfterKeyword = inputString.slice(keywordIndex + keyword.length); + + const numberMatch = substringAfterKeyword.match(/\d+/); + + if (!numberMatch) { + result = { + keywordFound: true, + number: null, + message: `No valid number found after ${keyword}`, + }; + } else { + result = { + keywordFound: true, + number: parseInt(numberMatch[0], 10), + message: `Found ${keyword} at index ${keywordIndex}, first number found after is: ${numberMatch[0]}`, + }; + } + } + + console.log(`%c ${result.message}`, "color:brown"); + return result; + }; + // Check the KeyDown useEffect(() => { if (isScanning) { @@ -70,27 +126,72 @@ const QrCodeScannerProvider: React.FC = ({ // Update Qr Code Scanner Values useEffect(() => { - if ( - leftCurlyBraceCount !== 0 && - rightCurlyBraceCount !== 0 && - leftCurlyBraceCount === rightCurlyBraceCount - ) { - const startBrace = keys.indexOf("{"); - const endBrace = keys.lastIndexOf("}"); - setQrCodeScannerValues((value) => [ - ...value, - keys.join("").substring(startBrace, endBrace + 1), - ]); - console.log(keys); - console.log("%c QR Scanner Values:", "color:cyan", qrCodeScannerValues); - - // reset - setKeys(() => []); - setLeftCurlyBraceCount(() => 0); - setRightCurlyBraceCount(() => 0); + if (rightCurlyBraceCount > leftCurlyBraceCount || leftCurlyBraceCount > 1) { // Prevent multiple scan + resetQrCodeScanner("Too many scans at once"); + } else { + if (leftCurlyBraceCount == 1 && keys.length == 1) + { console.log("%c Scan detected, waiting for inputs...", "color:cyan"); } + if ( + leftCurlyBraceCount !== 0 && + rightCurlyBraceCount !== 0 && + leftCurlyBraceCount === rightCurlyBraceCount + ) { + const startBrace = keys.indexOf("{"); + const endBrace = keys.lastIndexOf("}"); + setQrCodeScannerValues((value) => [ + ...value, + keys.join("").substring(startBrace, endBrace + 1), + ]); + // console.log(keys); + // console.log("%c QR Scanner Values:", "color:cyan", qrCodeScannerValues); + + resetScannerInput(); + } } }, [keys, leftCurlyBraceCount, rightCurlyBraceCount]); + useEffect(() => { + if (qrCodeScannerValues.length > 0) { + const scannedValues = qrCodeScannerValues[0]; + console.log("%c Scanned Result: ", "color:cyan", scannedValues); + + if (scannedValues.substring(0, 8) == "{2fitest") { // DEBUGGING + const number = scannedValues.substring(8, scannedValues.length - 1); + if (/^\d+$/.test(number)) { // Check if number contains only digits + console.log("%c DEBUG: detected ID: ", "color:pink", number); + const debugValue = { + value: number + } + setScanResult(debugValue); + } else { + resetQrCodeScanner("DEBUG -- Invalid number format: " + number); + } + return; + } + + try { + const data: QrCodeInfo = JSON.parse(scannedValues); + console.log("%c Parsed scan data", "color:green", data); + + const content = scannedValues.substring(1, scannedValues.length - 1); + data.value = content; + setScanResult(data); + + } catch (error) { // Rought match for other scanner input -- Pending Review + const silId = findIdByRoughMatch(scannedValues, "StockInLine").number ?? 0; + + if (silId == 0) { + const whId = findIdByRoughMatch(scannedValues, "warehouseId").number ?? 0; + setScanResult({...scanResult, stockInLineId: whId, value: whId.toString()}); + } else { setScanResult({...scanResult, stockInLineId: silId, value: silId.toString()}); } + + resetQrCodeScanner(String(error)); + } + + // resetQrCodeScanner(); + } + }, [qrCodeScannerValues]); + return ( = ({ startScan: startQrCodeScanner, stopScan: endQrCodeScanner, resetScan: resetQrCodeScanner, + result: scanResult, }} > {children}