FPSMS-frontend
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

307 regels
9.4 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. Collapse,
  12. Grid,
  13. IconButton,
  14. Paper,
  15. Stack,
  16. Tab,
  17. Table,
  18. TableBody,
  19. TableCell,
  20. TableContainer,
  21. TableHead,
  22. TableRow,
  23. Tabs,
  24. TabsProps,
  25. TextField,
  26. Typography,
  27. } from "@mui/material";
  28. import { useTranslation } from "react-i18next";
  29. // import InputDataGrid, { TableRow } from "../InputDataGrid/InputDataGrid";
  30. import {
  31. GridColDef,
  32. GridRowId,
  33. GridRowModel,
  34. useGridApiRef,
  35. } from "@mui/x-data-grid";
  36. import {
  37. checkPolAndCompletePo,
  38. fetchStockInLineInfo,
  39. PurchaseQcResult,
  40. testFetch,
  41. } from "@/app/api/po/actions";
  42. import {
  43. use,
  44. useCallback,
  45. useContext,
  46. useEffect,
  47. useMemo,
  48. useState,
  49. } from "react";
  50. import { FormProvider, useForm } from "react-hook-form";
  51. import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
  52. import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp";
  53. import InputDataGrid, {
  54. TableRow as InputTableRow,
  55. } from "../InputDataGrid/InputDataGrid";
  56. import PoInputGrid from "./PoInputGrid";
  57. import { QcItemWithChecks } from "@/app/api/qc";
  58. import { useSearchParams } from "next/navigation";
  59. import { WarehouseResult } from "@/app/api/warehouse";
  60. import { calculateWeight, returnWeightUnit } from "@/app/utils/formatUtil";
  61. import QrCodeScanner from "../QrCodeScanner";
  62. import { CameraDevice, Html5Qrcode } from "html5-qrcode";
  63. import { CameraContext } from "../Cameras/CameraProvider";
  64. import StyledDataGrid from "../StyledDataGrid";
  65. import { QrCodeInfo } from "@/app/api/qrcode";
  66. import { fetchQcResult } from "@/app/api/qc/actions";
  67. import PoQcStockInModal from "./PoQcStockInModal";
  68. import ReactQrCodeScannerModal, {
  69. ScannerConfig,
  70. } from "../ReactQrCodeScanner/ReactQrCodeScanner";
  71. import QrModal from "./QrModal";
  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 PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => {
  84. const cameras = useContext(CameraContext);
  85. console.log(cameras);
  86. const { t } = useTranslation();
  87. const apiRef = useGridApiRef();
  88. const [rows, setRows] = useState<PurchaseOrderLine[]>(po.pol || []);
  89. const params = useSearchParams();
  90. function Row(props: { row: PurchaseOrderLine }) {
  91. const { row } = props;
  92. const [open, setOpen] = useState(false);
  93. const [processedQty, setProcessedQty] = useState(row.processed);
  94. const [currStatus, setCurrStatus] = useState(row.status);
  95. useEffect(() => {
  96. if (processedQty === row.qty) {
  97. setCurrStatus("completed".toUpperCase());
  98. } else if (processedQty > 0) {
  99. setCurrStatus("receiving".toUpperCase());
  100. } else {
  101. setCurrStatus("pending".toUpperCase());
  102. }
  103. }, [processedQty]);
  104. const totalWeight = useMemo(
  105. () => calculateWeight(row.qty, row.uom),
  106. [calculateWeight]
  107. );
  108. const weightUnit = useMemo(
  109. () => returnWeightUnit(row.uom),
  110. [returnWeightUnit]
  111. );
  112. return (
  113. <>
  114. <TableRow sx={{ "& > *": { borderBottom: "unset" }, color: "black" }}>
  115. <TableCell>
  116. <IconButton
  117. aria-label="expand row"
  118. size="small"
  119. onClick={() => setOpen(!open)}
  120. >
  121. {open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
  122. </IconButton>
  123. </TableCell>
  124. <TableCell align="left">{row.itemNo}</TableCell>
  125. <TableCell align="left">{row.itemName}</TableCell>
  126. <TableCell align="left">{row.qty}</TableCell>
  127. <TableCell align="left">{processedQty}</TableCell>
  128. <TableCell align="left">{row.uom?.code}</TableCell>
  129. <TableCell align="left">
  130. {totalWeight} {weightUnit}
  131. </TableCell>
  132. {/* <TableCell align="left">{weightUnit}</TableCell> */}
  133. <TableCell align="left">{row.price}</TableCell>
  134. {/* <TableCell align="left">{row.expiryDate}</TableCell> */}
  135. <TableCell align="left">{currStatus}</TableCell>
  136. </TableRow>
  137. <TableRow>
  138. {/* <TableCell /> */}
  139. <TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={12}>
  140. <Collapse in={open} timeout="auto" unmountOnExit>
  141. <Table>
  142. <TableBody>
  143. <TableRow>
  144. <TableCell align="right">
  145. <Box>
  146. <PoInputGrid
  147. qc={qc}
  148. setRows={setRows}
  149. setProcessedQty={setProcessedQty}
  150. itemDetail={row}
  151. stockInLine={row.stockInLine}
  152. warehouse={warehouse}
  153. />
  154. </Box>
  155. </TableCell>
  156. </TableRow>
  157. </TableBody>
  158. </Table>
  159. </Collapse>
  160. </TableCell>
  161. </TableRow>
  162. </>
  163. );
  164. }
  165. const [tabIndex, setTabIndex] = useState(0);
  166. const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>(
  167. (_e, newValue) => {
  168. setTabIndex(newValue);
  169. },
  170. []
  171. );
  172. const [isOpenScanner, setOpenScanner] = useState(false);
  173. const onOpenScanner = useCallback(() => {
  174. setOpenScanner(true);
  175. }, []);
  176. const onCloseScanner = useCallback(() => {
  177. setOpenScanner(false);
  178. }, []);
  179. const [itemInfo, setItemInfo] = useState<
  180. StockInLine & { warehouseId?: number }
  181. >();
  182. const [putAwayOpen, setPutAwayOpen] = useState(false);
  183. // const [scannedInfo, setScannedInfo] = useState<QrCodeInfo>({} as QrCodeInfo);
  184. const closePutAwayModal = useCallback(() => {
  185. setPutAwayOpen(false);
  186. setItemInfo(undefined);
  187. }, []);
  188. const openPutAwayModal = useCallback(() => {
  189. setPutAwayOpen(true);
  190. }, []);
  191. const handleComplete = useCallback(async () => {
  192. const res = await checkPolAndCompletePo(po.id)
  193. if (res.type === "completed") {
  194. // toast.success(res.message)
  195. console.log(res)
  196. return
  197. }
  198. if (res.type === "receiving") {
  199. // toast.error(res.message)
  200. console.log(res)
  201. return
  202. }
  203. }, [checkPolAndCompletePo]);
  204. return (
  205. <>
  206. <Stack
  207. spacing={2}
  208. // component="form"
  209. // onSubmit={formProps.handleSubmit(onSubmit, onSubmitError)}
  210. >
  211. <Grid container xs={12} justifyContent="space-between">
  212. <Grid item>
  213. <Typography mb={2} variant="h4">
  214. {po.code}
  215. </Typography>
  216. </Grid>
  217. </Grid>
  218. {/* <Grid container xs={12} justifyContent="space-between">
  219. <Button onClick={handleComplete}>Complete</Button>
  220. </Grid> */}
  221. <Grid container xs={12} justifyContent="space-between">
  222. <Grid item xs={8}>
  223. <Tabs
  224. value={tabIndex}
  225. onChange={handleTabChange}
  226. variant="scrollable"
  227. >
  228. <Tab label={t("General")} iconPosition="end" />
  229. {/* <Tab label={t("Bind Storage")} iconPosition="end" /> */}
  230. </Tabs>
  231. </Grid>
  232. {/* <Grid item xs={4}> */}
  233. {/* scanner */}
  234. {/* </Grid> */}
  235. <Grid item xs={4} display="flex" justifyContent="end" alignItems="end">
  236. <QrModal
  237. open={isOpenScanner}
  238. onClose={onCloseScanner}
  239. warehouse={warehouse}
  240. />
  241. <Button onClick={onOpenScanner}>bind</Button>
  242. </Grid>
  243. </Grid>
  244. {/* tab 1 */}
  245. <Grid sx={{ display: tabIndex === 0 ? "block" : "none" }}>
  246. <TableContainer component={Paper}>
  247. <Table aria-label="collapsible table">
  248. <TableHead>
  249. <TableRow>
  250. <TableCell /> {/* for the collapse button */}
  251. <TableCell>{t("itemNo")}</TableCell>
  252. <TableCell align="left">{t("itemName")}</TableCell>
  253. <TableCell align="left">{t("qty")}</TableCell>
  254. <TableCell align="left">processed</TableCell>
  255. <TableCell align="left">{t("uom")}</TableCell>
  256. <TableCell align="left">{t("total weight")}</TableCell>
  257. {/* <TableCell align="left">{t("weight unit")}</TableCell> */}
  258. <TableCell align="left">{t("price")}</TableCell>
  259. {/* <TableCell align="left">{t("expiryDate")}</TableCell> */}
  260. <TableCell align="left">{t("status")}</TableCell>
  261. {/* <TableCell align="left">{"add icon button"}</TableCell> */}
  262. </TableRow>
  263. </TableHead>
  264. <TableBody>
  265. {rows.map((row) => (
  266. <Row key={row.id} row={row} />
  267. ))}
  268. </TableBody>
  269. </Table>
  270. </TableContainer>
  271. </Grid>
  272. {/* tab 2 */}
  273. <Grid sx={{ display: tabIndex === 1 ? "block" : "none" }}>
  274. {/* <StyledDataGrid
  275. /> */}
  276. </Grid>
  277. </Stack>
  278. {itemInfo !== undefined && (
  279. <>
  280. <PoQcStockInModal
  281. type={"putaway"}
  282. open={putAwayOpen}
  283. warehouse={warehouse}
  284. setItemDetail={setItemInfo}
  285. onClose={closePutAwayModal}
  286. itemDetail={itemInfo}
  287. />
  288. </>
  289. )}
  290. </>
  291. );
  292. };
  293. export default PoDetail;