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

11 месяцев назад
11 месяцев назад
11 месяцев назад
7 месяцев назад
11 месяцев назад
1 месяц назад
11 месяцев назад
1 месяц назад
11 месяцев назад
1 месяц назад
11 месяцев назад
11 месяцев назад
7 месяцев назад
3 недель назад
11 месяцев назад
11 месяцев назад
10 месяцев назад
7 месяцев назад
1 месяц назад
11 месяцев назад
9 месяцев назад
7 месяцев назад
7 месяцев назад
1 месяц назад
11 месяцев назад
11 месяцев назад
1 месяц назад
1 месяц назад
11 месяцев назад
11 месяцев назад
11 месяцев назад
1 месяц назад
11 месяцев назад
10 месяцев назад
9 месяцев назад
11 месяцев назад
9 месяцев назад
3 недель назад
11 месяцев назад
11 месяцев назад
11 месяцев назад
11 месяцев назад
11 месяцев назад
11 месяцев назад
1 месяц назад
11 месяцев назад
11 месяцев назад
11 месяцев назад
11 месяцев назад
11 месяцев назад
11 месяцев назад
1 месяц назад
11 месяцев назад
11 месяцев назад
11 месяцев назад
9 месяцев назад
1 месяц назад
9 месяцев назад
1 месяц назад
9 месяцев назад
11 месяцев назад
1 месяц назад
11 месяцев назад
11 месяцев назад
1 месяц назад
7 месяцев назад
10 месяцев назад
11 месяцев назад
11 месяцев назад
11 месяцев назад
10 месяцев назад
11 месяцев назад
11 месяцев назад
11 месяцев назад
10 месяцев назад
11 месяцев назад
10 месяцев назад
9 месяцев назад
11 месяцев назад
11 месяцев назад
11 месяцев назад
11 месяцев назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. "use client";
  2. import {
  3. Autocomplete,
  4. Box,
  5. Button,
  6. Card,
  7. CardContent,
  8. FormControl,
  9. FormControlLabel,
  10. FormLabel,
  11. Grid,
  12. InputLabel,
  13. MenuItem,
  14. Radio,
  15. RadioGroup,
  16. Select,
  17. Stack,
  18. TextField,
  19. Typography,
  20. } from "@mui/material";
  21. import { Check, EditNote } from "@mui/icons-material";
  22. import { Controller, useFormContext } from "react-hook-form";
  23. import { useTranslation } from "react-i18next";
  24. import InputDataGrid from "../InputDataGrid";
  25. import { SyntheticEvent, useCallback, useEffect, useMemo, useState } from "react";
  26. import { GridColDef, GridRowModel } from "@mui/x-data-grid";
  27. import { InputDataGridProps, TableRow } from "../InputDataGrid/InputDataGrid";
  28. import { TypeEnum } from "@/app/utils/typeEnum";
  29. import { CreateItemInputs } from "@/app/api/settings/item/actions";
  30. import { ItemQc } from "@/app/api/settings/item";
  31. import { QcCategoryCombo, QcItemInfo } from "@/app/api/settings/qcCategory";
  32. import { fetchQcItemsByCategoryId } from "@/app/api/settings/qcCategory/client";
  33. import { WarehouseResult } from "@/app/api/warehouse";
  34. import QcItemsList from "./QcItemsList";
  35. type Props = {
  36. // isEditMode: boolean;
  37. // type: TypeEnum;
  38. isEditMode: boolean;
  39. // type: TypeEnum;
  40. defaultValues?: Partial<CreateItemInputs> | undefined;
  41. qcChecks?: ItemQc[];
  42. qcCategoryCombo: QcCategoryCombo[];
  43. warehouses: WarehouseResult[];
  44. };
  45. const ProductDetails: React.FC<Props> = ({ isEditMode, qcCategoryCombo, warehouses, defaultValues: initialDefaultValues }) => {
  46. const [qcItems, setQcItems] = useState<QcItemInfo[]>([]);
  47. const [qcItemsLoading, setQcItemsLoading] = useState(false);
  48. const {
  49. t,
  50. i18n: { language },
  51. } = useTranslation("items");
  52. const {
  53. register,
  54. formState: { errors, touchedFields },
  55. watch,
  56. control,
  57. setValue,
  58. getValues,
  59. setError,
  60. clearErrors,
  61. } = useFormContext<CreateItemInputs>();
  62. // const typeColumns = useMemo<GridColDef[]>(
  63. // () => [
  64. // {
  65. // field: "type",
  66. // headerName: "type",
  67. // flex: 1,
  68. // editable: true,
  69. // },
  70. // ],
  71. // []
  72. // );
  73. // const weightUnitColumns = useMemo<GridColDef[]>(
  74. // () => [
  75. // {
  76. // field: "weightUnit",
  77. // headerName: "Weight Unit",
  78. // flex: 1,
  79. // editable: true,
  80. // },
  81. // {
  82. // field: "conversion",
  83. // headerName: "conversion", // show base unit
  84. // flex: 1,
  85. // type: "number",
  86. // editable: true,
  87. // },
  88. // ],
  89. // []
  90. // );
  91. // const uomColumns = useMemo<GridColDef[]>(
  92. // () => [
  93. // {
  94. // field: "uom",
  95. // headerName: "uom",
  96. // flex: 1,
  97. // editable: true,
  98. // },
  99. // ],
  100. // []
  101. // );
  102. // const validationTest = useCallback(
  103. // (
  104. // newRow: GridRowModel<TableRow<Partial<CreateItemInputs>, EntryError>>
  105. // ): EntryError => {
  106. // const error: EntryError = {};
  107. // console.log(newRow);
  108. // return Object.keys(error).length > 0 ? error : undefined;
  109. // },
  110. // []
  111. // );
  112. const handleAutoCompleteChange = useCallback((event: SyntheticEvent<Element, Event>, value: QcCategoryCombo, onChange: (...event: any[]) => void) => {
  113. onChange(value.id)
  114. }, [])
  115. // Ensure LocationCode is set from defaultValues when component mounts
  116. useEffect(() => {
  117. if (initialDefaultValues?.LocationCode && !getValues("LocationCode")) {
  118. setValue("LocationCode", initialDefaultValues.LocationCode);
  119. }
  120. }, [initialDefaultValues, setValue, getValues]);
  121. // Watch qcCategoryId and fetch QC items when it changes
  122. const qcCategoryId = watch("qcCategoryId");
  123. useEffect(() => {
  124. const fetchItems = async () => {
  125. if (qcCategoryId) {
  126. setQcItemsLoading(true);
  127. try {
  128. const items = await fetchQcItemsByCategoryId(qcCategoryId);
  129. setQcItems(items);
  130. } catch (error) {
  131. console.error("Failed to fetch QC items:", error);
  132. setQcItems([]);
  133. } finally {
  134. setQcItemsLoading(false);
  135. }
  136. } else {
  137. setQcItems([]);
  138. }
  139. };
  140. fetchItems();
  141. }, [qcCategoryId]);
  142. return (
  143. <Card sx={{ display: "block" }}>
  144. <CardContent component={Stack} spacing={4}>
  145. <Box>
  146. <Typography variant="overline" display="block" marginBlockEnd={1}>
  147. {t("Product Details")}
  148. </Typography>
  149. <Grid container spacing={2} columns={{ xs: 6, sm: 12 }}>
  150. <Grid item xs={6}>
  151. <TextField
  152. label={t("Name")}
  153. fullWidth
  154. disabled
  155. {...register("name", {
  156. required: "name required!",
  157. })}
  158. error={Boolean(errors.name)}
  159. helperText={errors.name?.message}
  160. />
  161. </Grid>
  162. <Grid item xs={6}>
  163. <TextField
  164. label={t("Code")}
  165. fullWidth
  166. disabled
  167. {...register("code", {
  168. required: "code required!",
  169. })}
  170. error={Boolean(errors.code)}
  171. helperText={errors.code?.message}
  172. />
  173. </Grid>
  174. <Grid item xs={6}>
  175. <Controller
  176. control={control}
  177. name="type"
  178. rules={{
  179. required: "type required!",
  180. }}
  181. render={({ field }) => (
  182. <FormControl fullWidth error={Boolean(errors.type)}>
  183. <InputLabel>{t("Type")}</InputLabel>
  184. <Select
  185. value={field.value || ""}
  186. label={t("Type")}
  187. onChange={field.onChange}
  188. onBlur={field.onBlur}
  189. >
  190. <MenuItem value="fg">FG</MenuItem>
  191. <MenuItem value="wip">WIP</MenuItem>
  192. <MenuItem value="mat">MAT</MenuItem>
  193. <MenuItem value="cmb">CMB</MenuItem>
  194. <MenuItem value="nm">NM</MenuItem>
  195. </Select>
  196. {errors.type && (
  197. <Typography variant="caption" color="error" sx={{ mt: 0.5, ml: 1.5 }}>
  198. {errors.type.message}
  199. </Typography>
  200. )}
  201. </FormControl>
  202. )}
  203. />
  204. </Grid>
  205. <Grid item xs={6}>
  206. <TextField
  207. label={t("description")}
  208. fullWidth
  209. disabled
  210. {...register("description")}
  211. />
  212. </Grid>
  213. <Grid item xs={6}>
  214. <Controller
  215. control={control}
  216. name="qcCategoryId"
  217. render={({ field }) => (
  218. <Autocomplete
  219. disableClearable
  220. options={qcCategoryCombo}
  221. defaultValue={qcCategoryCombo.find(qc => qc.id === field.value)}
  222. onChange={(event, value) => {
  223. handleAutoCompleteChange(event, value, field.onChange)
  224. }}
  225. onBlur={field.onBlur}
  226. renderInput={(params) => (
  227. <TextField
  228. {...params}
  229. variant="outlined"
  230. label={t("Qc Category")}
  231. />
  232. )}
  233. />
  234. )}
  235. />
  236. </Grid>
  237. <Grid item xs={6}>
  238. <Controller
  239. control={control}
  240. name="qcType"
  241. render={({ field }) => (
  242. <FormControl fullWidth>
  243. <InputLabel>{t("QC Type")}</InputLabel>
  244. <Select
  245. value={field.value || ""}
  246. label={t("QC Type")}
  247. onChange={field.onChange}
  248. onBlur={field.onBlur}
  249. >
  250. <MenuItem value="IPQC">{t("IPQC")}</MenuItem>
  251. <MenuItem value="EPQC">{t("EPQC")}</MenuItem>
  252. </Select>
  253. </FormControl>
  254. )}
  255. />
  256. </Grid>
  257. <Grid item xs={6}>
  258. <Controller
  259. control={control}
  260. name="LocationCode"
  261. render={({ field }) => (
  262. <Autocomplete
  263. freeSolo
  264. options={warehouses.map((w) => ({
  265. label: `${w.code}`,
  266. code: w.code,
  267. }))}
  268. getOptionLabel={(option) =>
  269. typeof option === "string"
  270. ? option
  271. : option.label ?? option.code ?? ""
  272. }
  273. value={
  274. warehouses
  275. .map((w) => ({
  276. label: `${w.code}`,
  277. code: w.code,
  278. }))
  279. .find((opt) => opt.code === field.value) ||
  280. (field.value
  281. ? { label: field.value as string, code: field.value as string }
  282. : null)
  283. }
  284. onChange={(_e, value) => {
  285. if (typeof value === "string") {
  286. field.onChange(value.trim() === "" ? undefined : value);
  287. } else {
  288. field.onChange(value?.code ? (value.code.trim() === "" ? undefined : value.code) : undefined);
  289. }
  290. }}
  291. onInputChange={(_e, value) => {
  292. // keep manual input synced - convert empty string to undefined
  293. field.onChange(value.trim() === "" ? undefined : value);
  294. }}
  295. renderInput={(params) => (
  296. <TextField
  297. {...params}
  298. label={t("DefaultLocationCode")}
  299. fullWidth
  300. error={Boolean(errors.LocationCode)}
  301. helperText={errors.LocationCode?.message}
  302. />
  303. )}
  304. />
  305. )}
  306. />
  307. </Grid>
  308. <Grid item xs={12}>
  309. <FormControl component="fieldset">
  310. <FormLabel component="legend">{t("Special Type")}</FormLabel>
  311. <RadioGroup
  312. row
  313. value={
  314. watch("isEgg") === true ? "isEgg" :
  315. watch("isFee") === true ? "isFee" :
  316. watch("isBag") === true ? "isBag" :
  317. "none"
  318. }
  319. onChange={(e) => {
  320. const value = e.target.value;
  321. setValue("isEgg", value === "isEgg", { shouldValidate: true });
  322. setValue("isFee", value === "isFee", { shouldValidate: true });
  323. setValue("isBag", value === "isBag", { shouldValidate: true });
  324. }}
  325. >
  326. <FormControlLabel value="none" control={<Radio />} label={t("None")} />
  327. <FormControlLabel value="isEgg" control={<Radio />} label={t("isEgg")} />
  328. <FormControlLabel value="isFee" control={<Radio />} label={t("isFee")} />
  329. <FormControlLabel value="isBag" control={<Radio />} label={t("isBag")} />
  330. </RadioGroup>
  331. </FormControl>
  332. </Grid>
  333. <Grid item xs={12}>
  334. <QcItemsList
  335. qcItems={qcItems}
  336. loading={qcItemsLoading}
  337. categorySelected={!!qcCategoryId}
  338. />
  339. </Grid>
  340. <Grid item xs={12}>
  341. <Stack
  342. direction="row"
  343. justifyContent="flex-end"
  344. spacing={2}
  345. sx={{ mt: 2 }}
  346. >
  347. <Button
  348. name="submit"
  349. variant="contained"
  350. startIcon={<Check />}
  351. type="submit"
  352. // disabled={submitDisabled}
  353. >
  354. {isEditMode ? t("Save") : t("Confirm")}
  355. </Button>
  356. </Stack>
  357. </Grid>
  358. {/* <Grid item xs={6}>
  359. <InputDataGrid<CreateItemInputs, EntryError>
  360. _formKey={"type"}
  361. columns={typeColumns}
  362. validateRow={validationTest}
  363. />
  364. </Grid>
  365. <Grid item xs={6}>
  366. <InputDataGrid<CreateItemInputs, EntryError>
  367. _formKey={"uom"}
  368. columns={uomColumns}
  369. validateRow={validationTest}
  370. />
  371. </Grid>
  372. <Grid item xs={12}>
  373. <InputDataGrid<CreateItemInputs, EntryError>
  374. _formKey={"weightUnit"}
  375. columns={weightUnitColumns}
  376. validateRow={validationTest}
  377. />
  378. </Grid>*/}
  379. </Grid>
  380. </Box>
  381. </CardContent>
  382. </Card>
  383. );
  384. };
  385. export default ProductDetails;