FPSMS-frontend
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 

722 行
23 KiB

  1. "use client";
  2. import {
  3. fetchPoWithStockInLines,
  4. PoResult,
  5. PurchaseOrderLine,
  6. StockInLine,
  7. } from "@/app/api/po";
  8. import {
  9. Box,
  10. Button,
  11. ButtonProps,
  12. Collapse,
  13. Grid,
  14. IconButton,
  15. Paper,
  16. Stack,
  17. Tab,
  18. Table,
  19. TableBody,
  20. TableCell,
  21. TableContainer,
  22. TableHead,
  23. TableRow,
  24. Tabs,
  25. TabsProps,
  26. TextField,
  27. Typography,
  28. Checkbox,
  29. FormControlLabel,
  30. } from "@mui/material";
  31. import { useTranslation } from "react-i18next";
  32. // import InputDataGrid, { TableRow } from "../InputDataGrid/InputDataGrid";
  33. import {
  34. GridColDef,
  35. GridRowId,
  36. GridRowModel,
  37. useGridApiRef,
  38. } from "@mui/x-data-grid";
  39. import {
  40. checkPolAndCompletePo,
  41. fetchPoInClient,
  42. fetchStockInLineInfo,
  43. PurchaseQcResult,
  44. startPo,
  45. } from "@/app/api/po/actions";
  46. import {
  47. useCallback,
  48. useContext,
  49. useEffect,
  50. useMemo,
  51. useState,
  52. } from "react";
  53. import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
  54. import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp";
  55. import PoInputGrid from "./PoInputGrid";
  56. import { QcItemWithChecks } from "@/app/api/qc";
  57. import { useRouter, useSearchParams, usePathname } from "next/navigation";
  58. import { WarehouseResult } from "@/app/api/warehouse";
  59. import { calculateWeight, returnWeightUnit } from "@/app/utils/formatUtil";
  60. import { CameraContext } from "../Cameras/CameraProvider";
  61. import PoQcStockInModal from "./PoQcStockInModal";
  62. import QrModal from "./QrModal";
  63. import { PlayArrow } from "@mui/icons-material";
  64. import DoneIcon from "@mui/icons-material/Done";
  65. import { getCustomWidth } from "@/app/utils/commonUtil";
  66. import PoInfoCard from "./PoInfoCard";
  67. import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil";
  68. import { fetchPoListClient } from "@/app/api/po/actions";
  69. import { List, ListItem, ListItemButton, ListItemText, Divider } from "@mui/material";
  70. import { createStockInLine } from "@/app/api/dashboard/actions";
  71. //import { useRouter } from "next/navigation";
  72. type Props = {
  73. po: PoResult;
  74. qc: QcItemWithChecks[];
  75. warehouse: WarehouseResult[];
  76. };
  77. type EntryError =
  78. | {
  79. [field in keyof StockInLine]?: string;
  80. }
  81. | undefined;
  82. // type PolRow = TableRow<Partial<StockInLine>, EntryError>;
  83. const PoSearchList: React.FC<{
  84. poList: PoResult[];
  85. selectedPoId: number;
  86. onSelect: (po: PoResult) => void;
  87. }> = ({ poList, selectedPoId, onSelect }) => {
  88. const { t } = useTranslation("purchaseOrder");
  89. const [searchTerm, setSearchTerm] = useState('');
  90. const filteredPoList = useMemo(() => {
  91. if (searchTerm.trim() === '') {
  92. return poList;
  93. }
  94. return poList.filter(poItem =>
  95. poItem.code.toLowerCase().includes(searchTerm.toLowerCase()) ||
  96. poItem.supplier?.toLowerCase().includes(searchTerm.toLowerCase()) ||
  97. t(`${poItem.status.toLowerCase()}`).toLowerCase().includes(searchTerm.toLowerCase())
  98. );
  99. }, [poList, searchTerm, t]);
  100. return (
  101. <Paper sx={{ p: 2, maxHeight: "400px", overflow: "auto", minWidth: "300px" }}>
  102. <Typography variant="h6" gutterBottom>
  103. {t("Purchase Orders")}
  104. </Typography>
  105. <TextField
  106. label={t("Search")}
  107. variant="outlined"
  108. size="small"
  109. fullWidth
  110. value={searchTerm}
  111. onChange={(e) => setSearchTerm(e.target.value)}
  112. sx={{ mb: 2 }}
  113. InputProps={{
  114. startAdornment: (
  115. <Typography variant="body2" color="text.secondary" sx={{ mr: 1 }}>
  116. </Typography>
  117. ),
  118. }}
  119. />
  120. <List dense sx={{ width: '100%' }}>
  121. {filteredPoList.map((poItem, index) => (
  122. <div key={poItem.id}>
  123. <ListItem disablePadding sx={{ width: '100%' }}>
  124. <ListItemButton
  125. selected={selectedPoId === poItem.id}
  126. onClick={() => onSelect(poItem)}
  127. sx={{
  128. width: '100%',
  129. "&.Mui-selected": {
  130. backgroundColor: "primary.light",
  131. "&:hover": {
  132. backgroundColor: "primary.light",
  133. },
  134. },
  135. }}
  136. >
  137. <ListItemText
  138. primary={
  139. <Typography variant="body2" sx={{ wordBreak: 'break-all' }}>
  140. {poItem.code}
  141. </Typography>
  142. }
  143. secondary={
  144. <Typography variant="caption" color="text.secondary">
  145. {t(`${poItem.status.toLowerCase()}`)}
  146. </Typography>
  147. }
  148. />
  149. </ListItemButton>
  150. </ListItem>
  151. {index < filteredPoList.length - 1 && <Divider />}
  152. </div>
  153. ))}
  154. </List>
  155. {searchTerm && (
  156. <Typography variant="caption" color="text.secondary" sx={{ mt: 1, display: "block" }}>
  157. {t("Found")} {filteredPoList.length} {t("of")} {poList.length} {t("items")}
  158. </Typography>
  159. )}
  160. </Paper>
  161. );
  162. };
  163. const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => {
  164. const cameras = useContext(CameraContext);
  165. console.log(cameras);
  166. const { t } = useTranslation("purchaseOrder");
  167. const apiRef = useGridApiRef();
  168. const [purchaseOrder, setPurchaseOrder] = useState({ ...po });
  169. const [rows, setRows] = useState<PurchaseOrderLine[]>(
  170. purchaseOrder.pol || [],
  171. );
  172. const pathname = usePathname()
  173. const searchParams = useSearchParams();
  174. const [row, setRow] = useState<PurchaseOrderLine>({});
  175. const [stockInLine, setStockInLine] = useState<StockInLine[]>([]);
  176. const [processedQty, setProcessedQty] = useState(0);
  177. const router = useRouter();
  178. const [poList, setPoList] = useState<PoResult[]>([]);
  179. const [selectedPoId, setSelectedPoId] = useState(po.id);
  180. const currentPoId = searchParams.get('id');
  181. const selectedIdsParam = searchParams.get('selectedIds');
  182. const fetchPoList = useCallback(async () => {
  183. try {
  184. if (selectedIdsParam) {
  185. const selectedIds = selectedIdsParam.split(',').map(id => parseInt(id));
  186. const promises = selectedIds.map(id => fetchPoInClient(id));
  187. const results = await Promise.all(promises);
  188. setPoList(results.filter(Boolean));
  189. } else {
  190. const result = await fetchPoListClient({ limit: 20, offset: 0 });
  191. if (result && result.records) {
  192. setPoList(result.records);
  193. }
  194. }
  195. } catch (error) {
  196. console.error("Failed to fetch PO list:", error);
  197. }
  198. }, [selectedIdsParam]);
  199. const handlePoSelect = useCallback(
  200. (selectedPo: PoResult) => {
  201. setSelectedPoId(selectedPo.id);
  202. const newSelectedIds = selectedIdsParam || selectedPo.id.toString();
  203. router.push(`/po/edit?id=${selectedPo.id}&start=true&selectedIds=${newSelectedIds}`, { scroll: false });
  204. },
  205. [router, selectedIdsParam]
  206. );
  207. const fetchPoDetail = useCallback(async (poId: string) => {
  208. try {
  209. const result = await fetchPoInClient(parseInt(poId));
  210. if (result) {
  211. setPurchaseOrder(result);
  212. setRows(result.pol || []);
  213. if (result.pol && result.pol.length > 0) {
  214. setRow(result.pol[0]);
  215. setStockInLine(result.pol[0].stockInLine);
  216. setProcessedQty(result.pol[0].processed);
  217. }
  218. }
  219. } catch (error) {
  220. console.error("Failed to fetch PO detail:", error);
  221. }
  222. }, []);
  223. useEffect(() => {
  224. if (currentPoId && currentPoId !== selectedPoId.toString()) {
  225. setSelectedPoId(parseInt(currentPoId));
  226. fetchPoDetail(currentPoId);
  227. }
  228. }, [currentPoId, selectedPoId, fetchPoDetail]);
  229. useEffect(() => {
  230. fetchPoList();
  231. }, [fetchPoList]);
  232. useEffect(() => {
  233. if (currentPoId) {
  234. setSelectedPoId(parseInt(currentPoId));
  235. }
  236. }, [currentPoId]);
  237. const removeParam = (paramToRemove: string) => {
  238. const newParams = new URLSearchParams(searchParams.toString());
  239. newParams.delete(paramToRemove);
  240. window.history.replaceState({}, '', `${window.location.pathname}?${newParams}`);
  241. };
  242. const handleCompletePo = useCallback(async () => {
  243. const checkRes = await checkPolAndCompletePo(purchaseOrder.id);
  244. console.log(checkRes);
  245. const newPo = await fetchPoInClient(purchaseOrder.id);
  246. setPurchaseOrder(newPo);
  247. }, [purchaseOrder.id]);
  248. const handleStartPo = useCallback(async () => {
  249. const startRes = await startPo(purchaseOrder.id);
  250. console.log(startRes);
  251. const newPo = await fetchPoInClient(purchaseOrder.id);
  252. setPurchaseOrder(newPo);
  253. }, [purchaseOrder.id]);
  254. useEffect(() => {
  255. setRows(purchaseOrder.pol || []);
  256. }, [purchaseOrder]);
  257. // useEffect(() => {
  258. // setStockInLine([])
  259. // }, []);
  260. function Row(props: { row: PurchaseOrderLine }) {
  261. const { row } = props;
  262. // const [firstReceiveQty, setFirstReceiveQty] = useState<number>()
  263. const [secondReceiveQty, setSecondReceiveQty] = useState<number>()
  264. // const [open, setOpen] = useState(false);
  265. const [processedQty, setProcessedQty] = useState(row.processed);
  266. const [currStatus, setCurrStatus] = useState(row.status);
  267. // const [stockInLine, setStockInLine] = useState(row.stockInLine);
  268. const totalWeight = useMemo(
  269. () => calculateWeight(row.qty, row.uom),
  270. [row.qty, row.uom],
  271. );
  272. const weightUnit = useMemo(
  273. () => returnWeightUnit(row.uom),
  274. [row.uom],
  275. );
  276. useEffect(() => {
  277. const polId = searchParams.get("polId") != null ? parseInt(searchParams.get("polId")!) : null
  278. if (polId) {
  279. setStockInLine(rows.find((r) => r.id == polId)!.stockInLine)
  280. }
  281. }, []);
  282. useEffect(() => {
  283. if (processedQty === row.qty) {
  284. setCurrStatus("completed".toUpperCase());
  285. } else if (processedQty > 0) {
  286. setCurrStatus("receiving".toUpperCase());
  287. } else {
  288. setCurrStatus("pending".toUpperCase());
  289. }
  290. }, [processedQty, row.qty]);
  291. const changeStockInLines = useCallback(
  292. (id: number) => {
  293. console.log(id)
  294. //rows = purchaseOrderLine
  295. console.log(rows)
  296. const target = rows.find((r) => r.id === id)
  297. const stockInLine = target!.stockInLine
  298. console.log(stockInLine)
  299. setStockInLine(stockInLine)
  300. setRow(target!)
  301. // console.log(pathname)
  302. // router.replace(`/po/edit?id=${item.poId}&polId=${item.polId}&stockInLineId=${item.stockInLineId}`);
  303. },
  304. [rows]
  305. );
  306. const handleStart = useCallback(
  307. () => {
  308. setTimeout(async () => {
  309. // post stock in line
  310. const oldId = row.id;
  311. const postData = {
  312. itemId: row.itemId,
  313. itemNo: row.itemNo,
  314. itemName: row.itemName,
  315. purchaseOrderId: row.purchaseOrderId,
  316. purchaseOrderLineId: row.id,
  317. acceptedQty: secondReceiveQty || 0,
  318. // acceptedQty: row.acceptedQty,
  319. };
  320. if (secondReceiveQty === 0) return
  321. const res = await createStockInLine(postData);
  322. console.log(res);
  323. }, 200);
  324. },
  325. [],
  326. );
  327. const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  328. const raw = e.target.value;
  329. // Allow empty input
  330. if (raw.trim() === '') {
  331. setSecondReceiveQty(undefined);
  332. return;
  333. }
  334. // Keep digits only
  335. const cleaned = raw.replace(/[^\d]/g, '');
  336. if (cleaned === '') {
  337. // If the user typed only non-digits, keep previous value
  338. return;
  339. }
  340. // Parse and clamp to non-negative integer
  341. const next = Math.max(0, Math.floor(Number(cleaned)));
  342. setSecondReceiveQty(next);
  343. };
  344. return (
  345. <>
  346. <TableRow
  347. sx={{ "& > *": { borderBottom: "unset" },
  348. color: "black"
  349. }}
  350. onClick={() => changeStockInLines(row.id)}
  351. >
  352. {/* <TableCell>
  353. <IconButton
  354. disabled={purchaseOrder.status.toLowerCase() === "pending"}
  355. aria-label="expand row"
  356. size="small"
  357. onClick={() => setOpen(!open)}
  358. >
  359. {open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
  360. </IconButton>
  361. </TableCell> */}
  362. <TableCell align="left">{row.itemNo}</TableCell>
  363. <TableCell align="left">{row.itemName}</TableCell>
  364. <TableCell align="right">{integerFormatter.format(row.qty)}</TableCell>
  365. <TableCell align="right">{integerFormatter.format(processedQty)}</TableCell>
  366. <TableCell align="left">{row.uom?.code}</TableCell>
  367. {/* <TableCell align="right">
  368. {decimalFormatter.format(totalWeight)} {weightUnit}
  369. </TableCell> */}
  370. {/* <TableCell align="left">{weightUnit}</TableCell> */}
  371. <TableCell align="right">{decimalFormatter.format(row.price)}</TableCell>
  372. {/* <TableCell align="left">{row.expiryDate}</TableCell> */}
  373. <TableCell align="left">{t(`${currStatus.toLowerCase()}`)}</TableCell>
  374. <TableCell align="right">{integerFormatter.format(row.receivedQty)}</TableCell>
  375. <TableCell align="center">
  376. <TextField
  377. label="輸入來貨數量"
  378. type="text" // Use type="text" to allow validation in the change handler
  379. variant="outlined"
  380. value={secondReceiveQty}
  381. onChange={handleChange}
  382. InputProps={{
  383. inputProps: {
  384. min: 0, // Optional: set a minimum value
  385. step: 1 // Optional: set the step for the number input
  386. }
  387. }}
  388. />
  389. </TableCell>
  390. <TableCell align="center">
  391. <Button
  392. variant="contained"
  393. onClick={() =>
  394. handleStart()
  395. }
  396. >
  397. 提交
  398. </Button>
  399. </TableCell>
  400. </TableRow>
  401. {/* <TableRow> */}
  402. {/* <TableCell /> */}
  403. {/* <TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={12}> */}
  404. {/* <Collapse in={true} timeout="auto" unmountOnExit> */}
  405. {/* <Collapse in={open} timeout="auto" unmountOnExit> */}
  406. {/* <Table>
  407. <TableBody>
  408. <TableRow>
  409. <TableCell align="right">
  410. <Box>
  411. <PoInputGrid
  412. qc={qc}
  413. setRows={setRows}
  414. stockInLine={stockInLine}
  415. setStockInLine={setStockInLine}
  416. setProcessedQty={setProcessedQty}
  417. itemDetail={row}
  418. warehouse={warehouse}
  419. />
  420. </Box>
  421. </TableCell>
  422. </TableRow>
  423. </TableBody>
  424. </Table> */}
  425. {/* </Collapse> */}
  426. {/* </TableCell> */}
  427. {/* </TableRow> */}
  428. </>
  429. );
  430. }
  431. const [tabIndex, setTabIndex] = useState(0);
  432. const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>(
  433. (_e, newValue) => {
  434. setTabIndex(newValue);
  435. },
  436. [],
  437. );
  438. const [isOpenScanner, setOpenScanner] = useState(false);
  439. // const testing = useCallback(() => {
  440. // // setOpenScanner(true);
  441. // const newParams = new URLSearchParams(searchParams.toString());
  442. // console.log(pathname)
  443. // }, [pathname, router, searchParams]);
  444. const onOpenScanner = useCallback(() => {
  445. setOpenScanner(true);
  446. }, []);
  447. const onCloseScanner = useCallback(() => {
  448. setOpenScanner(false);
  449. }, []);
  450. const [itemInfo, setItemInfo] = useState<
  451. StockInLine & { warehouseId?: number }
  452. >();
  453. const [putAwayOpen, setPutAwayOpen] = useState(false);
  454. // const [scannedInfo, setScannedInfo] = useState<QrCodeInfo>({} as QrCodeInfo);
  455. const closePutAwayModal = useCallback(() => {
  456. setPutAwayOpen(false);
  457. setItemInfo(undefined);
  458. }, []);
  459. const openPutAwayModal = useCallback(() => {
  460. setPutAwayOpen(true);
  461. }, []);
  462. const buttonData = useMemo(() => {
  463. switch (purchaseOrder.status.toLowerCase()) {
  464. case "pending":
  465. return {
  466. buttonName: "start",
  467. title: t("Do you want to start?"),
  468. confirmButtonText: t("Start"),
  469. successTitle: t("Start Success"),
  470. errorTitle: t("Start Fail"),
  471. buttonText: t("Start PO"),
  472. buttonIcon: <PlayArrow />,
  473. buttonColor: "success",
  474. disabled: false,
  475. onClick: handleStartPo,
  476. };
  477. case "receiving":
  478. return {
  479. buttonName: "complete",
  480. title: t("Do you want to complete?"),
  481. confirmButtonText: t("Complete"),
  482. successTitle: t("Complete Success"),
  483. errorTitle: t("Complete Fail"),
  484. buttonText: t("Complete PO"),
  485. buttonIcon: <DoneIcon />,
  486. buttonColor: "info",
  487. disabled: false,
  488. onClick: handleCompletePo,
  489. };
  490. default:
  491. return {
  492. buttonName: "complete",
  493. title: t("Do you want to complete?"),
  494. confirmButtonText: t("Complete"),
  495. successTitle: t("Complete Success"),
  496. errorTitle: t("Complete Fail"),
  497. buttonText: t("Complete PO"),
  498. buttonIcon: <DoneIcon />,
  499. buttonColor: "info",
  500. disabled: true,
  501. };
  502. // break;
  503. }
  504. }, [purchaseOrder.status, t, handleStartPo, handleCompletePo]);
  505. const FIRST_IN_FIELD = "firstInQty"
  506. const SECOND_IN_FIELD = "secondInQty"
  507. const renderFieldCondition = useCallback((field: "firstInQty" | "secondInQty"): boolean => {
  508. switch (field) {
  509. case FIRST_IN_FIELD:
  510. return true;
  511. case SECOND_IN_FIELD:
  512. return true;
  513. default:
  514. return false; // Default case
  515. }
  516. }, []);
  517. useEffect(() => {
  518. const params = searchParams.get("polId")
  519. if (params) {
  520. const polId = parseInt(params)
  521. }
  522. }, [searchParams])
  523. return (
  524. <>
  525. <Stack spacing={2}>
  526. {/* Area1: title */}
  527. <Grid container xs={12} justifyContent="start">
  528. <Grid item>
  529. <Typography mb={2} variant="h4">
  530. {purchaseOrder.code} -{" "}
  531. {t(`${purchaseOrder.status.toLowerCase()}`)}
  532. </Typography>
  533. </Grid>
  534. </Grid>
  535. {/* area2: dn info */}
  536. <Grid container spacing={3} sx={{ maxWidth: 'fit-content' }}>
  537. {/* left side select po */}
  538. <Grid item xs={4}>
  539. <PoSearchList
  540. poList={poList}
  541. selectedPoId={selectedPoId}
  542. onSelect={handlePoSelect}
  543. />
  544. </Grid>
  545. {/* right side po info */}
  546. <Grid item xs={8}>
  547. <PoInfoCard po={purchaseOrder} />
  548. {true ? (
  549. <Stack spacing={2}>
  550. <TextField
  551. label={t("dnNo")}
  552. type="text"
  553. variant="outlined"
  554. fullWidth
  555. // InputProps={{
  556. // inputProps: {
  557. // min: 0,
  558. // step: 1
  559. // }
  560. // }}
  561. />
  562. <TextField
  563. label={t("dnDate")}
  564. type="text"
  565. variant="outlined"
  566. defaultValue={"11/08/2025"}
  567. fullWidth
  568. InputProps={{
  569. inputProps: {
  570. min: 0,
  571. step: 1
  572. }
  573. }}
  574. />
  575. <Button variant="contained" onClick={onOpenScanner} fullWidth>
  576. 提交
  577. </Button>
  578. </Stack>
  579. ) : undefined}
  580. </Grid>
  581. </Grid>
  582. {/* Area4: Main Table */}
  583. <Grid container xs={12} justifyContent="start">
  584. <Grid item xs={12}>
  585. <TableContainer component={Paper} sx={{ width: 'fit-content', overflow: 'auto' }}>
  586. <Table aria-label="collapsible table" stickyHeader>
  587. <TableHead>
  588. <TableRow>
  589. <TableCell sx={{ width: '125px' }}>{t("itemNo")}</TableCell>
  590. <TableCell align="left" sx={{ width: '125px' }}>{t("itemName")}</TableCell>
  591. <TableCell align="right">{t("qty")}</TableCell>
  592. <TableCell align="right">{t("processed")}</TableCell>
  593. <TableCell align="left">{t("uom")}</TableCell>
  594. {/* <TableCell align="right">{t("total weight")}</TableCell> */}
  595. <TableCell align="right">{`${t("price")} (HKD)`}</TableCell>
  596. <TableCell align="left" sx={{ width: '75px' }}>{t("status")}</TableCell>
  597. {renderFieldCondition(FIRST_IN_FIELD) ? <TableCell align="right">{t("receivedQty")}</TableCell> : undefined}
  598. {renderFieldCondition(SECOND_IN_FIELD) ? <TableCell align="center" sx={{ width: '150px' }}>{t("dnQty")}(以訂單單位計算)</TableCell> : undefined}
  599. <TableCell align="center" sx={{ width: '100px' }}></TableCell>
  600. </TableRow>
  601. </TableHead>
  602. <TableBody>
  603. {rows.map((row) => (
  604. <Row key={row.id} row={row} />
  605. ))}
  606. </TableBody>
  607. </Table>
  608. </TableContainer>
  609. </Grid>
  610. </Grid>
  611. {/* area5: selected item info */}
  612. <Grid container xs={12} justifyContent="start">
  613. <Grid item xs={12}>
  614. <Typography variant="h6">{row.itemNo && row.itemName ? `已選擇: ${row.itemNo}-${row.itemName}` : `未選擇貨品`}</Typography>
  615. </Grid>
  616. <Grid item xs={12}>
  617. <TableContainer component={Paper} sx={{ width: 'fit-content', overflow: 'auto' }}>
  618. <Table>
  619. <TableBody>
  620. <TableRow>
  621. <TableCell align="right">
  622. <Box>
  623. <PoInputGrid
  624. qc={qc}
  625. setRows={setRows}
  626. stockInLine={stockInLine}
  627. setStockInLine={setStockInLine}
  628. setProcessedQty={setProcessedQty}
  629. itemDetail={row}
  630. warehouse={warehouse}
  631. />
  632. </Box>
  633. </TableCell>
  634. </TableRow>
  635. </TableBody>
  636. </Table>
  637. </TableContainer>
  638. </Grid>
  639. </Grid>
  640. {/* tab 2 */}
  641. <Grid sx={{ display: tabIndex === 1 ? "block" : "none" }}>
  642. {/* <StyledDataGrid
  643. /> */}
  644. </Grid>
  645. </Stack>
  646. {itemInfo !== undefined && (
  647. <>
  648. <PoQcStockInModal
  649. type={"putaway"}
  650. open={putAwayOpen}
  651. warehouse={warehouse}
  652. setItemDetail={setItemInfo}
  653. onClose={closePutAwayModal}
  654. itemDetail={itemInfo}
  655. />
  656. </>
  657. )}
  658. </>
  659. );
  660. };
  661. export default PoDetail;