From 26b5a43d1b0f9cafbfcca53ce3c99dce867a4e08 Mon Sep 17 00:00:00 2001 From: "CANCERYS\\kw093" Date: Wed, 13 Aug 2025 11:58:38 +0800 Subject: [PATCH] update podetail --- src/components/PoDetail/PoDetail.tsx | 317 ++++++++++++++++++------- src/components/PoDetail/PoInfoCard.tsx | 44 ++-- 2 files changed, 252 insertions(+), 109 deletions(-) diff --git a/src/components/PoDetail/PoDetail.tsx b/src/components/PoDetail/PoDetail.tsx index 5ffb3f8..06ee965 100644 --- a/src/components/PoDetail/PoDetail.tsx +++ b/src/components/PoDetail/PoDetail.tsx @@ -65,6 +65,14 @@ 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[]; @@ -77,6 +85,89 @@ type EntryError = } | 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); @@ -93,6 +184,90 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => { 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); @@ -315,116 +490,84 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => { return ( <> - + + {/* Area1: title */} - {/* {purchaseOrder.code} - {currPoStatus} */} {purchaseOrder.code} -{" "} {t(`${purchaseOrder.status.toLowerCase()}`)} - {true ? ( - - - + + {/* area2: dn info */} + + {/* left side select po */} - - {/* */} - - - - - ) : undefined} - - - {/* */} - {/* scanner */} - {/* */} - - - {/* */} - {/* */} - - {/* tab 1 */} - - + + {/* right side po info */} + + {true ? ( + + + + + + ) : undefined} + + + + + {/* Area4: Main Table */} + - {/* */} - {/* for the collapse button */} {t("itemNo")} {t("itemName")} {t("qty")} {t("processed")} {t("uom")} {t("total weight")} - {/* {t("weight unit")} */} {`${t("price")} (HKD)`} - {/* {t("expiryDate")} */} - {t("status")} - {/* start == true && firstInQty == null ? no hide : hide*/} + {t("status")} {renderFieldCondition(FIRST_IN_FIELD) ? {t("receivedQty")} : undefined} - {/* start == true && firstInQty == null ? hide and disabled : no hide*/} {renderFieldCondition(SECOND_IN_FIELD) ? {t("dnQty")}(以訂單單位計算) : undefined} @@ -437,6 +580,10 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => {
+
+ + {/* area5: selected item info */} + 已選擇: {row.itemNo}-{row.itemName} @@ -486,4 +633,4 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => { ); }; -export default PoDetail; +export default PoDetail; \ No newline at end of file diff --git a/src/components/PoDetail/PoInfoCard.tsx b/src/components/PoDetail/PoInfoCard.tsx index 87fddd4..9d8d7ac 100644 --- a/src/components/PoDetail/PoInfoCard.tsx +++ b/src/components/PoDetail/PoInfoCard.tsx @@ -32,30 +32,25 @@ const PoInfoCard: React.FC = async ( - - - - - - - - + + {/* 第一行:供应商 - 占据全宽 */} + + + {/* 第二行:订单日期和预计到货日期 - 各占一半 */} + + + + = async ( /> +