FPSMS-frontend
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 

345 Zeilen
10 KiB

  1. "use client";
  2. import React, { useCallback, useEffect, useMemo, useState } from "react";
  3. import SearchBox, { Criterion } from "../SearchBox";
  4. import SearchResults, { Column } from "../SearchResults";
  5. import { EditNote } from "@mui/icons-material";
  6. import { useRouter, useSearchParams } from "next/navigation";
  7. import { useTranslation } from "react-i18next";
  8. import { ScheduleType } from "@/app/api/scheduling";
  9. import {
  10. ProdScheduleResult,
  11. SearchProdSchedule,
  12. fetchDetailedProdSchedules,
  13. fetchProdSchedules,
  14. testDetailedSchedule,
  15. } from "@/app/api/scheduling/actions";
  16. import { defaultPagingController } from "../SearchResults/SearchResults";
  17. import { arrayToDateString, arrayToDayjs, decimalFormatter } from "@/app/utils/formatUtil";
  18. import dayjs from "dayjs";
  19. import { orderBy, uniqBy, upperFirst } from "lodash";
  20. import { Button, Stack } from "@mui/material";
  21. import isToday from 'dayjs/plugin/isToday';
  22. import useUploadContext from "../UploadProvider/useUploadContext";
  23. dayjs.extend(isToday);
  24. // may need move to "index" or "actions"
  25. // type RecordStructure = {
  26. // id: number,
  27. // scheduledPeriod: string,
  28. // scheduledAt: string,
  29. // productCount: number,
  30. // };
  31. type Props = {
  32. type: ScheduleType;
  33. // records: RecordStructure[];
  34. defaultInputs: SearchProdSchedule;
  35. };
  36. type SearchQuery = Partial<
  37. Omit<SearchProdSchedule, "id" | "pageSize" | "pageNum">
  38. >;
  39. type SearchParamNames = keyof SearchQuery;
  40. const DSOverview: React.FC<Props> = ({ type, defaultInputs }) => {
  41. const [filteredSchedules, setFilteredSchedules] = useState<
  42. ProdScheduleResult[]
  43. >([]);
  44. const { t } = useTranslation("schedule");
  45. const { setIsUploading } = useUploadContext();
  46. const router = useRouter();
  47. // const [filterObj, setFilterObj] = useState({});
  48. // const [tempSelectedValue, setTempSelectedValue] = useState({});
  49. const [pagingController, setPagingController] = useState(
  50. defaultPagingController,
  51. );
  52. const [totalCount, setTotalCount] = useState(0);
  53. const [inputs, setInputs] = useState(defaultInputs);
  54. const typeOptions = [
  55. {
  56. value: "detailed",
  57. label: t("Detailed"),
  58. },
  59. {
  60. value: "manual",
  61. label: t("Manual"),
  62. },
  63. ];
  64. const searchCriteria: Criterion<SearchParamNames>[] = useMemo(() => {
  65. const searchCriteria: Criterion<SearchParamNames>[] = [
  66. // {
  67. // label: t("Schedule Period"),
  68. // label2: t("Schedule Period To"),
  69. // paramName: "schedulePeriod",
  70. // type: "dateRange",
  71. // },
  72. { label: t("Production Date"), paramName: "scheduleAt", type: "date" },
  73. //{
  74. // label: t("Product Count"),
  75. // paramName: "totalEstProdCount",
  76. // type: "text",
  77. //},
  78. //{
  79. // label: t("Type"),
  80. // paramName: "types",
  81. // type: "autocomplete",
  82. // options: typeOptions,
  83. //},
  84. ];
  85. return searchCriteria;
  86. }, [t]);
  87. // const onDetailClick = useCallback(
  88. // (item: ItemsResult) => {
  89. // router.push(`/settings/items/edit?id=${item.id}`);
  90. // },
  91. // [router]
  92. // );
  93. // const onDeleteClick = useCallback(
  94. // (item: ItemsResult) => {},
  95. // [router]
  96. // );
  97. const onDetailClick = (record: ProdScheduleResult) => {
  98. console.log("[debug] record", record);
  99. router.push(`/scheduling/detailed/edit?id=${record.id}`);
  100. };
  101. const columns = useMemo<Column<ProdScheduleResult>[]>(
  102. () => [
  103. {
  104. name: "id",
  105. label: t("Details"),
  106. onClick: (record) => onDetailClick(record),
  107. buttonIcon: <EditNote />,
  108. },
  109. // {
  110. // name: "schedulePeriod",
  111. // label: t("Demand Forecast Period"),
  112. // renderCell: (params) => {
  113. // return `${arrayToDateString(
  114. // params.schedulePeriod,
  115. // )} - ${arrayToDateString(params.schedulePeriodTo)}`;
  116. // },
  117. // },
  118. {
  119. name: "produceAt",
  120. label: t("Production Date"),
  121. renderCell: (params) => {
  122. return arrayToDateString(params.produceAt);
  123. },
  124. },
  125. {
  126. name: "totalEstProdCount",
  127. label: t("Product Count(s)"),
  128. headerAlign: "right",
  129. align: "right",
  130. renderCell: (params) => {
  131. return decimalFormatter.format(params.totalEstProdCount);
  132. },
  133. },
  134. {
  135. name: "type",
  136. label: t("Type"),
  137. renderCell: (params) => {
  138. return upperFirst(t(params.type));
  139. },
  140. },
  141. // {
  142. // name: "action",
  143. // label: t(""),
  144. // buttonIcon: <GridDeleteIcon />,
  145. // onClick: onDeleteClick,
  146. // },
  147. ],
  148. [filteredSchedules],
  149. );
  150. const refetchData = useCallback(
  151. async (
  152. query: Record<SearchParamNames, string> | SearchProdSchedule,
  153. actionType: "reset" | "search" | "paging",
  154. ) => {
  155. // console.log(query)
  156. const defaultTypes = ["detailed", "manual"];
  157. const convertedTypes = (
  158. query.types == undefined || typeof query.types == "string"
  159. ? query.types?.toLowerCase() == "all"
  160. ? defaultTypes
  161. : [query.types]
  162. : query.types.some((ele) => ele.toLowerCase() === "all")
  163. ? defaultTypes
  164. : query.types
  165. ) as ScheduleType[];
  166. const params: SearchProdSchedule = {
  167. //scheduleAt: dayjs(query?.scheduleAt).isValid()
  168. // ? query?.scheduleAt
  169. // : undefined,
  170. //schedulePeriod: dayjs(query?.schedulePeriod).isValid()
  171. // ? query?.schedulePeriod
  172. // : undefined,
  173. //schedulePeriodTo: dayjs(query?.schedulePeriodTo).isValid()
  174. // ? query?.schedulePeriodTo
  175. // : undefined,
  176. //totalEstProdCount: query?.totalEstProdCount
  177. // ? Number(query?.totalEstProdCount)
  178. // : undefined,
  179. types: convertedTypes,
  180. pageNum: pagingController.pageNum - 1,
  181. pageSize: pagingController.pageSize,
  182. };
  183. const response = await fetchDetailedProdSchedules(params);
  184. // console.log(response)
  185. if (response) {
  186. setTotalCount(response.total);
  187. switch (actionType) {
  188. case "reset":
  189. case "search":
  190. setFilteredSchedules(() => response.records);
  191. break;
  192. case "paging":
  193. setFilteredSchedules((fs) =>
  194. orderBy(
  195. uniqBy([...fs, ...response.records], "id"),
  196. ["id"], ["asc"]));
  197. break;
  198. }
  199. }
  200. },
  201. [pagingController, setPagingController],
  202. );
  203. useEffect(() => {
  204. refetchData(inputs, "paging");
  205. }, [pagingController]);
  206. // useEffect(() => {
  207. // refetchData(filterObj);
  208. // }, [filterObj, pagingController.pageNum, pagingController.pageSize]);
  209. // const refetchData = async (filterObj: SearchQuery | null) => {
  210. // const authHeader = axiosInstance.defaults.headers['Authorization'];
  211. // if (!authHeader) {
  212. // return; // Exit the function if the token is not set
  213. // }
  214. // const params = {
  215. // pageNum: pagingController.pageNum,
  216. // pageSize: pagingController.pageSize,
  217. // ...filterObj,
  218. // ...tempSelectedValue,
  219. // }
  220. // try {
  221. // const response = await axiosInstance.get<ItemsResult[]>(`${NEXT_PUBLIC_API_URL}/items/getRecordByPage`, {
  222. // params,
  223. // paramsSerializer: (params) => {
  224. // return Qs.stringify(params, { arrayFormat: 'repeat' });
  225. // },
  226. // });
  227. // //setFilteredItems(response.data.records);
  228. // setFilteredItems([
  229. // {
  230. // id: 1,
  231. // scheduledPeriod: "2025-05-11 to 2025-05-17",
  232. // scheduledAt: "2025-05-07",
  233. // productCount: 13,
  234. // },
  235. // {
  236. // id: 2,
  237. // scheduledPeriod: "2025-05-18 to 2025-05-24",
  238. // scheduledAt: "2025-05-14",
  239. // productCount: 15,
  240. // },
  241. // {
  242. // id: 3,
  243. // scheduledPeriod: "2025-05-25 to 2025-05-31",
  244. // scheduledAt: "2025-05-21",
  245. // productCount: 13,
  246. // },
  247. // ])
  248. // setPagingController({
  249. // ...pagingController,
  250. // totalCount: response.data.total
  251. // })
  252. // return response; // Return the data from the response
  253. // } catch (error) {
  254. // console.error('Error fetching items:', error);
  255. // throw error; // Rethrow the error for further handling
  256. // }
  257. // };
  258. const onReset = useCallback(() => {
  259. //setFilteredItems(items ?? []);
  260. // setFilterObj({});
  261. // setTempSelectedValue({});
  262. refetchData(defaultInputs, "reset");
  263. }, []);
  264. const testDetailedScheduleClick = useCallback(async () => {
  265. try {
  266. setIsUploading(true)
  267. const response = await testDetailedSchedule(inputs.scheduleAt)
  268. if (response) {
  269. refetchData(inputs, "paging");
  270. }
  271. } catch(e) {
  272. console.log(e)
  273. } finally {
  274. setIsUploading(false)
  275. }
  276. }, [inputs])
  277. return (
  278. <>
  279. <Stack
  280. direction="row"
  281. justifyContent="flex-end"
  282. flexWrap="wrap"
  283. rowGap={2}
  284. >
  285. <Button
  286. variant="contained"
  287. onClick={testDetailedScheduleClick}
  288. // disabled={filteredSchedules.some(ele => arrayToDayjs(ele.scheduleAt).isToday())}
  289. >
  290. {t("Detailed Schedule")}
  291. </Button>
  292. </Stack>
  293. <SearchBox
  294. criteria={searchCriteria}
  295. onSearch={(query) => {
  296. setInputs(() => ({
  297. scheduleAt: query?.scheduleAt,
  298. schedulePeriod: query?.schedulePeriod,
  299. schedulePeriodTo: query?.schedulePeriodTo,
  300. totalEstProdCount: Number(query?.totalEstProdCount),
  301. types: query.types as unknown as ScheduleType[],
  302. }));
  303. refetchData(query, "search");
  304. }}
  305. onReset={onReset}
  306. />
  307. <SearchResults<ProdScheduleResult>
  308. items={filteredSchedules}
  309. columns={columns}
  310. setPagingController={setPagingController}
  311. pagingController={pagingController}
  312. totalCount={totalCount}
  313. // isAutoPaging={false}
  314. // hasCollapse={false}
  315. />
  316. </>
  317. );
  318. };
  319. export default DSOverview;