"use client"; import { fetchPoWithStockInLines, PoResult, PurchaseOrderLine, StockInLine, } from "@/app/api/po"; import { Box, Button, ButtonProps, Collapse, Grid, IconButton, Paper, Stack, Tab, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Tabs, TabsProps, TextField, Typography, } from "@mui/material"; import { useTranslation } from "react-i18next"; // import InputDataGrid, { TableRow } from "../InputDataGrid/InputDataGrid"; import { GridColDef, GridRowId, GridRowModel, useGridApiRef, } from "@mui/x-data-grid"; import { checkPolAndCompletePo, fetchPoInClient, fetchStockInLineInfo, PurchaseQcResult, startPo, } from "@/app/api/po/actions"; import { useCallback, useContext, useEffect, useMemo, useState, } from "react"; import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp"; import PoInputGrid from "./PoInputGrid"; import { QcItemWithChecks } from "@/app/api/qc"; import { useSearchParams } from "next/navigation"; import { WarehouseResult } from "@/app/api/warehouse"; import { calculateWeight, returnWeightUnit } from "@/app/utils/formatUtil"; import { CameraContext } from "../Cameras/CameraProvider"; import PoQcStockInModal from "./PoQcStockInModal"; import QrModal from "./QrModal"; import { PlayArrow } from "@mui/icons-material"; import DoneIcon from "@mui/icons-material/Done"; import { getCustomWidth } from "@/app/utils/commonUtil"; import PoInfoCard from "./PoInfoCard"; import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil"; import { fetchPoListClient } from "@/app/api/po/actions"; import { List, ListItem, ListItemButton, ListItemText, Divider } from "@mui/material"; import { useRouter } from "next/navigation"; type Props = { po: PoResult; qc: QcItemWithChecks[]; warehouse: WarehouseResult[]; }; type EntryError = | { [field in keyof StockInLine]?: string; } | undefined; // type PolRow = TableRow, EntryError>; const PoSearchList: React.FC<{ poList: PoResult[]; selectedPoId: number; onSelect: (po: PoResult) => void; }> = ({ poList, selectedPoId, onSelect }) => { const { t } = useTranslation("purchaseOrder"); const [searchTerm, setSearchTerm] = useState(''); const filteredPoList = useMemo(() => { if (searchTerm.trim() === '') { return poList; } return poList.filter(poItem => poItem.code.toLowerCase().includes(searchTerm.toLowerCase()) || poItem.supplier?.toLowerCase().includes(searchTerm.toLowerCase()) || t(`${poItem.status.toLowerCase()}`).toLowerCase().includes(searchTerm.toLowerCase()) ); }, [poList, searchTerm, t]); return ( {t("Purchase Orders")} setSearchTerm(e.target.value)} sx={{ mb: 2 }} InputProps={{ startAdornment: ( ), }} /> {filteredPoList.map((poItem, index) => (
onSelect(poItem)} sx={{ "&.Mui-selected": { backgroundColor: "primary.light", "&:hover": { backgroundColor: "primary.light", }, }, }} > {poItem.code} } secondary={ {t(`${poItem.status.toLowerCase()}`)} } /> {index < filteredPoList.length - 1 && }
))}
{searchTerm && ( {t("Found")} {filteredPoList.length} {t("of")} {poList.length} {t("items")} )}
); }; const PoDetail: React.FC = ({ po, qc, warehouse }) => { const cameras = useContext(CameraContext); console.log(cameras); const { t } = useTranslation("purchaseOrder"); const apiRef = useGridApiRef(); const [purchaseOrder, setPurchaseOrder] = useState({ ...po }); const [rows, setRows] = useState( purchaseOrder.pol || [], ); const [row, setRow] = useState(rows[0]); const [stockInLine, setStockInLine] = useState(rows[0].stockInLine); const [processedQty, setProcessedQty] = useState(rows[0].processed); const searchParams = useSearchParams(); // const [currPoStatus, setCurrPoStatus] = useState(purchaseOrder.status); const router = useRouter(); const [poList, setPoList] = useState([]); const [selectedPoId, setSelectedPoId] = useState(po.id); const currentPoId = searchParams.get('id'); const [searchTerm, setSearchTerm] = useState(''); const filteredPoList = useMemo(() => { if (searchTerm.trim() === '') { return poList; } return poList.filter(poItem => poItem.code.toLowerCase().includes(searchTerm.toLowerCase()) || poItem.supplier?.toLowerCase().includes(searchTerm.toLowerCase()) || t(`${poItem.status.toLowerCase()}`).toLowerCase().includes(searchTerm.toLowerCase()) ); }, [poList, searchTerm, t]); const fetchPoList = useCallback(async () => { try { const result = await fetchPoListClient({ limit: 20, offset: 0 }); if (result && result.records) { setPoList(result.records); } } catch (error) { console.error("Failed to fetch PO list:", error); } }, []); const handlePoSelect = useCallback( (selectedPo: PoResult) => { setSelectedPoId(selectedPo.id); router.push(`/po/edit?id=${selectedPo.id}&start=true`, { scroll: false }); }, [router] ); const fetchPoDetail = useCallback(async (poId: string) => { try { const result = await fetchPoInClient(parseInt(poId)); if (result) { setPurchaseOrder(result); setRows(result.pol || []); if (result.pol && result.pol.length > 0) { setRow(result.pol[0]); setStockInLine(result.pol[0].stockInLine); setProcessedQty(result.pol[0].processed); } } } catch (error) { console.error("Failed to fetch PO detail:", error); } }, []); useEffect(() => { if (currentPoId && currentPoId !== selectedPoId.toString()) { setSelectedPoId(parseInt(currentPoId)); fetchPoDetail(currentPoId); } }, [currentPoId, selectedPoId, fetchPoDetail]); useEffect(() => { fetchPoList(); }, [fetchPoList]); useEffect(() => { if (currentPoId) { setSelectedPoId(parseInt(currentPoId)); } }, [currentPoId]); const removeParam = (paramToRemove: string) => { const newParams = new URLSearchParams(searchParams.toString()); newParams.delete(paramToRemove); window.history.replaceState({}, '', `${window.location.pathname}?${newParams}`); }; const handleCompletePo = useCallback(async () => { const checkRes = await checkPolAndCompletePo(purchaseOrder.id); console.log(checkRes); const newPo = await fetchPoInClient(purchaseOrder.id); setPurchaseOrder(newPo); }, [purchaseOrder.id]); const handleStartPo = useCallback(async () => { const startRes = await startPo(purchaseOrder.id); console.log(startRes); const newPo = await fetchPoInClient(purchaseOrder.id); setPurchaseOrder(newPo); }, [purchaseOrder.id]); useEffect(() => { setRows(purchaseOrder.pol || []); }, [purchaseOrder]); function Row(props: { row: PurchaseOrderLine }) { const { row } = props; const [firstReceiveQty, setFirstReceiveQty] = useState() const [secondReceiveQty, setSecondReceiveQty] = useState() const [open, setOpen] = useState(false); const [processedQty, setProcessedQty] = useState(row.processed); const [currStatus, setCurrStatus] = useState(row.status); const [stockInLine, setStockInLine] = useState(row.stockInLine); const totalWeight = useMemo( () => calculateWeight(row.qty, row.uom), [row.qty, row.uom], ); const weightUnit = useMemo( () => returnWeightUnit(row.uom), [row.uom], ); useEffect(() => { if (processedQty === row.qty) { setCurrStatus("completed".toUpperCase()); } else if (processedQty > 0) { setCurrStatus("receiving".toUpperCase()); } else { setCurrStatus("pending".toUpperCase()); } }, [processedQty, row.qty]); return ( <> *": { borderBottom: "unset" }, color: "black" }}> {/* setOpen(!open)} > {open ? : } */} {row.itemNo} {row.itemName} {integerFormatter.format(row.qty)} {integerFormatter.format(processedQty)} {row.uom?.code} {decimalFormatter.format(totalWeight)} {weightUnit} {/* {weightUnit} */} {decimalFormatter.format(row.price)} {/* {row.expiryDate} */} {t(`${currStatus.toLowerCase()}`)} 0 {/* */} {/* */} {/* */} {/* */} {/* */} {/*
*/} {/*
*/} {/*
*/} {/*
*/} ); } const [tabIndex, setTabIndex] = useState(0); const handleTabChange = useCallback>( (_e, newValue) => { setTabIndex(newValue); }, [], ); const [isOpenScanner, setOpenScanner] = useState(false); const onOpenScanner = useCallback(() => { setOpenScanner(true); }, []); const onCloseScanner = useCallback(() => { setOpenScanner(false); }, []); const [itemInfo, setItemInfo] = useState< StockInLine & { warehouseId?: number } >(); const [putAwayOpen, setPutAwayOpen] = useState(false); // const [scannedInfo, setScannedInfo] = useState({} as QrCodeInfo); const closePutAwayModal = useCallback(() => { setPutAwayOpen(false); setItemInfo(undefined); }, []); const openPutAwayModal = useCallback(() => { setPutAwayOpen(true); }, []); const buttonData = useMemo(() => { switch (purchaseOrder.status.toLowerCase()) { case "pending": return { buttonName: "start", title: t("Do you want to start?"), confirmButtonText: t("Start"), successTitle: t("Start Success"), errorTitle: t("Start Fail"), buttonText: t("Start PO"), buttonIcon: , buttonColor: "success", disabled: false, onClick: handleStartPo, }; case "receiving": return { buttonName: "complete", title: t("Do you want to complete?"), confirmButtonText: t("Complete"), successTitle: t("Complete Success"), errorTitle: t("Complete Fail"), buttonText: t("Complete PO"), buttonIcon: , buttonColor: "info", disabled: false, onClick: handleCompletePo, }; default: return { buttonName: "complete", title: t("Do you want to complete?"), confirmButtonText: t("Complete"), successTitle: t("Complete Success"), errorTitle: t("Complete Fail"), buttonText: t("Complete PO"), buttonIcon: , buttonColor: "info", disabled: true, }; // break; } }, [purchaseOrder.status, t, handleStartPo, handleCompletePo]); const FIRST_IN_FIELD = "firstInQty" const SECOND_IN_FIELD = "secondInQty" const renderFieldCondition = useCallback((field: "firstInQty" | "secondInQty"): boolean => { switch (field) { case FIRST_IN_FIELD: return true; case SECOND_IN_FIELD: return true; default: return false; // Default case } }, []); return ( <> {/* Area1: title */} {purchaseOrder.code} -{" "} {t(`${purchaseOrder.status.toLowerCase()}`)} {/* area2: dn info */} {/* left side select po */} {/* right side po info */} {true ? ( ) : undefined} {/* Area4: Main Table */} {t("itemNo")} {t("itemName")} {t("qty")} {t("processed")} {t("uom")} {t("total weight")} {`${t("price")} (HKD)`} {t("status")} {renderFieldCondition(FIRST_IN_FIELD) ? {t("receivedQty")} : undefined} {renderFieldCondition(SECOND_IN_FIELD) ? {t("dnQty")}(以訂單單位計算) : undefined} {rows.map((row) => ( ))}
{/* area5: selected item info */} 已選擇: {row.itemNo}-{row.itemName}
{/* tab 2 */} {/* */}
{itemInfo !== undefined && ( <> )} ); }; export default PoDetail;