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

11 месяцев назад
7 месяцев назад
11 месяцев назад
7 месяцев назад
1 месяц назад
11 месяцев назад
11 месяцев назад
9 месяцев назад
1 месяц назад
11 месяцев назад
9 месяцев назад
10 месяцев назад
7 месяцев назад
1 месяц назад
11 месяцев назад
10 месяцев назад
11 месяцев назад
9 месяцев назад
11 месяцев назад
7 месяцев назад
1 месяц назад
11 месяцев назад
9 месяцев назад
7 месяцев назад
11 месяцев назад
7 месяцев назад
11 месяцев назад
7 месяцев назад
9 месяцев назад
7 месяцев назад
9 месяцев назад
7 месяцев назад
9 месяцев назад
11 месяцев назад
9 месяцев назад
10 месяцев назад
7 месяцев назад
11 месяцев назад
9 месяцев назад
11 месяцев назад
9 месяцев назад
11 месяцев назад
9 месяцев назад
11 месяцев назад
7 месяцев назад
9 месяцев назад
11 месяцев назад
1 месяц назад
11 месяцев назад
7 месяцев назад
11 месяцев назад
7 месяцев назад
9 месяцев назад
7 месяцев назад
10 месяцев назад
7 месяцев назад
3 недель назад
7 месяцев назад
9 месяцев назад
7 месяцев назад
9 месяцев назад
11 месяцев назад
7 месяцев назад
11 месяцев назад
10 месяцев назад
11 месяцев назад
7 месяцев назад
11 месяцев назад
7 месяцев назад
1 месяц назад
7 месяцев назад
7 месяцев назад
11 месяцев назад
1 месяц назад
9 месяцев назад
7 месяцев назад
11 месяцев назад
7 месяцев назад
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;