|
|
@@ -0,0 +1,179 @@ |
|
|
|
|
|
"use client"; |
|
|
|
|
|
|
|
|
|
|
|
import { useCallback, useEffect, useMemo, useState } from "react"; |
|
|
|
|
|
import { Box, Paper, Typography } from "@mui/material"; |
|
|
|
|
|
import ReactQrCodeScanner, { |
|
|
|
|
|
ScannerConfig, |
|
|
|
|
|
defaultScannerConfig, |
|
|
|
|
|
} from "../ReactQrCodeScanner/ReactQrCodeScanner"; |
|
|
|
|
|
import { WarehouseResult } from "@/app/api/warehouse"; |
|
|
|
|
|
import { useTranslation } from "react-i18next"; |
|
|
|
|
|
import { QrCodeScanner as QrCodeIcon } from "@mui/icons-material"; |
|
|
|
|
|
import PutAwayModal from "./PutAwayModal"; |
|
|
|
|
|
import PutAwayReviewGrid from "./PutAwayReviewGrid"; |
|
|
|
|
|
import type { PutAwayRecord } from "."; |
|
|
|
|
|
import type { QrCodeScanner as QrCodeScannerType } from "../QrCodeScannerProvider/QrCodeScannerProvider"; |
|
|
|
|
|
|
|
|
|
|
|
type Props = { |
|
|
|
|
|
warehouse: WarehouseResult[]; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
type ScanStatusType = "pending" | "scanning"; |
|
|
|
|
|
|
|
|
|
|
|
const dummyScanner: QrCodeScannerType = { |
|
|
|
|
|
values: [], |
|
|
|
|
|
isScanning: false, |
|
|
|
|
|
startScan: () => {}, |
|
|
|
|
|
stopScan: () => {}, |
|
|
|
|
|
resetScan: () => {}, |
|
|
|
|
|
result: undefined, |
|
|
|
|
|
state: "pending", |
|
|
|
|
|
error: undefined, |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const PutAwayCamScan: React.FC<Props> = ({ warehouse }) => { |
|
|
|
|
|
const { t } = useTranslation("putAway"); |
|
|
|
|
|
|
|
|
|
|
|
const [scanStatus, setScanStatus] = useState<ScanStatusType>("pending"); |
|
|
|
|
|
const [openPutAwayModal, setOpenPutAwayModal] = useState(false); |
|
|
|
|
|
const [scannedSilId, setScannedSilId] = useState<number>(0); |
|
|
|
|
|
const [scannedWareHouseId, setScannedWareHouseId] = useState<number>(0); |
|
|
|
|
|
const [putAwayHistory, setPutAwayHistory] = useState<PutAwayRecord[]>([]); |
|
|
|
|
|
|
|
|
|
|
|
const addPutAwayHistory = (putAwayData: PutAwayRecord) => { |
|
|
|
|
|
const newPutaway = { ...putAwayData, id: putAwayHistory.length + 1 }; |
|
|
|
|
|
setPutAwayHistory((prev) => [...prev, newPutaway]); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const handleSetDefaultWarehouseId = useCallback((warehouseId: number) => { |
|
|
|
|
|
if (scannedWareHouseId === 0) { |
|
|
|
|
|
setScannedWareHouseId(warehouseId); |
|
|
|
|
|
} |
|
|
|
|
|
}, [scannedWareHouseId]); |
|
|
|
|
|
|
|
|
|
|
|
const handleScan = useCallback( |
|
|
|
|
|
(rawText: string) => { |
|
|
|
|
|
if (!rawText) return; |
|
|
|
|
|
|
|
|
|
|
|
setScanStatus("scanning"); |
|
|
|
|
|
|
|
|
|
|
|
const trySetNumeric = (value: unknown) => { |
|
|
|
|
|
const num = Number(value); |
|
|
|
|
|
if (!Number.isFinite(num) || num <= 0) return false; |
|
|
|
|
|
if (scannedSilId === 0) { |
|
|
|
|
|
setScannedSilId(num); |
|
|
|
|
|
} else if (scannedWareHouseId === 0) { |
|
|
|
|
|
setScannedWareHouseId(num); |
|
|
|
|
|
} |
|
|
|
|
|
return true; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// 1) Try JSON payload first |
|
|
|
|
|
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; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} catch { |
|
|
|
|
|
// Not JSON – fall through to numeric parsing |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 2) Fallback: plain numeric content |
|
|
|
|
|
if (trySetNumeric(rawText)) return; |
|
|
|
|
|
}, |
|
|
|
|
|
[scannedSilId, scannedWareHouseId], |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
if (scannedSilId > 0) { |
|
|
|
|
|
setOpenPutAwayModal(true); |
|
|
|
|
|
setScanStatus("pending"); |
|
|
|
|
|
} |
|
|
|
|
|
}, [scannedSilId]); |
|
|
|
|
|
|
|
|
|
|
|
const closeModal = () => { |
|
|
|
|
|
setScannedSilId(0); |
|
|
|
|
|
setScannedWareHouseId(0); |
|
|
|
|
|
setOpenPutAwayModal(false); |
|
|
|
|
|
setScanStatus("pending"); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const displayText = useMemo(() => { |
|
|
|
|
|
if (scanStatus === "scanning") { |
|
|
|
|
|
return t("Scanning"); |
|
|
|
|
|
} |
|
|
|
|
|
if (scannedSilId > 0) { |
|
|
|
|
|
return t("Scanned, opening detail"); |
|
|
|
|
|
} |
|
|
|
|
|
return t("Pending scan"); |
|
|
|
|
|
}, [scanStatus, scannedSilId, t]); |
|
|
|
|
|
|
|
|
|
|
|
const scannerConfig: ScannerConfig = { |
|
|
|
|
|
...defaultScannerConfig, |
|
|
|
|
|
onUpdate: (_err, result) => { |
|
|
|
|
|
if (result) { |
|
|
|
|
|
handleScan(result.getText()); |
|
|
|
|
|
} |
|
|
|
|
|
}, |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
|
<> |
|
|
|
|
|
<Paper |
|
|
|
|
|
sx={{ |
|
|
|
|
|
display: "flex", |
|
|
|
|
|
flexDirection: "column", |
|
|
|
|
|
justifyContent: "center", |
|
|
|
|
|
alignItems: "center", |
|
|
|
|
|
textAlign: "center", |
|
|
|
|
|
gap: 2, |
|
|
|
|
|
p: 2, |
|
|
|
|
|
}} |
|
|
|
|
|
> |
|
|
|
|
|
<Typography variant="h4" sx={{ mb: 1 }}> |
|
|
|
|
|
{displayText} |
|
|
|
|
|
</Typography> |
|
|
|
|
|
<QrCodeIcon sx={{ fontSize: 80, mb: 1 }} color="primary" /> |
|
|
|
|
|
<Box |
|
|
|
|
|
sx={{ |
|
|
|
|
|
width: "100%", |
|
|
|
|
|
maxWidth: 480, |
|
|
|
|
|
aspectRatio: "4 / 3", |
|
|
|
|
|
overflow: "hidden", |
|
|
|
|
|
}} |
|
|
|
|
|
> |
|
|
|
|
|
<ReactQrCodeScanner scannerConfig={scannerConfig} /> |
|
|
|
|
|
</Box> |
|
|
|
|
|
</Paper> |
|
|
|
|
|
|
|
|
|
|
|
{putAwayHistory.length > 0 && ( |
|
|
|
|
|
<> |
|
|
|
|
|
<Typography variant="h5" sx={{ mt: 3, mb: 1 }}> |
|
|
|
|
|
{t("putAwayHistory")} |
|
|
|
|
|
</Typography> |
|
|
|
|
|
<PutAwayReviewGrid putAwayHistory={putAwayHistory} /> |
|
|
|
|
|
</> |
|
|
|
|
|
)} |
|
|
|
|
|
|
|
|
|
|
|
<PutAwayModal |
|
|
|
|
|
open={openPutAwayModal} |
|
|
|
|
|
onClose={closeModal} |
|
|
|
|
|
warehouse={warehouse} |
|
|
|
|
|
stockInLineId={scannedSilId} |
|
|
|
|
|
warehouseId={scannedWareHouseId} |
|
|
|
|
|
scanner={dummyScanner} |
|
|
|
|
|
addPutAwayHistory={addPutAwayHistory} |
|
|
|
|
|
onSetDefaultWarehouseId={handleSetDefaultWarehouseId} |
|
|
|
|
|
/> |
|
|
|
|
|
</> |
|
|
|
|
|
); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
export default PutAwayCamScan; |
|
|
|
|
|
|