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.
 
 

159 line
7.6 KiB

  1. "use client";
  2. import Check from "@mui/icons-material/Check";
  3. import Close from "@mui/icons-material/Close";
  4. import Button from "@mui/material/Button";
  5. import Stack from "@mui/material/Stack";
  6. import { useRouter } from "next/navigation";
  7. import React, { useCallback, useState } from "react";
  8. import { useTranslation } from "react-i18next";
  9. import ClaimFormInfo from "./ClaimFormInfo";
  10. import { ProjectCombo } from "@/app/api/claims";
  11. import { Typography } from "@mui/material";
  12. import { FormProvider, SubmitErrorHandler, SubmitHandler, useForm } from "react-hook-form";
  13. import { ClaimInputFormByStaff, saveClaim } from "@/app/api/claims/actions";
  14. import { DoneAll } from "@mui/icons-material";
  15. import { expenseTypeCombo } from "@/app/utils/comboUtil";
  16. import { convertDateToString } from "@/app/utils/formatUtil";
  17. import { errorDialog, submitDialog, successDialog, warningDialog } from "../Swal/CustomAlerts";
  18. export interface Props {
  19. projectCombo: ProjectCombo[]
  20. }
  21. const ClaimDetail: React.FC<Props> = ({ projectCombo }) => {
  22. const { t } = useTranslation("common");
  23. const [serverError, setServerError] = useState("");
  24. const router = useRouter();
  25. const formProps = useForm<ClaimInputFormByStaff>({
  26. defaultValues: {
  27. id: null,
  28. expenseType: expenseTypeCombo[0],
  29. addClaimDetails: []
  30. },
  31. });
  32. const handleCancel = () => {
  33. router.back();
  34. };
  35. const onSubmit = useCallback<SubmitHandler<ClaimInputFormByStaff>>(
  36. async (data, event) => {
  37. try {
  38. if (data.isGridEditing) {
  39. warningDialog(t("Please save all the rows before submitting"), t)
  40. return false
  41. }
  42. let haveError = false
  43. if (data.addClaimDetails.length === 0 || data.addClaimDetails.filter(row => String(row.description).trim().length === 0 || String(row.amount).trim().length === 0 || row.project === null || row.project === undefined || ((row.oldSupportingDocument === null || row.oldSupportingDocument === undefined) && (row.newSupportingDocument === null || row.newSupportingDocument === undefined))).length > 0) {
  44. haveError = true
  45. formProps.setError("addClaimDetails", { message: "Claim details include empty fields", type: "required" })
  46. }
  47. if (data.addClaimDetails.length > 0 && data.addClaimDetails.filter(row => row.invoiceDate.getTime() > new Date().getTime()).length > 0) {
  48. haveError = true
  49. formProps.setError("addClaimDetails", { message: "Claim details include invalid invoice date", type: "invalid_date" })
  50. }
  51. if (data.addClaimDetails.length > 0 && data.addClaimDetails.filter(row => row.project === null || row.project === undefined).length > 0) {
  52. haveError = true
  53. formProps.setError("addClaimDetails", { message: "Claim details include empty project", type: "invalid_project" })
  54. }
  55. if (data.addClaimDetails.length > 0 && data.addClaimDetails.filter(row => row.amount <= 0).length > 0) {
  56. haveError = true
  57. formProps.setError("addClaimDetails", { message: "Claim details include invalid amount", type: "invalid_amount" })
  58. }
  59. if (haveError) {
  60. return false
  61. }
  62. const buttonName = (event?.nativeEvent as any).submitter.name
  63. const formData = new FormData()
  64. formData.append("expenseType", data.expenseType)
  65. data.addClaimDetails.forEach((claimDetail) => {
  66. console.log(claimDetail)
  67. formData.append("addClaimDetailIds", JSON.stringify(claimDetail.id))
  68. formData.append("addClaimDetailInvoiceDates", convertDateToString(claimDetail.invoiceDate, "YYYY-MM-DD"))
  69. formData.append("addClaimDetailProjectIds", JSON.stringify(claimDetail.project))
  70. formData.append("addClaimDetailDescriptions", claimDetail.description)
  71. formData.append("addClaimDetailAmounts", JSON.stringify(claimDetail.amount))
  72. formData.append("addClaimDetailNewSupportingDocuments", claimDetail.newSupportingDocument)
  73. formData.append("addClaimDetailOldSupportingDocumentIds", JSON.stringify(claimDetail?.oldSupportingDocument?.id ?? -1))
  74. })
  75. // for (let i = 0; i < data.addClaimDetails.length; i++) {
  76. // const updatedData = {
  77. // id: data.addClaimDetails[i].id,
  78. // // project: data.addClaimDetails[i].project,
  79. // invoiceDate: convertDateToString(data.addClaimDetails[i].invoiceDate, "YYYY-MM-DD"),
  80. // description: data.addClaimDetails[i].description,
  81. // amount:data.addClaimDetails[i].amount,
  82. // // oldSupportingDocument: data.addClaimDetails[i].oldSupportingDocument,
  83. // }
  84. // formData.append("addClaimDetails", JSON.stringify(updatedData))
  85. // formData.append("addClaimDetailsFiles", data.addClaimDetails[i].newSupportingDocument)
  86. // formData.append("testFiles", data.addClaimDetails[i].newSupportingDocument)
  87. // }
  88. if (buttonName === "submit") {
  89. formData.append("status", "Waiting for Approval")
  90. } else if (buttonName === "save") {
  91. formData.append("status", "Not Submitted")
  92. }
  93. formData.append("id", "-1")
  94. setServerError("");
  95. submitDialog(async () => {
  96. const response = await saveClaim(formData);
  97. if (response.message === "Success") {
  98. successDialog(t("Submit Success"), t).then(() => {
  99. router.replace("/staffReimbursement");
  100. })
  101. }
  102. }, t)
  103. } catch (e) {
  104. setServerError(t("An error has occurred. Please try again later."));
  105. }
  106. },
  107. [router, t],
  108. );
  109. const onSubmitError = useCallback<SubmitErrorHandler<ClaimInputFormByStaff>>(
  110. (errors) => {
  111. // Set the tab so that the focus will go there
  112. console.log(errors)
  113. },
  114. [],
  115. );
  116. return (
  117. <FormProvider {...formProps}>
  118. <Stack spacing={2} component={"form"} onSubmit={formProps.handleSubmit(onSubmit, onSubmitError)}>
  119. <ClaimFormInfo projectCombo={projectCombo} />
  120. {serverError && (
  121. <Typography variant="body2" color="error" alignSelf="flex-end">
  122. {serverError}
  123. </Typography>
  124. )}
  125. <Stack direction="row" justifyContent="flex-end" gap={1}>
  126. <Button variant="text" startIcon={<Close />} onClick={handleCancel}>
  127. {t("Cancel")}
  128. </Button>
  129. <Button variant="outlined" name="save" startIcon={<Check />} type="submit" disabled={Boolean(formProps.watch("isGridEditing"))}>
  130. {t("Save")}
  131. </Button>
  132. <Button variant="contained" name="submit" startIcon={<DoneAll />} type="submit" disabled={Boolean(formProps.watch("isGridEditing"))}>
  133. {t("Submit")}
  134. </Button>
  135. </Stack>
  136. </Stack>
  137. </FormProvider>
  138. );
  139. };
  140. export default ClaimDetail;