diff --git a/src/app/(main)/putAwayCam/page.tsx b/src/app/(main)/putAwayCam/page.tsx new file mode 100644 index 0000000..c55cb3a --- /dev/null +++ b/src/app/(main)/putAwayCam/page.tsx @@ -0,0 +1,37 @@ +import PutAwayCamScanWrapper from "@/components/PutAwayScan/PutAwayCamScanWrapper"; +import { I18nProvider, getServerI18n } from "@/i18n"; +import Stack from "@mui/material/Stack"; +import Typography from "@mui/material/Typography"; +import { Metadata } from "next"; +import { Suspense } from "react"; + +export const metadata: Metadata = { + title: "Put Away Camera", +}; + +const PutAwayCamPage: React.FC = async () => { + const { t } = await getServerI18n("putAway"); + + return ( + <> + + + {t("Put Away")} + + + + }> + + + + + ); +}; + +export default PutAwayCamPage; + diff --git a/src/components/PutAwayScan/PutAwayCamScan.tsx b/src/components/PutAwayScan/PutAwayCamScan.tsx new file mode 100644 index 0000000..85a0b9a --- /dev/null +++ b/src/components/PutAwayScan/PutAwayCamScan.tsx @@ -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 = ({ warehouse }) => { + const { t } = useTranslation("putAway"); + + const [scanStatus, setScanStatus] = useState("pending"); + const [openPutAwayModal, setOpenPutAwayModal] = useState(false); + const [scannedSilId, setScannedSilId] = useState(0); + const [scannedWareHouseId, setScannedWareHouseId] = useState(0); + const [putAwayHistory, setPutAwayHistory] = useState([]); + + 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 ( + <> + + + {displayText} + + + + + + + + {putAwayHistory.length > 0 && ( + <> + + {t("putAwayHistory")} + + + + )} + + + + ); +}; + +export default PutAwayCamScan; + diff --git a/src/components/PutAwayScan/PutAwayCamScanWrapper.tsx b/src/components/PutAwayScan/PutAwayCamScanWrapper.tsx new file mode 100644 index 0000000..841ff10 --- /dev/null +++ b/src/components/PutAwayScan/PutAwayCamScanWrapper.tsx @@ -0,0 +1,19 @@ +import React from "react"; +import GeneralLoading from "../General/GeneralLoading"; +import PutAwayCamScan from "./PutAwayCamScan"; +import { fetchWarehouseList } from "@/app/api/warehouse"; + +interface SubComponents { + Loading: typeof GeneralLoading; +} + +const PutAwayCamScanWrapper: React.FC & SubComponents = async () => { + const [warehouse] = await Promise.all([fetchWarehouseList()]); + + return ; +}; + +PutAwayCamScanWrapper.Loading = GeneralLoading; + +export default PutAwayCamScanWrapper; +