FPSMS-frontend
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

CreateItem.tsx 8.1 KiB

11 个月前
11 个月前
11 个月前
11 个月前
10 个月前
11 个月前
10 个月前
11 个月前
11 个月前
11 个月前
11 个月前
7 个月前
11 个月前
11 个月前
10 个月前
11 个月前
11 个月前
11 个月前
11 个月前
11 个月前
11 个月前
10 个月前
11 个月前
11 个月前
10 个月前
11 个月前
11 个月前
11 个月前
11 个月前
11 个月前
10 个月前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. "use client";
  2. import { useCallback, useEffect, useMemo, useState } from "react";
  3. import { useRouter, useSearchParams } from "next/navigation";
  4. import { useTranslation } from "react-i18next";
  5. import { CreateItemInputs, saveItem } from "@/app/api/settings/item/actions";
  6. import {
  7. FormProvider,
  8. SubmitErrorHandler,
  9. SubmitHandler,
  10. useForm,
  11. } from "react-hook-form";
  12. import { deleteDialog } from "../Swal/CustomAlerts";
  13. import {
  14. Box,
  15. Button,
  16. Grid,
  17. Stack,
  18. Tab,
  19. Tabs,
  20. TabsProps,
  21. Typography,
  22. } from "@mui/material";
  23. import { Check, Close, EditNote, ArrowBack } from "@mui/icons-material";
  24. import { TypeEnum } from "@/app/utils/typeEnum";
  25. import ProductDetails from "./ProductDetails";
  26. import { CreateItemResponse } from "@/app/api/utils";
  27. import QcDetails from "./QcDetails";
  28. import { ItemQc } from "@/app/api/settings/item";
  29. import { saveItemQcChecks } from "@/app/api/settings/qcCheck/actions";
  30. import { useGridApiRef } from "@mui/x-data-grid";
  31. import { QcCategoryCombo } from "@/app/api/settings/qcCategory";
  32. import { WarehouseResult } from "@/app/api/warehouse";
  33. type Props = {
  34. isEditMode: boolean;
  35. // type: TypeEnum;
  36. defaultValues: Partial<CreateItemInputs> | undefined;
  37. qcChecks: ItemQc[];
  38. qcCategoryCombo: QcCategoryCombo[];
  39. warehouses: WarehouseResult[];
  40. };
  41. const CreateItem: React.FC<Props> = ({
  42. isEditMode,
  43. // type,
  44. defaultValues,
  45. qcChecks,
  46. qcCategoryCombo,
  47. warehouses,
  48. }) => {
  49. // console.log(type)
  50. const apiRef = useGridApiRef();
  51. const params = useSearchParams();
  52. console.log(params.get("id"));
  53. const [serverError, setServerError] = useState("");
  54. const [tabIndex, setTabIndex] = useState(0);
  55. const { t } = useTranslation("items");
  56. const router = useRouter();
  57. const title = "Product / Material";
  58. const [mode, redirPath] = useMemo(() => {
  59. // var typeId = TypeEnum.CONSUMABLE_ID
  60. let title = "";
  61. let mode = "";
  62. let redirPath = "";
  63. // if (type === TypeEnum.MATERIAL) {
  64. // typeId = TypeEnum.MATERIAL_ID
  65. // title = "Material";
  66. // redirPath = "/settings/material";
  67. // }
  68. // if (type === TypeEnum.PRODUCT) {
  69. // typeId = TypeEnum.PRODUCT_ID
  70. title = "Product";
  71. redirPath = "/settings/items";
  72. // }
  73. // if (type === TypeEnum.BYPRODUCT) {
  74. // typeId = TypeEnum.BYPRODUCT_ID
  75. // title = "By-Product";
  76. // redirPath = "/settings/byProduct";
  77. // }
  78. if (isEditMode) {
  79. mode = "Edit";
  80. } else {
  81. mode = "Create";
  82. }
  83. return [mode, redirPath];
  84. }, [isEditMode]);
  85. // console.log(typeId)
  86. const formProps = useForm<CreateItemInputs>({
  87. defaultValues: defaultValues ? defaultValues : {},
  88. });
  89. const errors = formProps.formState.errors;
  90. const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>(
  91. (_e, newValue) => {
  92. setTabIndex(newValue);
  93. },
  94. [],
  95. );
  96. const handleCancel = () => {
  97. router.replace(`/settings/product`);
  98. };
  99. const onSubmit = useCallback<SubmitHandler<CreateItemInputs & {}>>(
  100. async (data, event) => {
  101. const hasErrors = false;
  102. console.log(errors);
  103. // console.log(apiRef.current.getCellValue(2, "lowerLimit"))
  104. // apiRef.current.
  105. try {
  106. if (hasErrors) {
  107. setServerError(t("An error has occurred. Please try again later."));
  108. return false;
  109. }
  110. // Normalize LocationCode: convert empty string to null
  111. if (data.LocationCode && data.LocationCode.trim() !== "") {
  112. // Parse LocationCode and populate store_id, warehouse, area, slot
  113. const parts = data.LocationCode.split("-");
  114. if (parts.length >= 4) {
  115. data.store_id = parts[0] || undefined;
  116. data.warehouse = parts[1] || undefined;
  117. data.area = parts[2] || undefined;
  118. data.slot = parts[3] || undefined;
  119. }
  120. } else {
  121. // If LocationCode is null or empty, set LocationCode to null and clear related fields
  122. data.LocationCode = undefined;
  123. data.store_id = undefined;
  124. data.warehouse = undefined;
  125. data.area = undefined;
  126. data.slot = undefined;
  127. }
  128. console.log("data posted");
  129. console.log(data);
  130. const qcCheck =
  131. data.qcChecks.length > 0
  132. ? data.qcChecks
  133. .filter((q) => data.qcChecks_active.includes(q.id!))
  134. .map((qc) => {
  135. return {
  136. qcItemId: qc.id,
  137. instruction: qc.instruction,
  138. lowerLimit: qc.lowerLimit,
  139. upperLimit: qc.upperLimit,
  140. itemId: parseInt(params.get("id")!.toString()),
  141. };
  142. })
  143. : [];
  144. const test = data.qcChecks.filter((q) =>
  145. data.qcChecks_active.includes(q.id!),
  146. );
  147. // TODO:
  148. // 1. check field ( directly modify col def / check here )
  149. // 2. set error change tab index
  150. console.log(test);
  151. console.log(qcCheck);
  152. // return
  153. // do api
  154. const responseI = await saveItem(data);
  155. const responseQ = await saveItemQcChecks(qcCheck);
  156. if (responseI && responseQ) {
  157. if (!Boolean(responseI.id)) {
  158. formProps.setError(
  159. responseI.errorPosition! as keyof CreateItemInputs,
  160. {
  161. message: responseI.message!,
  162. type: "required",
  163. },
  164. );
  165. } else if (!Boolean(responseQ.id)) {
  166. } else if (Boolean(responseI.id) && Boolean(responseQ.id)) {
  167. router.replace(redirPath);
  168. }
  169. }
  170. } catch (e) {
  171. // backend error
  172. setServerError(t("An error has occurred. Please try again later."));
  173. console.log(e);
  174. }
  175. },
  176. [apiRef, router, t],
  177. );
  178. // multiple tabs
  179. const onSubmitError = useCallback<SubmitErrorHandler<CreateItemInputs>>(
  180. (errors) => {},
  181. [],
  182. );
  183. return (
  184. <>
  185. <FormProvider {...formProps}>
  186. <Stack
  187. spacing={2}
  188. component="form"
  189. onSubmit={formProps.handleSubmit(onSubmit, onSubmitError)}
  190. >
  191. <Grid>
  192. <Stack direction="column" spacing={1} mb={2}>
  193. <Button
  194. variant="outlined"
  195. startIcon={<ArrowBack />}
  196. onClick={() => router.push("/settings/items")}
  197. sx={{ alignSelf: "flex-start", minWidth: "auto" }}
  198. >
  199. {t("Back")}
  200. </Button>
  201. <Typography variant="h4">
  202. {t(`${mode} ${title}`)}
  203. </Typography>
  204. </Stack>
  205. </Grid>
  206. <Tabs
  207. value={tabIndex}
  208. onChange={handleTabChange}
  209. variant="scrollable"
  210. >
  211. <Tab label={t("Product / Material Details")} iconPosition="end" />
  212. {/* <Tab label={t("Qc items")} iconPosition="end" /> */}
  213. </Tabs>
  214. {serverError && (
  215. <Typography variant="body2" color="error" alignSelf="flex-end">
  216. {serverError}
  217. </Typography>
  218. )}
  219. {tabIndex === 0 && (
  220. <ProductDetails
  221. isEditMode={isEditMode}
  222. qcCategoryCombo={qcCategoryCombo}
  223. warehouses={warehouses}
  224. defaultValues={defaultValues}
  225. />
  226. )}
  227. {tabIndex === 1 && <QcDetails apiRef={apiRef} />}
  228. {/* {type === TypeEnum.MATERIAL && <MaterialDetails />} */}
  229. {/* {type === TypeEnum.BYPRODUCT && <ByProductDetails />} */}
  230. {/*
  231. <Stack direction="row" justifyContent="flex-end" gap={1}>
  232. <Button
  233. name="submit"
  234. variant="contained"
  235. startIcon={<Check />}
  236. type="submit"
  237. >
  238. {isEditMode ? t("Save") : t("Confirm")}
  239. </Button>
  240. <Button
  241. variant="outlined"
  242. startIcon={<Close />}
  243. onClick={handleCancel}
  244. >
  245. {t("Cancel")}
  246. </Button>
  247. </Stack>
  248. */}
  249. </Stack>
  250. </FormProvider>
  251. </>
  252. );
  253. };
  254. export default CreateItem;