From 93f73b4df9f4ad2f0e62e0d926759eff998c7f50 Mon Sep 17 00:00:00 2001 From: "cyril.tsui" Date: Fri, 3 May 2024 11:16:46 +0800 Subject: [PATCH] update project --- .../(main)/staffReimbursement/create/page.tsx | 4 +- src/app/api/projects/actions.ts | 30 +++++- src/components/ClaimDetail/index.ts | 1 - .../ClaimFormInfo.tsx | 0 .../ClaimFormInputGrid.tsx | 0 .../ClaimSave.tsx} | 22 ++--- .../ClaimSaveWrapper.tsx} | 4 +- src/components/ClaimSave/index.ts | 1 + .../CreateProject/CreateProject.tsx | 94 ++++++++++++++----- src/components/CustomerSave/CustomerSave.tsx | 28 +++--- src/components/Swal/CustomAlerts.js | 6 +- 11 files changed, 133 insertions(+), 57 deletions(-) delete mode 100644 src/components/ClaimDetail/index.ts rename src/components/{ClaimDetail => ClaimSave}/ClaimFormInfo.tsx (100%) rename src/components/{ClaimDetail => ClaimSave}/ClaimFormInputGrid.tsx (100%) rename src/components/{ClaimDetail/ClaimDetail.tsx => ClaimSave/ClaimSave.tsx} (93%) rename src/components/{ClaimDetail/ClaimDetailWrapper.tsx => ClaimSave/ClaimSaveWrapper.tsx} (82%) create mode 100644 src/components/ClaimSave/index.ts diff --git a/src/app/(main)/staffReimbursement/create/page.tsx b/src/app/(main)/staffReimbursement/create/page.tsx index f1effc4..7633135 100644 --- a/src/app/(main)/staffReimbursement/create/page.tsx +++ b/src/app/(main)/staffReimbursement/create/page.tsx @@ -1,4 +1,4 @@ -import ClaimDetail from "@/components/ClaimDetail"; +import ClaimSave from "@/components/ClaimSave"; import { I18nProvider, getServerI18n } from "@/i18n"; import Typography from "@mui/material/Typography"; import { Metadata } from "next"; @@ -14,7 +14,7 @@ const ClaimDetails: React.FC = async () => { <> {t("Create Claim")} - + ); diff --git a/src/app/api/projects/actions.ts b/src/app/api/projects/actions.ts index 121111a..e383e89 100644 --- a/src/app/api/projects/actions.ts +++ b/src/app/api/projects/actions.ts @@ -1,18 +1,22 @@ "use server"; -import { serverFetchJson } from "@/app/utils/fetchUtil"; +import { serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil"; import { BASE_API_URL } from "@/config/api"; import { Task, TaskGroup } from "../tasks"; import { Customer } from "../customer"; import { revalidateTag } from "next/cache"; export interface CreateProjectInputs { - // Project details + // Project + projectId: number | null; + projectDeleted: boolean | null; projectCode: string; projectName: string; projectCategoryId: number; projectDescription: string; projectLeadId: number; + projectActualStart: string; + projectActualEnd: string; // Project info serviceTypeId: number; @@ -62,8 +66,16 @@ export interface PaymentInputs { amount: number; } +export interface CreateProjectResponse { + id: number, + name: string, + code: string, + category: string, + team: string, + client: string, +} export const saveProject = async (data: CreateProjectInputs) => { - const newProject = await serverFetchJson(`${BASE_API_URL}/projects/new`, { + const newProject = await serverFetchJson(`${BASE_API_URL}/projects/new`, { method: "POST", body: JSON.stringify(data), headers: { "Content-Type": "application/json" }, @@ -72,3 +84,15 @@ export const saveProject = async (data: CreateProjectInputs) => { revalidateTag("projects"); return newProject; }; + +export const deleteProject = async (id: number) => { + const project = await serverFetchWithNoContent( + `${BASE_API_URL}/projects/${id}`, + { + method: "DELETE", + headers: { "Content-Type": "application/json" }, + }, + ); + + return project +}; diff --git a/src/components/ClaimDetail/index.ts b/src/components/ClaimDetail/index.ts deleted file mode 100644 index 0fa3ab2..0000000 --- a/src/components/ClaimDetail/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./ClaimDetailWrapper"; diff --git a/src/components/ClaimDetail/ClaimFormInfo.tsx b/src/components/ClaimSave/ClaimFormInfo.tsx similarity index 100% rename from src/components/ClaimDetail/ClaimFormInfo.tsx rename to src/components/ClaimSave/ClaimFormInfo.tsx diff --git a/src/components/ClaimDetail/ClaimFormInputGrid.tsx b/src/components/ClaimSave/ClaimFormInputGrid.tsx similarity index 100% rename from src/components/ClaimDetail/ClaimFormInputGrid.tsx rename to src/components/ClaimSave/ClaimFormInputGrid.tsx diff --git a/src/components/ClaimDetail/ClaimDetail.tsx b/src/components/ClaimSave/ClaimSave.tsx similarity index 93% rename from src/components/ClaimDetail/ClaimDetail.tsx rename to src/components/ClaimSave/ClaimSave.tsx index 54a82a5..336d554 100644 --- a/src/components/ClaimDetail/ClaimDetail.tsx +++ b/src/components/ClaimSave/ClaimSave.tsx @@ -21,7 +21,7 @@ export interface Props { projectCombo: ProjectCombo[] } -const ClaimDetail: React.FC = ({ projectCombo }) => { +const ClaimSave: React.FC = ({ projectCombo }) => { const { t } = useTranslation("common"); const [serverError, setServerError] = useState(""); const router = useRouter(); @@ -74,15 +74,15 @@ const ClaimDetail: React.FC = ({ projectCombo }) => { const buttonName = (event?.nativeEvent as any).submitter.name const formData = new FormData() formData.append("expenseType", data.expenseType) - data.addClaimDetails.forEach((claimDetail) => { - console.log(claimDetail) - formData.append("addClaimDetailIds", JSON.stringify(claimDetail.id)) - formData.append("addClaimDetailInvoiceDates", convertDateToString(claimDetail.invoiceDate, "YYYY-MM-DD")) - formData.append("addClaimDetailProjectIds", JSON.stringify(claimDetail.project)) - formData.append("addClaimDetailDescriptions", claimDetail.description) - formData.append("addClaimDetailAmounts", JSON.stringify(claimDetail.amount)) - formData.append("addClaimDetailNewSupportingDocuments", claimDetail.newSupportingDocument) - formData.append("addClaimDetailOldSupportingDocumentIds", JSON.stringify(claimDetail?.oldSupportingDocument?.id ?? -1)) + data.addClaimDetails.forEach((ClaimSave) => { + console.log(ClaimSave) + formData.append("addClaimDetailIds", JSON.stringify(ClaimSave.id)) + formData.append("addClaimDetailInvoiceDates", convertDateToString(ClaimSave.invoiceDate, "YYYY-MM-DD")) + formData.append("addClaimDetailProjectIds", JSON.stringify(ClaimSave.project)) + formData.append("addClaimDetailDescriptions", ClaimSave.description) + formData.append("addClaimDetailAmounts", JSON.stringify(ClaimSave.amount)) + formData.append("addClaimDetailNewSupportingDocuments", ClaimSave.newSupportingDocument) + formData.append("addClaimDetailOldSupportingDocumentIds", JSON.stringify(ClaimSave?.oldSupportingDocument?.id ?? -1)) }) // for (let i = 0; i < data.addClaimDetails.length; i++) { // const updatedData = { @@ -155,4 +155,4 @@ const ClaimDetail: React.FC = ({ projectCombo }) => { ); }; -export default ClaimDetail; +export default ClaimSave; diff --git a/src/components/ClaimDetail/ClaimDetailWrapper.tsx b/src/components/ClaimSave/ClaimSaveWrapper.tsx similarity index 82% rename from src/components/ClaimDetail/ClaimDetailWrapper.tsx rename to src/components/ClaimSave/ClaimSaveWrapper.tsx index 602f9e3..af6234f 100644 --- a/src/components/ClaimDetail/ClaimDetailWrapper.tsx +++ b/src/components/ClaimSave/ClaimSaveWrapper.tsx @@ -1,6 +1,6 @@ import React from "react"; -import ClaimDetail from "./ClaimDetail"; +import ClaimSave from "./ClaimSave"; import { fetchProjectCombo } from "@/app/api/claims"; // import TaskSetup from "./TaskSetup"; // import StaffAllocation from "./StaffAllocation"; @@ -13,7 +13,7 @@ const ClaimDetailWrapper: React.FC = async () => { ]); return ( - + ); }; diff --git a/src/components/ClaimSave/index.ts b/src/components/ClaimSave/index.ts new file mode 100644 index 0000000..56eabaf --- /dev/null +++ b/src/components/ClaimSave/index.ts @@ -0,0 +1 @@ +export { default } from "./ClaimSaveWrapper"; diff --git a/src/components/CreateProject/CreateProject.tsx b/src/components/CreateProject/CreateProject.tsx index 3a91a8f..fb57dd7 100644 --- a/src/components/CreateProject/CreateProject.tsx +++ b/src/components/CreateProject/CreateProject.tsx @@ -1,5 +1,6 @@ "use client"; +import DoneIcon from '@mui/icons-material/Done' import Check from "@mui/icons-material/Check"; import Close from "@mui/icons-material/Close"; import Button from "@mui/material/Button"; @@ -21,7 +22,7 @@ import { SubmitHandler, useForm, } from "react-hook-form"; -import { CreateProjectInputs, saveProject } from "@/app/api/projects/actions"; +import { CreateProjectInputs, deleteProject, saveProject } from "@/app/api/projects/actions"; import { Delete, Error, PlayArrow } from "@mui/icons-material"; import { BuildingType, @@ -37,6 +38,8 @@ import { Typography } from "@mui/material"; import { Grade } from "@/app/api/grades"; import { Customer, Subsidiary } from "@/app/api/customer"; import { isEmpty } from "lodash"; +import { deleteDialog, errorDialog, submitDialog, successDialog } from "../Swal/CustomAlerts"; +import dayjs from "dayjs"; export interface Props { isEditMode: boolean; @@ -98,6 +101,19 @@ const CreateProject: React.FC = ({ router.replace("/projects"); }; + const handleDelete = () => { + deleteDialog(async () => { + await deleteProject(formProps.getValues("projectId")!!) + + const clickSuccessDialog = await successDialog("Delete Success", t) + + if (clickSuccessDialog) { + router.replace("/projects"); + } + + }, t) + } + const handleTabChange = useCallback>( (_e, newValue) => { setTabIndex(newValue); @@ -106,15 +122,48 @@ const CreateProject: React.FC = ({ ); const onSubmit = useCallback>( - async (data) => { + async (data, event) => { try { + console.log("first") setServerError(""); - if (isEditMode) { - console.log("edit project", data); - } else { - await saveProject(data); + + let title = t("Do you want to submit?") + let confirmButtonText = t("Submit") + let successTitle = t("Submit Success") + let errorTitle = t("Submit Fail") + const buttonName = (event?.nativeEvent as any).submitter.name + + if (buttonName === "start") { + title = t("Do you want to start?") + confirmButtonText = t("Start") + successTitle = t("Start Success") + errorTitle = t("Start Fail") + } else if (buttonName === "complete") { + title = t("Do you want to complete?") + confirmButtonText = t("Complete") + successTitle = t("Complete Success") + errorTitle = t("Complete Fail") } - router.replace("/projects"); + + submitDialog(async () => { + if (buttonName === "start") { + data.projectActualStart = dayjs().format("YYYY-MM-DD") + } else if (buttonName === "complete") { + data.projectActualEnd = dayjs().format("YYYY-MM-DD") + } + + const response = await saveProject(data); + + if (response.id > 0) { + successDialog(successTitle, t).then(() => { + router.replace("/projects"); + }) + } else { + errorDialog(errorTitle, t).then(() => { + return false + }) + } + }, t, { title: title, confirmButtonText: confirmButtonText }) } catch (e) { setServerError(t("An error has occurred. Please try again later.")); } @@ -147,9 +196,9 @@ const CreateProject: React.FC = ({ // manhourPercentageByGrade should have a sensible default manhourPercentageByGrade: isEmpty(defaultInputs?.manhourPercentageByGrade) ? grades.reduce((acc, grade) => { - return { ...acc, [grade.id]: 1 / grades.length }; - }, {}) - : defaultInputs.manhourPercentageByGrade, + return { ...acc, [grade.id]: 1 / grades.length }; + }, {}) + : defaultInputs?.manhourPercentageByGrade, }, }); @@ -157,22 +206,25 @@ const CreateProject: React.FC = ({ return ( <> - {isEditMode && ( - - - - - )} + {isEditMode && !(formProps.getValues("projectDeleted") === true) && ( + + {!formProps.getValues("projectActualStart") && } + {formProps.getValues("projectActualStart") && !formProps.getValues("projectActualEnd") && } + {!(formProps.getValues("projectActualStart") && formProps.getValues("projectActualEnd")) && } + + )} = ({ > {t("Cancel")} - diff --git a/src/components/CustomerSave/CustomerSave.tsx b/src/components/CustomerSave/CustomerSave.tsx index fc2469e..acb4ecf 100644 --- a/src/components/CustomerSave/CustomerSave.tsx +++ b/src/components/CustomerSave/CustomerSave.tsx @@ -199,20 +199,20 @@ const CustomerSave: React.FC = ({ setServerError(""); submitDialog(async () => { - const response = await saveCustomer(data); - - if (response.message === "Success") { - successDialog(t("Submit Success"), t).then(() => { - router.replace("/settings/customer"); - }) - } else { - errorDialog(t("Submit Fail"), t).then(() => { - formProps.setError("code", { message: response.message, type: "custom" }) - setTabIndex(0) - return false - }) - } - }, t) + const response = await saveCustomer(data); + + if (response.message === "Success") { + successDialog(t("Submit Success"), t).then(() => { + router.replace("/settings/customer"); + }) + } else { + errorDialog(t("Submit Fail"), t).then(() => { + formProps.setError("code", { message: response.message, type: "custom" }) + setTabIndex(0) + return false + }) + } + }, t) } catch (e) { console.log(e) setServerError(t("An error has occurred. Please try again later.")); diff --git a/src/components/Swal/CustomAlerts.js b/src/components/Swal/CustomAlerts.js index 6eddfb2..668502c 100644 --- a/src/components/Swal/CustomAlerts.js +++ b/src/components/Swal/CustomAlerts.js @@ -50,13 +50,13 @@ export const warningDialog = (text, t) => { }) } -export const submitDialog = async (confirmAction, t) => { +export const submitDialog = async (confirmAction, t, {...props}) => { // const { t } = useTranslation("common") const result = await Swal.fire({ icon: "question", - title: t("Do you want to submit?"), + title: props.title ?? t("Do you want to submit?"), cancelButtonText: t("Cancel"), - confirmButtonText: t("Submit"), + confirmButtonText: props.confirmButtonText ?? t("Submit"), showCancelButton: true, showConfirmButton: true, });