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.
 
 
 

395 rivejä
12 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. } from "@mui/material";
  29. import { useTranslation } from "react-i18next";
  30. // import InputDataGrid, { TableRow } from "../InputDataGrid/InputDataGrid";
  31. import {
  32. GridColDef,
  33. GridRowId,
  34. GridRowModel,
  35. useGridApiRef,
  36. } from "@mui/x-data-grid";
  37. import {
  38. checkPolAndCompletePo,
  39. fetchPoInClient,
  40. fetchStockInLineInfo,
  41. PurchaseQcResult,
  42. startPo,
  43. testFetch,
  44. } from "@/app/api/po/actions";
  45. import {
  46. use,
  47. useCallback,
  48. useContext,
  49. useEffect,
  50. useMemo,
  51. useState,
  52. } from "react";
  53. import { FormProvider, useForm } from "react-hook-form";
  54. import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
  55. import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp";
  56. import InputDataGrid, {
  57. TableRow as InputTableRow,
  58. } from "../InputDataGrid/InputDataGrid";
  59. import PoInputGrid from "./PoInputGrid";
  60. import { QcItemWithChecks } from "@/app/api/qc";
  61. import { useSearchParams } from "next/navigation";
  62. import { WarehouseResult } from "@/app/api/warehouse";
  63. import { calculateWeight, returnWeightUnit } from "@/app/utils/formatUtil";
  64. import QrCodeScanner from "../QrCodeScanner";
  65. import { CameraDevice, Html5Qrcode } from "html5-qrcode";
  66. import { CameraContext } from "../Cameras/CameraProvider";
  67. import StyledDataGrid from "../StyledDataGrid";
  68. import { QrCodeInfo } from "@/app/api/qrcode";
  69. import { fetchQcResult } from "@/app/api/qc/actions";
  70. import PoQcStockInModal from "./PoQcStockInModal";
  71. import ReactQrCodeScannerModal, {
  72. ScannerConfig,
  73. } from "../ReactQrCodeScanner/ReactQrCodeScanner";
  74. import QrModal from "./QrModal";
  75. import { PlayArrow } from "@mui/icons-material";
  76. import DoneIcon from "@mui/icons-material/Done";
  77. type Props = {
  78. po: PoResult;
  79. qc: QcItemWithChecks[];
  80. warehouse: WarehouseResult[];
  81. };
  82. type EntryError =
  83. | {
  84. [field in keyof StockInLine]?: string;
  85. }
  86. | undefined;
  87. // type PolRow = TableRow<Partial<StockInLine>, EntryError>;
  88. const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => {
  89. const cameras = useContext(CameraContext);
  90. console.log(cameras);
  91. const { t } = useTranslation("purchaseOrder");
  92. const apiRef = useGridApiRef();
  93. const [purchaseOrder, setPurchaseOrder] = useState({ ...po });
  94. const [rows, setRows] = useState<PurchaseOrderLine[]>(
  95. purchaseOrder.pol || []
  96. );
  97. const params = useSearchParams();
  98. // const [currPoStatus, setCurrPoStatus] = useState(purchaseOrder.status);
  99. const handleCompletePo = useCallback(async () => {
  100. const checkRes = await checkPolAndCompletePo(purchaseOrder.id);
  101. console.log(checkRes);
  102. const newPo = await fetchPoInClient(purchaseOrder.id);
  103. setPurchaseOrder(newPo);
  104. }, [checkPolAndCompletePo, fetchPoInClient]);
  105. const handleStartPo = useCallback(async () => {
  106. const startRes = await startPo(purchaseOrder.id);
  107. console.log(startRes);
  108. const newPo = await fetchPoInClient(purchaseOrder.id);
  109. setPurchaseOrder(newPo);
  110. }, [startPo, fetchPoInClient]);
  111. useEffect(() => {
  112. setRows(purchaseOrder.pol || []);
  113. }, [purchaseOrder]);
  114. function Row(props: { row: PurchaseOrderLine }) {
  115. const { row } = props;
  116. const [open, setOpen] = useState(false);
  117. const [processedQty, setProcessedQty] = useState(row.processed);
  118. const [currStatus, setCurrStatus] = useState(row.status);
  119. const [stockInLine, setStockInLine] = useState(row.stockInLine);
  120. const totalWeight = useMemo(
  121. () => calculateWeight(row.qty, row.uom),
  122. [calculateWeight]
  123. );
  124. const weightUnit = useMemo(
  125. () => returnWeightUnit(row.uom),
  126. [returnWeightUnit]
  127. );
  128. useEffect(() => {
  129. if (processedQty === row.qty) {
  130. setCurrStatus("completed".toUpperCase());
  131. } else if (processedQty > 0) {
  132. setCurrStatus("receiving".toUpperCase());
  133. } else {
  134. setCurrStatus("pending".toUpperCase());
  135. }
  136. }, [processedQty]);
  137. return (
  138. <>
  139. <TableRow sx={{ "& > *": { borderBottom: "unset" }, color: "black" }}>
  140. <TableCell>
  141. <IconButton
  142. disabled={purchaseOrder.status.toLowerCase() === "pending"}
  143. aria-label="expand row"
  144. size="small"
  145. onClick={() => setOpen(!open)}
  146. >
  147. {open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
  148. </IconButton>
  149. </TableCell>
  150. <TableCell align="left">{row.itemNo}</TableCell>
  151. <TableCell align="left">{row.itemName}</TableCell>
  152. <TableCell align="left">{row.qty}</TableCell>
  153. <TableCell align="left">{processedQty}</TableCell>
  154. <TableCell align="left">{row.uom?.code}</TableCell>
  155. <TableCell align="left">
  156. {totalWeight} {weightUnit}
  157. </TableCell>
  158. {/* <TableCell align="left">{weightUnit}</TableCell> */}
  159. <TableCell align="left">{row.price}</TableCell>
  160. {/* <TableCell align="left">{row.expiryDate}</TableCell> */}
  161. <TableCell align="left">{t(`${currStatus.toLowerCase()}`)}</TableCell>
  162. </TableRow>
  163. <TableRow>
  164. {/* <TableCell /> */}
  165. <TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={12}>
  166. <Collapse in={open} timeout="auto" unmountOnExit>
  167. <Table>
  168. <TableBody>
  169. <TableRow>
  170. <TableCell align="right">
  171. <Box>
  172. <PoInputGrid
  173. qc={qc}
  174. setRows={setRows}
  175. stockInLine={stockInLine}
  176. setStockInLine={setStockInLine}
  177. setProcessedQty={setProcessedQty}
  178. itemDetail={row}
  179. warehouse={warehouse}
  180. />
  181. </Box>
  182. </TableCell>
  183. </TableRow>
  184. </TableBody>
  185. </Table>
  186. </Collapse>
  187. </TableCell>
  188. </TableRow>
  189. </>
  190. );
  191. }
  192. const [tabIndex, setTabIndex] = useState(0);
  193. const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>(
  194. (_e, newValue) => {
  195. setTabIndex(newValue);
  196. },
  197. []
  198. );
  199. const [isOpenScanner, setOpenScanner] = useState(false);
  200. const onOpenScanner = useCallback(() => {
  201. setOpenScanner(true);
  202. }, []);
  203. const onCloseScanner = useCallback(() => {
  204. setOpenScanner(false);
  205. }, []);
  206. const [itemInfo, setItemInfo] = useState<
  207. StockInLine & { warehouseId?: number }
  208. >();
  209. const [putAwayOpen, setPutAwayOpen] = useState(false);
  210. // const [scannedInfo, setScannedInfo] = useState<QrCodeInfo>({} as QrCodeInfo);
  211. const closePutAwayModal = useCallback(() => {
  212. setPutAwayOpen(false);
  213. setItemInfo(undefined);
  214. }, []);
  215. const openPutAwayModal = useCallback(() => {
  216. setPutAwayOpen(true);
  217. }, []);
  218. const buttonData = useMemo(() => {
  219. switch (purchaseOrder.status.toLowerCase()) {
  220. case "pending":
  221. return {
  222. buttonName: "start",
  223. title: t("Do you want to start?"),
  224. confirmButtonText: t("Start"),
  225. successTitle: t("Start Success"),
  226. errorTitle: t("Start Fail"),
  227. buttonText: t("Start PO"),
  228. buttonIcon: <PlayArrow />,
  229. buttonColor: "success",
  230. disabled: false,
  231. onClick: handleStartPo,
  232. };
  233. case "receiving":
  234. return {
  235. buttonName: "complete",
  236. title: t("Do you want to complete?"),
  237. confirmButtonText: t("Complete"),
  238. successTitle: t("Complete Success"),
  239. errorTitle: t("Complete Fail"),
  240. buttonText: t("Complete PO"),
  241. buttonIcon: <DoneIcon />,
  242. buttonColor: "info",
  243. disabled: false,
  244. onClick: handleCompletePo,
  245. };
  246. default:
  247. return {
  248. buttonName: "complete",
  249. title: t("Do you want to complete?"),
  250. confirmButtonText: t("Complete"),
  251. successTitle: t("Complete Success"),
  252. errorTitle: t("Complete Fail"),
  253. buttonText: t("Complete PO"),
  254. buttonIcon: <DoneIcon />,
  255. buttonColor: "info",
  256. disabled: true,
  257. };
  258. // break;
  259. }
  260. }, [purchaseOrder, handleStartPo, handleCompletePo]);
  261. return (
  262. <>
  263. <Stack
  264. spacing={2}
  265. // component="form"
  266. // onSubmit={formProps.handleSubmit(onSubmit, onSubmitError)}
  267. >
  268. <Grid container xs={12} justifyContent="start">
  269. <Grid item>
  270. <Typography mb={2} variant="h4">
  271. {/* {purchaseOrder.code} - {currPoStatus} */}
  272. {purchaseOrder.code} - {purchaseOrder.status}
  273. </Typography>
  274. </Grid>
  275. </Grid>
  276. <Grid container xs={12} justifyContent="start">
  277. <Grid item>
  278. <Button
  279. onClick={buttonData.onClick}
  280. disabled={buttonData.disabled}
  281. color={buttonData.buttonColor as ButtonProps["color"]}
  282. startIcon={buttonData.buttonIcon}
  283. >
  284. {t(buttonData.buttonText)}
  285. </Button>
  286. </Grid>
  287. {/* {purchaseOrder.status.toLowerCase() === "pending" && (
  288. <Grid item>
  289. <Button onClick={handleStartPo}>Start</Button>
  290. </Grid>
  291. )}
  292. {purchaseOrder.status.toLowerCase() === "receiving" && (
  293. <Grid item>
  294. <Button onClick={handleCompletePo}>Complete</Button>
  295. </Grid>
  296. )} */}
  297. </Grid>
  298. {/* <Grid container xs={12} justifyContent="space-between">
  299. <Button onClick={handleCompletePo}>Complete</Button>
  300. </Grid> */}
  301. <Grid container xs={12} justifyContent="space-between">
  302. <Grid item xs={8}>
  303. <Tabs
  304. value={tabIndex}
  305. onChange={handleTabChange}
  306. variant="scrollable"
  307. >
  308. <Tab label={t("General")} iconPosition="end" />
  309. {/* <Tab label={t("Bind Storage")} iconPosition="end" /> */}
  310. </Tabs>
  311. </Grid>
  312. {/* <Grid item xs={4}> */}
  313. {/* scanner */}
  314. {/* </Grid> */}
  315. <Grid
  316. item
  317. xs={4}
  318. display="flex"
  319. justifyContent="end"
  320. alignItems="end"
  321. >
  322. <QrModal
  323. open={isOpenScanner}
  324. onClose={onCloseScanner}
  325. warehouse={warehouse}
  326. />
  327. <Button onClick={onOpenScanner}>bind</Button>
  328. </Grid>
  329. </Grid>
  330. {/* tab 1 */}
  331. <Grid sx={{ display: tabIndex === 0 ? "block" : "none" }}>
  332. <TableContainer component={Paper}>
  333. <Table aria-label="collapsible table">
  334. <TableHead>
  335. <TableRow>
  336. <TableCell /> {/* for the collapse button */}
  337. <TableCell>{t("itemNo")}</TableCell>
  338. <TableCell align="left">{t("itemName")}</TableCell>
  339. <TableCell align="left">{t("qty")}</TableCell>
  340. <TableCell align="left">{t("processed")}</TableCell>
  341. <TableCell align="left">{t("uom")}</TableCell>
  342. <TableCell align="left">{t("total weight")}</TableCell>
  343. {/* <TableCell align="left">{t("weight unit")}</TableCell> */}
  344. <TableCell align="left">{t("price")}</TableCell>
  345. {/* <TableCell align="left">{t("expiryDate")}</TableCell> */}
  346. <TableCell align="left">{t("status")}</TableCell>
  347. {/* <TableCell align="left">{"add icon button"}</TableCell> */}
  348. </TableRow>
  349. </TableHead>
  350. <TableBody>
  351. {rows.map((row) => (
  352. <Row key={row.id} row={row} />
  353. ))}
  354. </TableBody>
  355. </Table>
  356. </TableContainer>
  357. </Grid>
  358. {/* tab 2 */}
  359. <Grid sx={{ display: tabIndex === 1 ? "block" : "none" }}>
  360. {/* <StyledDataGrid
  361. /> */}
  362. </Grid>
  363. </Stack>
  364. {itemInfo !== undefined && (
  365. <>
  366. <PoQcStockInModal
  367. type={"putaway"}
  368. open={putAwayOpen}
  369. warehouse={warehouse}
  370. setItemDetail={setItemInfo}
  371. onClose={closePutAwayModal}
  372. itemDetail={itemInfo}
  373. />
  374. </>
  375. )}
  376. </>
  377. );
  378. };
  379. export default PoDetail;