FPSMS-frontend
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

300 regels
8.5 KiB

  1. "use client";
  2. import { DoResult } from "@/app/api/do";
  3. import { useRouter } from "next/navigation";
  4. import { useCallback, useMemo, useState } from "react";
  5. import { useTranslation } from "react-i18next";
  6. import { Criterion } from "../SearchBox";
  7. import { isEmpty, sortBy, uniqBy, upperFirst } from "lodash";
  8. import { Column } from "../SearchResults";
  9. import { arrayToDateString, arrayToDayjs } from "@/app/utils/formatUtil";
  10. import SearchBox from "../SearchBox/SearchBox";
  11. import SearchResults from "../SearchResults/SearchResults";
  12. import { EditNote } from "@mui/icons-material";
  13. import InputDataGrid from "../InputDataGrid";
  14. import { CreateConsoDoInput } from "@/app/api/do/actions";
  15. import { TableRow } from "../InputDataGrid/InputDataGrid";
  16. import { FooterPropsOverrides, GridColDef, GridRowModel, GridToolbarContainer, useGridApiRef } from "@mui/x-data-grid";
  17. import {
  18. FormProvider,
  19. SubmitErrorHandler,
  20. SubmitHandler,
  21. useForm,
  22. } from "react-hook-form";
  23. import { Box, Button, Grid, Stack, Typography } from "@mui/material";
  24. import StyledDataGrid from "../StyledDataGrid";
  25. import { GridRowSelectionModel } from "@mui/x-data-grid";
  26. type Props = {
  27. dos: DoResult[];
  28. };
  29. type SearchQuery = Partial<Omit<DoResult, "id">>;
  30. type SearchParamNames = keyof SearchQuery;
  31. // put all this into a new component
  32. // ConsoDoForm
  33. type EntryError =
  34. | {
  35. [field in keyof DoResult]?: string;
  36. }
  37. | undefined;
  38. type DoRow = TableRow<Partial<DoResult>, EntryError>;
  39. const DoSearch: React.FC<Props> = ({ dos }) => {
  40. const apiRef = useGridApiRef();
  41. const formProps = useForm<CreateConsoDoInput>({
  42. defaultValues: {},
  43. });
  44. const errors = formProps.formState.errors;
  45. const tttt = [
  46. {
  47. id: 1,
  48. code: "string",
  49. orderDate: "2025-01-01",
  50. estimatedArrivalDate: "2025-01-01",
  51. status: "string",
  52. shopName: "string",
  53. },
  54. {
  55. id: 2,
  56. code: "string1",
  57. orderDate: "2025-01-01",
  58. estimatedArrivalDate: "2025-01-01",
  59. status: "string",
  60. shopName: "string",
  61. },
  62. {
  63. id: 3,
  64. code: "string2",
  65. orderDate: "2025-01-01",
  66. estimatedArrivalDate: "2025-01-01",
  67. status: "string",
  68. shopName: "string",
  69. },
  70. ]
  71. // const [filteredDos, setFilteredDos] = useState<DoResult[]>(dos);
  72. const [filteredDos, setFilteredDos] = useState<DoResult[]>(tttt);
  73. const { t } = useTranslation("do");
  74. const router = useRouter();
  75. const [rowSelectionModel, setRowSelectionModel] = useState<GridRowSelectionModel>([])
  76. const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
  77. () => [
  78. { label: t("Code"), paramName: "code", type: "text" },
  79. {
  80. label: t("Order Date From"),
  81. label2: t("Order Date To"),
  82. paramName: "orderDate",
  83. type: "dateRange",
  84. },
  85. { label: t("Shop Name"), paramName: "shopName", type: "text" },
  86. {
  87. label: t("Status"),
  88. paramName: "status",
  89. type: "autocomplete",
  90. options: sortBy(
  91. uniqBy(
  92. dos.map((_do) => ({
  93. value: _do.status,
  94. label: t(upperFirst(_do.status)),
  95. })),
  96. "value"
  97. ),
  98. "label"
  99. ),
  100. },
  101. ],
  102. [t, dos]
  103. );
  104. const onReset = useCallback(() => {
  105. setFilteredDos(dos);
  106. }, [dos]);
  107. const onDetailClick = useCallback(
  108. (doResult: DoResult) => {
  109. router.push(`/do/edit?id=${doResult.id}`);
  110. },
  111. [router]
  112. );
  113. const validationTest = useCallback(
  114. (
  115. newRow: GridRowModel<DoRow>
  116. // rowModel: GridRowSelectionModel
  117. ): EntryError => {
  118. const error: EntryError = {};
  119. console.log(newRow);
  120. // if (!newRow.lowerLimit) {
  121. // error["lowerLimit"] = "lower limit cannot be null"
  122. // }
  123. // if (newRow.lowerLimit && newRow.upperLimit && newRow.lowerLimit > newRow.upperLimit) {
  124. // error["lowerLimit"] = "lower limit should not be greater than upper limit"
  125. // error["upperLimit"] = "lower limit should not be greater than upper limit"
  126. // }
  127. return Object.keys(error).length > 0 ? error : undefined;
  128. },
  129. []
  130. );
  131. const columns = useMemo<GridColDef[]>(
  132. () => [
  133. // {
  134. // name: "id",
  135. // label: t("Details"),
  136. // onClick: onDetailClick,
  137. // buttonIcon: <EditNote />,
  138. // },
  139. {
  140. field: "code",
  141. headerName: t("code"),
  142. flex: 1,
  143. },
  144. {
  145. field: "shopName",
  146. headerName: t("Shop Name"),
  147. flex: 1,
  148. },
  149. {
  150. field: "orderDate",
  151. headerName: t("Order Date"),
  152. flex: 1,
  153. renderCell: (params) => {
  154. return params.row.orderDate
  155. ? arrayToDateString(params.row.orderDate)
  156. : "N/A";
  157. },
  158. },
  159. {
  160. field: "estimatedArrivalDate",
  161. headerName: t("Estimated Arrival"),
  162. flex: 1,
  163. renderCell: (params) => {
  164. return params.row.estimatedArrivalDate
  165. ? arrayToDateString(params.row.estimatedArrivalDate)
  166. : "N/A";
  167. },
  168. },
  169. {
  170. field: "status",
  171. headerName: t("Status"),
  172. flex: 1,
  173. renderCell: (params) => {
  174. return t(upperFirst(params.row.status));
  175. },
  176. },
  177. ],
  178. [t, arrayToDateString]
  179. );
  180. const onSubmit = useCallback<SubmitHandler<CreateConsoDoInput>>(
  181. async (data, event) => {
  182. let hasErrors = false;
  183. console.log(errors);
  184. console.log(data);
  185. },
  186. []
  187. );
  188. const onSubmitError = useCallback<SubmitErrorHandler<CreateConsoDoInput>>(
  189. (errors) => {},
  190. []
  191. );
  192. return (
  193. <>
  194. <FormProvider {...formProps}>
  195. <Stack
  196. spacing={2}
  197. component="form"
  198. onSubmit={formProps.handleSubmit(onSubmit, onSubmitError)}
  199. >
  200. <Grid container>
  201. <Grid item xs={8}>
  202. <Typography variant="h4" marginInlineEnd={2}>
  203. {t("Delivery Order")}
  204. </Typography>
  205. </Grid>
  206. <Grid
  207. item
  208. xs={4}
  209. display="flex"
  210. justifyContent="end"
  211. alignItems="end"
  212. >
  213. <Button
  214. name="submit"
  215. variant="contained"
  216. // startIcon={<Check />}
  217. type="submit"
  218. >
  219. {t("Create")}
  220. </Button>
  221. </Grid>
  222. </Grid>
  223. <SearchBox
  224. criteria={searchCriteria}
  225. onSearch={(query) => {
  226. setFilteredDos(
  227. dos.filter((_do) => {
  228. const doOrderDateStr = arrayToDayjs(_do.orderDate);
  229. return (
  230. _do.code.toLowerCase().includes(query.code.toLowerCase()) &&
  231. _do.shopName
  232. .toLowerCase()
  233. .includes(query.shopName.toLowerCase()) &&
  234. (query.status == "All" ||
  235. _do.status
  236. .toLowerCase()
  237. .includes(query.status.toLowerCase())) &&
  238. (isEmpty(query.orderDate) ||
  239. doOrderDateStr.isSame(query.orderDate) ||
  240. doOrderDateStr.isAfter(query.orderDate)) &&
  241. (isEmpty(query.orderDateTo) ||
  242. doOrderDateStr.isSame(query.orderDateTo) ||
  243. doOrderDateStr.isBefore(query.orderDateTo))
  244. );
  245. })
  246. );
  247. }}
  248. onReset={onReset}
  249. />
  250. <StyledDataGrid
  251. checkboxSelection={true}
  252. rows={filteredDos}
  253. columns={columns}
  254. rowSelectionModel={rowSelectionModel}
  255. onRowSelectionModelChange={(newRowSelectionModel) => {
  256. setRowSelectionModel(newRowSelectionModel);
  257. formProps.setValue("ids", newRowSelectionModel)
  258. }}
  259. slots={{
  260. footer: FooterToolbar,
  261. noRowsOverlay: NoRowsOverlay,
  262. }}
  263. />
  264. </Stack>
  265. </FormProvider>
  266. </>
  267. );
  268. };
  269. const FooterToolbar: React.FC<FooterPropsOverrides> = ({ child }) => {
  270. return <GridToolbarContainer sx={{ p: 2 }}>{child}</GridToolbarContainer>;
  271. };
  272. const NoRowsOverlay: React.FC = () => {
  273. const { t } = useTranslation("home");
  274. return (
  275. <Box
  276. display="flex"
  277. justifyContent="center"
  278. alignItems="center"
  279. height="100%"
  280. >
  281. <Typography variant="caption">{t("Add some entries!")}</Typography>
  282. </Box>
  283. );
  284. };
  285. export default DoSearch;