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;
+