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

PutawayForm.tsx 12 KiB

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