Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 

255 rindas
7.9 KiB

  1. "use client";
  2. import { ProjectCategory, ProjectResult } from "@/app/api/projects";
  3. import React, { useCallback, useEffect, useMemo, useState } from "react";
  4. import SearchBox, { Criterion } from "../SearchBox";
  5. import { useTranslation } from "react-i18next";
  6. import SearchResults, { Column } from "../SearchResults";
  7. import EditNote from "@mui/icons-material/EditNote";
  8. import uniq from "lodash/uniq";
  9. import { useRouter, useSearchParams } from "next/navigation";
  10. import { MAINTAIN_PROJECT } from "@/middleware";
  11. import { reverse, uniqBy } from "lodash";
  12. import { loadDrafts } from "@/app/utils/draftUtils";
  13. import { TeamResult } from "@/app/api/team";
  14. import { Customer } from "@/app/api/customer";
  15. import ContentCopyIcon from '@mui/icons-material/ContentCopy';
  16. import PlayCircleOutlineIcon from '@mui/icons-material/PlayCircleOutline';
  17. type ProjectResultOrDraft = ProjectResult & { isDraft?: boolean };
  18. interface Props {
  19. projects: ProjectResult[];
  20. projectCategories: ProjectCategory[];
  21. abilities: string[];
  22. teams: TeamResult[];
  23. customers: Customer[];
  24. }
  25. type SearchQuery = Partial<Omit<ProjectResult, "id">>;
  26. type SearchParamNames = keyof SearchQuery;
  27. const ProjectSearch: React.FC<Props> = ({
  28. projects,
  29. projectCategories,
  30. abilities,
  31. teams,
  32. customers,
  33. }) => {
  34. const router = useRouter();
  35. const { t } = useTranslation("projects");
  36. const [draftProjects, setDraftProjects] = useState<ProjectResultOrDraft[]>(
  37. [],
  38. );
  39. useEffect(() => {
  40. const drafts = reverse(loadDrafts());
  41. setDraftProjects(
  42. drafts.map(([id, inputs]) => {
  43. const team = teams.find(
  44. (team) => team.teamLead === inputs.projectLeadId,
  45. );
  46. return {
  47. isDraft: true,
  48. id: parseInt(id),
  49. code: inputs.projectCode || "",
  50. name: inputs.projectName || t("Draft Project"),
  51. category:
  52. projectCategories.find((cat) => cat.id === inputs.projectCategoryId)
  53. ?.name || "",
  54. team: team?.code || "",
  55. client:
  56. customers.find((customer) => customer.id === inputs.clientId)
  57. ?.name || "",
  58. status: t("Draft"),
  59. teamCodeName: team?.code || "",
  60. teamId: team?.teamId || 0,
  61. mainProject: "",
  62. };
  63. }),
  64. );
  65. }, [projectCategories, t, teams, customers]);
  66. const [filteredProjects, setFilteredProjects] = useState(projects);
  67. const draftAndFilterdProjects = useMemo<ProjectResultOrDraft[]>(
  68. () => [...draftProjects, ...filteredProjects],
  69. [draftProjects, filteredProjects],
  70. );
  71. const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
  72. () => [
  73. { label: t("Project Code"), paramName: "code", type: "text" },
  74. { label: t("Project Name"), paramName: "name", type: "text" },
  75. {
  76. label: t("Client Name"),
  77. paramName: "client",
  78. type: "autocomplete",
  79. options: uniqBy(
  80. projects.map((project) => ({
  81. value: project.client,
  82. label: project.client,
  83. })),
  84. "value",
  85. ).sort((a, b) => (a.value >= b.value ? 1 : -1)),
  86. },
  87. {
  88. label: t("Project Category"),
  89. paramName: "category",
  90. type: "select",
  91. options: projectCategories.map((category) => category.name),
  92. },
  93. {
  94. label: t("Team"),
  95. paramName: "team",
  96. type: "select",
  97. options: uniq(projects.map((project) => project.teamCodeName)),
  98. },
  99. {
  100. label: t("Status"),
  101. paramName: "status",
  102. type: "select",
  103. options: uniq(projects.map((project) => project.status)),
  104. },
  105. ],
  106. [t, projectCategories, projects],
  107. );
  108. const onReset = useCallback(() => {
  109. setFilteredProjects(projects);
  110. }, [projects]);
  111. const onProjectClick = useCallback(
  112. (project: ProjectResultOrDraft) => {
  113. if (project.isDraft && project.id) {
  114. router.push(`/projects/create?draftId=${project.id}`);
  115. } else if (Boolean(project.mainProject)) {
  116. router.push(`/projects/editSub?id=${project.id}`);
  117. } else router.push(`/projects/edit?id=${project.id}`);
  118. },
  119. [router],
  120. );
  121. const onProjectCopyClick = useCallback(
  122. (project: ProjectResultOrDraft) => {
  123. if (!project.isDraft) {
  124. if (Boolean(project.mainProject)) {
  125. router.push(`/projects/copySub?id=${project.id}`);
  126. } else router.push(`/projects/copy?id=${project.id}`);
  127. }
  128. },
  129. [router],
  130. );
  131. const onProjectStatusClick = useCallback(
  132. (project: ProjectResultOrDraft) => {
  133. const status = project.status.toLocaleLowerCase()
  134. console.log(status)
  135. if (status && statusList.includes(status)) {
  136. /* switch (status) {
  137. case "pending to start":
  138. router.push(`/projects/edit?id=${project.id}&autoClick=start`);
  139. break;
  140. case "on-going":
  141. router.push(`/projects/edit?id=${project.id}&autoClick=complete`);
  142. break;
  143. case "completed":
  144. router.push(`/projects/edit?id=${project.id}&autoClick=reopen`);
  145. break;
  146. } */
  147. router.push(`/projects/edit?id=${project.id}&autoClick=true`);
  148. }
  149. },
  150. [router],
  151. );
  152. const statusList = ["pending to start", "on-going","completed"]
  153. const ignoreStatusList = ["draft", "deleted"]
  154. const columns = useMemo<Column<ProjectResult>[]>(
  155. () => [
  156. {
  157. name: "id",
  158. label: t("Details"),
  159. onClick: onProjectClick,
  160. buttonIcon: <EditNote />,
  161. disabled: !abilities.includes(MAINTAIN_PROJECT),
  162. },
  163. {
  164. name: "id",
  165. label: t("Copy"),
  166. onClick: onProjectCopyClick,
  167. buttonIcon: <ContentCopyIcon />,
  168. disabled: !abilities.includes(MAINTAIN_PROJECT),
  169. disabledRows: {
  170. status: ["Draft"]
  171. }
  172. },
  173. { name: "code", label: t("Project Code") },
  174. { name: "name", label: t("Project Name") },
  175. { name: "category", label: t("Project Category") },
  176. { name: "team", label: t("Team") },
  177. { name: "client", label: t("Client") },
  178. {
  179. name: "status",
  180. label: t("Status"),
  181. // type: "link",
  182. // onClick: onProjectStatusClick,
  183. // underlines: ignoreStatusList.reduce((acc, cur) => ({...acc, [cur]: "none"}), {}),
  184. // colors: ignoreStatusList.reduce((acc, cur) => ({...acc, [cur]: "inherit"}), {}),
  185. },
  186. // {
  187. // name: "status",
  188. // label: t("Status"),
  189. // type: "button",
  190. // onClick: onProjectStatusClick,
  191. // variants: ignoreStatusList.reduce((acc, cur) => ({...acc, [cur]: "text"}), {}),
  192. // colors: ignoreStatusList.reduce((acc, cur) => ({...acc, [cur]: "inherit"}), {}),
  193. // }
  194. {
  195. name: "status",
  196. label: t(""),
  197. onClick: onProjectStatusClick,
  198. buttonIcon: <PlayCircleOutlineIcon />,
  199. disabled: !abilities.includes(MAINTAIN_PROJECT),
  200. disabledRows: {
  201. status: ignoreStatusList
  202. }
  203. },
  204. ],
  205. [t, onProjectClick],
  206. );
  207. return (
  208. <>
  209. <SearchBox
  210. criteria={searchCriteria}
  211. onSearch={(query) => {
  212. setFilteredProjects(
  213. projects.filter(
  214. (p) =>
  215. p.code.toLowerCase().includes(query.code.toLowerCase()) &&
  216. p.name.toLowerCase().includes(query.name.toLowerCase()) &&
  217. (query.client === "All" || p.client === query.client) &&
  218. (query.category === "All" || p.category === query.category) &&
  219. // (query.team === "All" || p.team === query.team) &&
  220. (query.team === "All" ||
  221. query.team.toLowerCase().includes(p.team.toLowerCase())) &&
  222. (query.status === "All" || p.status === query.status),
  223. ),
  224. );
  225. }}
  226. onReset={onReset}
  227. />
  228. <SearchResults<ProjectResult>
  229. items={draftAndFilterdProjects}
  230. columns={columns}
  231. />
  232. </>
  233. );
  234. };
  235. export default ProjectSearch;