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

PutawayForm.tsx 11 KiB

6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
6ヶ月前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  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;