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

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