FPSMS-frontend
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 

415 строки
11 KiB

  1. "use client";
  2. import { PurchaseQcResult, PutawayInput } from "@/app/api/po/actions";
  3. import {
  4. Autocomplete,
  5. Box,
  6. Button,
  7. Card,
  8. CardContent,
  9. FormControl,
  10. Grid,
  11. Modal,
  12. ModalProps,
  13. Stack,
  14. TextField,
  15. Tooltip,
  16. Typography,
  17. } from "@mui/material";
  18. import { Controller, useFormContext } from "react-hook-form";
  19. import { useTranslation } from "react-i18next";
  20. import StyledDataGrid from "../StyledDataGrid";
  21. import { useCallback, useEffect, useMemo, useState } from "react";
  22. import {
  23. GridColDef,
  24. GridRowIdGetter,
  25. GridRowModel,
  26. useGridApiContext,
  27. GridRenderCellParams,
  28. GridRenderEditCellParams,
  29. useGridApiRef,
  30. } from "@mui/x-data-grid";
  31. import InputDataGrid from "../InputDataGrid";
  32. import { TableRow } from "../InputDataGrid/InputDataGrid";
  33. import TwoLineCell from "./TwoLineCell";
  34. import QcSelect from "./QcSelect";
  35. import { QcItemWithChecks } from "@/app/api/qc";
  36. import { GridEditInputCell } from "@mui/x-data-grid";
  37. import { StockInLine } from "@/app/api/po";
  38. import { WarehouseResult } from "@/app/api/warehouse";
  39. import { stockInLineStatusMap } from "@/app/utils/formatUtil";
  40. import { QRCodeSVG } from "qrcode.react";
  41. import { QrCode } from "../QrCode";
  42. import ReactQrCodeScanner, {
  43. ScannerConfig,
  44. } from "../ReactQrCodeScanner/ReactQrCodeScanner";
  45. import { QrCodeInfo } from "@/app/api/qrcode";
  46. interface Props {
  47. itemDetail: StockInLine;
  48. warehouse: WarehouseResult[];
  49. // qc: QcItemWithChecks[];
  50. }
  51. type EntryError =
  52. | {
  53. [field in keyof PurchaseQcResult]?: string;
  54. }
  55. | undefined;
  56. // type PoQcRow = TableRow<Partial<PurchaseQcResult>, EntryError>;
  57. const style = {
  58. position: "absolute",
  59. top: "50%",
  60. left: "50%",
  61. transform: "translate(-50%, -50%)",
  62. bgcolor: "background.paper",
  63. pt: 5,
  64. px: 5,
  65. pb: 10,
  66. width: "auto",
  67. };
  68. const PutawayForm: React.FC<Props> = ({ itemDetail, warehouse }) => {
  69. const { t } = useTranslation();
  70. const apiRef = useGridApiRef();
  71. const {
  72. register,
  73. formState: { errors, defaultValues, touchedFields },
  74. watch,
  75. control,
  76. setValue,
  77. getValues,
  78. reset,
  79. resetField,
  80. setError,
  81. clearErrors,
  82. } = useFormContext<PutawayInput>();
  83. console.log(itemDetail);
  84. // const [recordQty, setRecordQty] = useState(0);
  85. const [warehouseId, setWarehouseId] = useState(itemDetail.defaultWarehouseId);
  86. const filteredWarehouse = useMemo(() => {
  87. // do filtering here if any
  88. return warehouse;
  89. }, []);
  90. const defaultOption = {
  91. value: 0, // think think sin
  92. label: t("Select warehouse"),
  93. group: "default",
  94. }
  95. const options = useMemo(() => {
  96. return [
  97. // {
  98. // value: 0, // think think sin
  99. // label: t("Select warehouse"),
  100. // group: "default",
  101. // },
  102. ...filteredWarehouse.map((w) => ({
  103. value: w.id,
  104. label: `${w.code} - ${w.name}`,
  105. group: "existing",
  106. })),
  107. ];
  108. }, [filteredWarehouse]);
  109. const currentValue =
  110. warehouseId > 0
  111. ? options.find((o) => o.value === warehouseId)
  112. : options.find((o) => o.value === getValues("warehouseId")) || defaultOption;
  113. const onChange = useCallback(
  114. (
  115. event: React.SyntheticEvent,
  116. newValue: { value: number; group: string } | { value: number }[]
  117. ) => {
  118. const singleNewVal = newValue as {
  119. value: number;
  120. group: string;
  121. };
  122. console.log(singleNewVal);
  123. console.log("onChange");
  124. // setValue("warehouseId", singleNewVal.value);
  125. setWarehouseId(singleNewVal.value);
  126. },
  127. []
  128. );
  129. // const accQty = watch("acceptedQty");
  130. // const validateForm = useCallback(() => {
  131. // console.log(accQty);
  132. // if (accQty > itemDetail.acceptedQty) {
  133. // setError("acceptedQty", {
  134. // message: `acceptedQty must not greater than ${itemDetail.acceptedQty}`,
  135. // type: "required",
  136. // });
  137. // }
  138. // if (accQty < 1) {
  139. // setError("acceptedQty", {
  140. // message: `minimal value is 1`,
  141. // type: "required",
  142. // });
  143. // }
  144. // if (isNaN(accQty)) {
  145. // setError("acceptedQty", {
  146. // message: `value must be a number`,
  147. // type: "required",
  148. // });
  149. // }
  150. // }, [accQty]);
  151. // useEffect(() => {
  152. // clearErrors();
  153. // validateForm();
  154. // }, [validateForm]);
  155. const qrContent = useMemo(
  156. () => ({
  157. stockInLineId: itemDetail.id,
  158. itemId: itemDetail.itemId,
  159. lotNo: itemDetail.lotNo,
  160. // warehouseId: 2 // for testing
  161. // expiryDate: itemDetail.expiryDate,
  162. // productionDate: itemDetail.productionDate,
  163. // supplier: itemDetail.supplier,
  164. // poCode: itemDetail.poCode,
  165. }),
  166. [itemDetail]
  167. );
  168. const [isOpenScanner, setOpenScanner] = useState(false);
  169. const closeHandler = useCallback<NonNullable<ModalProps["onClose"]>>(
  170. (...args) => {
  171. setOpenScanner(false);
  172. },
  173. []
  174. );
  175. const onOpenScanner = useCallback(() => {
  176. setOpenScanner(true);
  177. }, []);
  178. const onCloseScanner = useCallback(() => {
  179. setOpenScanner(false);
  180. }, []);
  181. const scannerConfig = useMemo<ScannerConfig>(
  182. () => ({
  183. onUpdate: (err, result) => {
  184. console.log(result);
  185. console.log(Boolean(result));
  186. if (result) {
  187. const data: QrCodeInfo = JSON.parse(result.getText());
  188. console.log(data);
  189. if (data.warehouseId) {
  190. console.log(data.warehouseId);
  191. setWarehouseId(data.warehouseId);
  192. onCloseScanner();
  193. }
  194. } else return;
  195. },
  196. }),
  197. [onCloseScanner]
  198. );
  199. useEffect(() => {
  200. setValue("status", "completed");
  201. }, []);
  202. useEffect(() => {
  203. if (warehouseId > 0) {
  204. setValue("warehouseId", warehouseId);
  205. clearErrors("warehouseId")
  206. }
  207. }, [warehouseId]);
  208. return (
  209. <Grid container justifyContent="flex-start" alignItems="flex-start">
  210. <Grid item xs={12}>
  211. <Typography variant="h6" display="block" marginBlockEnd={1}>
  212. {t("Putaway Detail")}
  213. </Typography>
  214. </Grid>
  215. <Grid
  216. container
  217. justifyContent="flex-start"
  218. alignItems="flex-start"
  219. spacing={2}
  220. sx={{ mt: 0.5 }}
  221. >
  222. <Grid item xs={12}>
  223. <TextField
  224. label={t("LotNo")}
  225. fullWidth
  226. value={itemDetail.lotNo}
  227. disabled
  228. />
  229. </Grid>
  230. <Grid item xs={6}>
  231. <TextField
  232. label={t("Supplier")}
  233. fullWidth
  234. value={itemDetail.supplier}
  235. disabled
  236. />
  237. </Grid>
  238. <Grid item xs={6}>
  239. <TextField
  240. label={t("Po Code")}
  241. fullWidth
  242. value={itemDetail.poCode}
  243. disabled
  244. />
  245. </Grid>
  246. <Grid item xs={6}>
  247. <TextField
  248. label={t("item name")}
  249. fullWidth
  250. value={itemDetail.itemName}
  251. disabled
  252. />
  253. </Grid>
  254. <Grid item xs={6}>
  255. <TextField
  256. label={t("item no")}
  257. fullWidth
  258. value={itemDetail.itemNo}
  259. disabled
  260. />
  261. </Grid>
  262. <Grid item xs={6}>
  263. <TextField
  264. label={t("qty")}
  265. fullWidth
  266. value={itemDetail.acceptedQty}
  267. disabled
  268. />
  269. </Grid>
  270. <Grid item xs={6}>
  271. <TextField
  272. label={t("productionDate")}
  273. fullWidth
  274. value={itemDetail.productionDate}
  275. disabled
  276. />
  277. </Grid>
  278. <Grid item xs={6}>
  279. <TextField
  280. label={t("expiryDate")}
  281. fullWidth
  282. value={itemDetail.expiryDate}
  283. disabled
  284. />
  285. </Grid>
  286. <Grid item xs={6}>
  287. <FormControl fullWidth>
  288. <Autocomplete
  289. noOptionsText={t("No Warehouse")}
  290. disableClearable
  291. disabled
  292. fullWidth
  293. defaultValue={options.find((o) => o.value === 1)} /// modify this later
  294. // onChange={onChange}
  295. getOptionLabel={(option) => option.label}
  296. options={options}
  297. renderInput={(params) => (
  298. <TextField {...params} label="Default Warehouse" />
  299. )}
  300. />
  301. </FormControl>
  302. </Grid>
  303. <Grid item xs={5.5}>
  304. <TextField
  305. label={t("acceptedQty")}
  306. fullWidth
  307. {...register("acceptedQty", {
  308. required: "acceptedQty required!",
  309. min: 1,
  310. max: itemDetail.acceptedQty,
  311. valueAsNumber: true,
  312. })}
  313. // defaultValue={itemDetail.acceptedQty}
  314. error={Boolean(errors.acceptedQty)}
  315. helperText={errors.acceptedQty?.message}
  316. />
  317. </Grid>
  318. <Grid item xs={1}>
  319. <Button onClick={onOpenScanner}>bind</Button>
  320. </Grid>
  321. <Grid item xs={5.5}>
  322. {/* <Controller
  323. control={control}
  324. name="warehouseId"
  325. render={({ field }) => {
  326. console.log(field);
  327. return (
  328. <Autocomplete
  329. noOptionsText={t("No Warehouse")}
  330. disableClearable
  331. fullWidth
  332. value={options.find((o) => o.value == field.value)}
  333. onChange={onChange}
  334. getOptionLabel={(option) => option.label}
  335. options={options}
  336. renderInput={(params) => (
  337. <TextField
  338. {...params}
  339. label={"Select warehouse"}
  340. error={Boolean(errors.warehouseId?.message)}
  341. helperText={warehouseHelperText}
  342. // helperText={errors.warehouseId?.message}
  343. />
  344. )}
  345. />
  346. );
  347. }}
  348. /> */}
  349. <FormControl fullWidth>
  350. <Autocomplete
  351. noOptionsText={t("No Warehouse")}
  352. disableClearable
  353. fullWidth
  354. // value={warehouseId > 0
  355. // ? options.find((o) => o.value === warehouseId)
  356. // : undefined}
  357. value={currentValue}
  358. onChange={onChange}
  359. getOptionLabel={(option) => option.label}
  360. options={options}
  361. renderInput={(params) => (
  362. <TextField
  363. {...params}
  364. // label={"Select warehouse"}
  365. error={Boolean(errors.warehouseId?.message)}
  366. helperText={errors.warehouseId?.message}
  367. // helperText={warehouseHelperText}
  368. />
  369. )}
  370. />
  371. </FormControl>
  372. </Grid>
  373. <Grid
  374. item
  375. xs={12}
  376. style={{ display: "flex", justifyContent: "center" }}
  377. >
  378. <QrCode content={qrContent} sx={{ width: 200, height: 200 }} />
  379. </Grid>
  380. </Grid>
  381. {/* <Grid
  382. container
  383. justifyContent="flex-start"
  384. alignItems="flex-start"
  385. spacing={2}
  386. sx={{ mt: 0.5 }}
  387. >
  388. <Button onClick={onOpenScanner}>bind</Button>
  389. </Grid> */}
  390. <Modal open={isOpenScanner} onClose={closeHandler}>
  391. <Box sx={style}>
  392. <ReactQrCodeScanner scannerConfig={scannerConfig} />
  393. </Box>
  394. </Modal>
  395. </Grid>
  396. );
  397. };
  398. export default PutawayForm;