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.
 
 

81 regels
3.7 KiB

  1. "use client";
  2. import React, { useMemo } from "react";
  3. import SearchBox, { Criterion } from "../SearchBox";
  4. import { useTranslation } from "react-i18next";
  5. import { ProjectPotentialDelayReportFilter } from "@/app/api/reports";
  6. import { fetchProjectPotentialDelayReport } from "@/app/api/reports/actions";
  7. import { downloadFile } from "@/app/utils/commonUtil";
  8. import { TeamResult } from "@/app/api/team";
  9. import { Customer } from "@/app/api/customer";
  10. interface Props {
  11. teams: TeamResult[];
  12. clients: Customer[];
  13. }
  14. type SearchQuery = Partial<Omit<ProjectPotentialDelayReportFilter, "id">>;
  15. type SearchParamNames = keyof SearchQuery;
  16. const GenerateProjectPotentialDelayReport: React.FC<Props> = ({ teams, clients }) => {
  17. const { t } = useTranslation("report");
  18. const teamCombo = teams.map(team => `${team.code} - ${team.name}`)
  19. const clientCombo = clients.map(client => `${client.code} - ${client.name}`)
  20. const [errors, setErrors] = React.useState({
  21. numberOfDays: false,
  22. projectCompletion: false,
  23. })
  24. const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
  25. () => [
  26. { label: t("Team"), paramName: "team", type: "select", options: teamCombo },
  27. { label: t("Client"), paramName: "client", type: "select", options: clientCombo },
  28. { label: t("Number Of Days"), paramName: "numberOfDays", type: "text", textType: "number", error: errors.numberOfDays, helperText: t("Can not be null and decimal, and should be >= 0") },
  29. { label: t("Project Completion (<= %)"), paramName: "projectCompletion", type: "text", textType: "number", error: errors.projectCompletion, helperText: t("Can not be null and decimal, and should be in range of 0 - 100") },
  30. ],
  31. [t, errors],
  32. );
  33. return (
  34. <>
  35. <SearchBox
  36. criteria={searchCriteria}
  37. onSearch={async (query) => {
  38. let hasError = false
  39. if (query.numberOfDays.length === 0 || !Number.isInteger(parseFloat(query.numberOfDays)) || parseInt(query.numberOfDays) < 0) {
  40. setErrors((prev) => ({...prev, numberOfDays: true}))
  41. hasError = true
  42. } else {
  43. setErrors((prev) => ({...prev, numberOfDays: false}))
  44. }
  45. if (query.projectCompletion.length === 0 || !Number.isInteger(parseFloat(query.projectCompletion)) || parseInt(query.projectCompletion) < 0 || parseInt(query.projectCompletion) > 100) {
  46. setErrors((prev) => ({...prev, projectCompletion: true}))
  47. hasError = true
  48. } else {
  49. setErrors((prev) => ({...prev, projectCompletion: false}))
  50. }
  51. if (hasError) return false
  52. const teamIndex = teamCombo.findIndex(team => team === query.team)
  53. const clientIndex = clientCombo.findIndex(client => client === query.client)
  54. const response = await fetchProjectPotentialDelayReport({
  55. teamId: teams[teamIndex]?.id ?? "All",
  56. clientId: clients[clientIndex]?.id ?? "All",
  57. numberOfDays: parseInt(query.numberOfDays),
  58. projectCompletion: parseInt(query.projectCompletion)
  59. })
  60. if (response) {
  61. downloadFile(new Uint8Array(response.blobValue), response.filename!!)
  62. }
  63. }}
  64. formType={"download"}
  65. />
  66. </>
  67. );
  68. };
  69. export default GenerateProjectPotentialDelayReport;