| @@ -16,7 +16,6 @@ import TaskSetup from "./TaskSetup"; | |||
| import StaffAllocation from "./StaffAllocation"; | |||
| import Milestone from "./Milestone"; | |||
| import { Task, TaskTemplate } from "@/app/api/tasks"; | |||
| import AssignIcon from '@mui/icons-material/AssignmentIndOutlined'; | |||
| import { | |||
| FieldErrors, | |||
| FormProvider, | |||
| @@ -54,6 +53,7 @@ import { | |||
| } from "../Swal/CustomAlerts"; | |||
| import dayjs from "dayjs"; | |||
| import { DELETE_PROJECT } from "@/middleware"; | |||
| import { OUTPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; | |||
| export interface Props { | |||
| isEditMode: boolean; | |||
| @@ -137,8 +137,8 @@ const CreateProject: React.FC<Props> = ({ | |||
| title: t("Do you want to submit?"), | |||
| confirmButtonText: t("Submit"), | |||
| successTitle: t("Submit Success"), | |||
| errorTitle: t("Submit Fail") | |||
| } | |||
| errorTitle: t("Submit Fail"), | |||
| }; | |||
| const [buttonData, setButtonData] = useState<{ | |||
| buttonName: string; | |||
| title: string; | |||
| @@ -147,26 +147,23 @@ const CreateProject: React.FC<Props> = ({ | |||
| errorTitle: string; | |||
| buttonText: string; | |||
| buttonIcon: any; | |||
| buttonColor: any | |||
| }> ({ | |||
| buttonColor: any; | |||
| }>({ | |||
| ...defaultBtn, | |||
| buttonText: t("Submit Project"), | |||
| buttonIcon: <Check />, | |||
| buttonColor : "success" | |||
| }) | |||
| buttonColor: "success", | |||
| }); | |||
| const disableChecking = () => { | |||
| return (loading || | |||
| formProps.getValues("projectDeleted") === true || | |||
| formProps.getValues("projectStatus")?.toLowerCase() === | |||
| "deleted" || | |||
| // !!formProps.getValues("projectActualStart") && | |||
| !!( | |||
| formProps.getValues("projectStatus")?.toLowerCase() === | |||
| "completed" | |||
| )) | |||
| } | |||
| return ( | |||
| loading || | |||
| formProps.getValues("projectDeleted") === true || | |||
| formProps.getValues("projectStatus")?.toLowerCase() === "deleted" || | |||
| // !!formProps.getValues("projectActualStart") && | |||
| !!(formProps.getValues("projectStatus")?.toLowerCase() === "completed") | |||
| ); | |||
| }; | |||
| const handleCancel = () => { | |||
| router.replace("/projects"); | |||
| @@ -200,7 +197,11 @@ const CreateProject: React.FC<Props> = ({ | |||
| let hasErrors = false; | |||
| // Tab - Staff Allocation and Resource | |||
| if (data.totalManhour === null || data.totalManhour <= 0 || Number.isNaN(data.totalManhour)) { | |||
| if ( | |||
| data.totalManhour === null || | |||
| data.totalManhour <= 0 || | |||
| Number.isNaN(data.totalManhour) | |||
| ) { | |||
| formProps.setError("totalManhour", { | |||
| message: "totalManhour value is not valid", | |||
| type: "required", | |||
| @@ -209,7 +210,11 @@ const CreateProject: React.FC<Props> = ({ | |||
| hasErrors = true; | |||
| } | |||
| if (data.ratePerManhour === null || data.ratePerManhour <= 0 || Number.isNaN(data.ratePerManhour)) { | |||
| if ( | |||
| data.ratePerManhour === null || | |||
| data.ratePerManhour <= 0 || | |||
| Number.isNaN(data.ratePerManhour) | |||
| ) { | |||
| formProps.setError("ratePerManhour", { | |||
| message: "ratePerManhour value is not valid", | |||
| type: "required", | |||
| @@ -316,17 +321,28 @@ const CreateProject: React.FC<Props> = ({ | |||
| data.taskTemplateId = | |||
| data.taskTemplateId === "All" ? undefined : data.taskTemplateId; | |||
| const response = await saveProject(data); | |||
| if ( | |||
| response.id > 0 && | |||
| response.message?.toLowerCase() === "success" && | |||
| response.errorPosition === null | |||
| ) { | |||
| successDialog(buttonName==="submit"? defaultBtn.successTitle : buttonData.successTitle, t).then(() => { | |||
| successDialog( | |||
| buttonName === "submit" | |||
| ? defaultBtn.successTitle | |||
| : buttonData.successTitle, | |||
| t, | |||
| ).then(() => { | |||
| router.replace("/projects"); | |||
| }); | |||
| } else { | |||
| errorDialog(response.message ?? (buttonName==="submit"? defaultBtn.errorTitle : buttonData.errorTitle), t).then(() => { | |||
| errorDialog( | |||
| response.message ?? | |||
| (buttonName === "submit" | |||
| ? defaultBtn.errorTitle | |||
| : buttonData.errorTitle), | |||
| t, | |||
| ).then(() => { | |||
| if ( | |||
| response.errorPosition !== null && | |||
| response.errorPosition === "projectCode" | |||
| @@ -337,34 +353,29 @@ const CreateProject: React.FC<Props> = ({ | |||
| }); | |||
| setTabIndex(0); | |||
| } | |||
| return false; | |||
| }); | |||
| } | |||
| } | |||
| }; | |||
| if (buttonName === "complete") { | |||
| submitDialogWithWarning( | |||
| handleSubmit, | |||
| t, | |||
| { title: buttonData.title, | |||
| confirmButtonText: buttonData.confirmButtonText, | |||
| text: "<b style='color:red'>Completing project will restrict any further changes to the project, are you sure to proceed?</b>" | |||
| },) | |||
| submitDialogWithWarning(handleSubmit, t, { | |||
| title: buttonData.title, | |||
| confirmButtonText: buttonData.confirmButtonText, | |||
| text: "<b style='color:red'>Completing project will restrict any further changes to the project, are you sure to proceed?</b>", | |||
| }); | |||
| } else if (buttonName === "submit") { | |||
| submitDialog( | |||
| handleSubmit, | |||
| t, | |||
| { title: defaultBtn.title, confirmButtonText: defaultBtn.confirmButtonText }, | |||
| ); | |||
| submitDialog(handleSubmit, t, { | |||
| title: defaultBtn.title, | |||
| confirmButtonText: defaultBtn.confirmButtonText, | |||
| }); | |||
| } else { | |||
| submitDialog( | |||
| handleSubmit, | |||
| t, | |||
| { title: buttonData.title, confirmButtonText: buttonData.confirmButtonText }, | |||
| ); | |||
| submitDialog(handleSubmit, t, { | |||
| title: buttonData.title, | |||
| confirmButtonText: buttonData.confirmButtonText, | |||
| }); | |||
| } | |||
| } catch (e) { | |||
| setServerError(t("An error has occurred. Please try again later.")); | |||
| } | |||
| @@ -432,77 +443,86 @@ const CreateProject: React.FC<Props> = ({ | |||
| const errors = formProps.formState.errors; | |||
| // auto calculate the total project manhour | |||
| const expectedProjectFee = formProps.watch("expectedProjectFee") | |||
| const ratePerManhour = formProps.watch("ratePerManhour") | |||
| const totalManhour = formProps.watch("totalManhour") | |||
| const [firstLoaded, setFirstLoaded] = useState(false) | |||
| const expectedProjectFee = formProps.watch("expectedProjectFee"); | |||
| const ratePerManhour = formProps.watch("ratePerManhour"); | |||
| const totalManhour = formProps.watch("totalManhour"); | |||
| const [firstLoaded, setFirstLoaded] = useState(false); | |||
| React.useMemo(() => { | |||
| if ((firstLoaded && expectedProjectFee > 0 && ratePerManhour > 0)) { | |||
| console.log(ratePerManhour, formProps.watch("totalManhour")) | |||
| formProps.setValue("totalManhour", Math.ceil(expectedProjectFee / ratePerManhour)) | |||
| if (firstLoaded && expectedProjectFee > 0 && ratePerManhour > 0) { | |||
| console.log(ratePerManhour, formProps.watch("totalManhour")); | |||
| formProps.setValue( | |||
| "totalManhour", | |||
| Math.ceil(expectedProjectFee / ratePerManhour), | |||
| ); | |||
| } else { | |||
| setFirstLoaded(true) | |||
| setFirstLoaded(true); | |||
| } | |||
| }, [expectedProjectFee, ratePerManhour]) | |||
| }, [expectedProjectFee, ratePerManhour]); | |||
| React.useMemo(() => { | |||
| if ((expectedProjectFee > 0 && ratePerManhour > 0) && (totalManhour === null || Number.isNaN(totalManhour) || totalManhour <= 0)) { | |||
| formProps.setValue("totalManhour", Math.ceil(expectedProjectFee / ratePerManhour)) | |||
| if ( | |||
| expectedProjectFee > 0 && | |||
| ratePerManhour > 0 && | |||
| (totalManhour === null || Number.isNaN(totalManhour) || totalManhour <= 0) | |||
| ) { | |||
| formProps.setValue( | |||
| "totalManhour", | |||
| Math.ceil(expectedProjectFee / ratePerManhour), | |||
| ); | |||
| } | |||
| }, [totalManhour]) | |||
| }, [totalManhour]); | |||
| const updateButtonData = () => { | |||
| const status = formProps.getValues("projectStatus")?.toLowerCase(); | |||
| //Button Parameters// | |||
| switch (status) { | |||
| case "pending to start" : | |||
| case "pending to start": | |||
| setButtonData({ | |||
| buttonName: "start", | |||
| title : t("Do you want to start?"), | |||
| confirmButtonText : t("Start"), | |||
| successTitle : t("Start Success"), | |||
| errorTitle : t("Start Fail"), | |||
| buttonText : t("Start Project"), | |||
| buttonIcon : <PlayArrow />, | |||
| buttonColor: "success" | |||
| }) | |||
| title: t("Do you want to start?"), | |||
| confirmButtonText: t("Start"), | |||
| successTitle: t("Start Success"), | |||
| errorTitle: t("Start Fail"), | |||
| buttonText: t("Start Project"), | |||
| buttonIcon: <PlayArrow />, | |||
| buttonColor: "success", | |||
| }); | |||
| break; | |||
| case "on-going" : | |||
| case "on-going": | |||
| setButtonData({ | |||
| buttonName: "complete", | |||
| title : t("Do you want to complete?"), | |||
| confirmButtonText : t("Complete"), | |||
| successTitle : t("Complete Success"), | |||
| errorTitle : t("Complete Fail"), | |||
| buttonText : t("Complete Project"), | |||
| buttonIcon : <DoneIcon />, | |||
| buttonColor: "info" | |||
| }) | |||
| title: t("Do you want to complete?"), | |||
| confirmButtonText: t("Complete"), | |||
| successTitle: t("Complete Success"), | |||
| errorTitle: t("Complete Fail"), | |||
| buttonText: t("Complete Project"), | |||
| buttonIcon: <DoneIcon />, | |||
| buttonColor: "info", | |||
| }); | |||
| break; | |||
| case "completed" : | |||
| case "completed": | |||
| setButtonData({ | |||
| buttonName: "reopen", | |||
| title : t("Do you want to reopen?"), | |||
| confirmButtonText : t("Reopen"), | |||
| successTitle : t("Reopen Success"), | |||
| errorTitle : t("Reopen Fail"), | |||
| buttonText : t("Reopen Project"), | |||
| buttonIcon : <AutorenewIcon />, | |||
| buttonColor: "secondary" | |||
| }) | |||
| title: t("Do you want to reopen?"), | |||
| confirmButtonText: t("Reopen"), | |||
| successTitle: t("Reopen Success"), | |||
| errorTitle: t("Reopen Fail"), | |||
| buttonText: t("Reopen Project"), | |||
| buttonIcon: <AutorenewIcon />, | |||
| buttonColor: "secondary", | |||
| }); | |||
| } | |||
| } | |||
| }; | |||
| useEffect(() => { | |||
| if (!isEditMode) { | |||
| setLoading(false); | |||
| } | |||
| else if (formProps?.getValues("projectName")) { | |||
| } else if (formProps?.getValues("projectName")) { | |||
| setLoading(false); | |||
| updateButtonData(); | |||
| }}, [formProps] | |||
| ) | |||
| } | |||
| }, [formProps]); | |||
| return ( | |||
| <> | |||
| @@ -512,43 +532,70 @@ const CreateProject: React.FC<Props> = ({ | |||
| component="form" | |||
| onSubmit={formProps.handleSubmit(onSubmit, onSubmitError)} | |||
| > | |||
| {isEditMode && !(formProps.getValues("projectDeleted") === true) && !loading && ( | |||
| <Grid> | |||
| <Typography mb={2} variant="h4">{t("Edit Project")}: {`<${defaultInputs?.projectCode}>`}</Typography> | |||
| <Stack direction="row" gap={1}> | |||
| {/* {!formProps.getValues("projectActualStart") && ( */} | |||
| <Button | |||
| name={buttonData.buttonName} | |||
| type="submit" | |||
| variant="contained" | |||
| startIcon={buttonData.buttonIcon} | |||
| color={buttonData.buttonColor} | |||
| > | |||
| {t(buttonData.buttonText)} | |||
| </Button> | |||
| {!( | |||
| // formProps.getValues("projectActualStart") && | |||
| // formProps.getValues("projectActualEnd") | |||
| ( | |||
| formProps.getValues("projectStatus")?.toLowerCase() === | |||
| "completed" || | |||
| formProps.getValues("projectStatus")?.toLowerCase() === | |||
| "deleted" | |||
| ) | |||
| ) && | |||
| abilities.includes(DELETE_PROJECT) && ( | |||
| {isEditMode && | |||
| !(formProps.getValues("projectDeleted") === true) && | |||
| !loading && ( | |||
| <Grid> | |||
| <Typography mb={2} variant="h4"> | |||
| {t("Edit Project")}: {`<${defaultInputs?.projectCode}>`} | |||
| </Typography> | |||
| {(defaultInputs?.projectActualEnd || | |||
| defaultInputs?.projectActualStart) && ( | |||
| <Stack mb={2}> | |||
| {defaultInputs?.projectActualStart && ( | |||
| <Typography variant="caption"> | |||
| {t("Project Start Date: {{date}}", { | |||
| date: dayjs(defaultInputs.projectActualStart).format( | |||
| OUTPUT_DATE_FORMAT, | |||
| ), | |||
| })} | |||
| </Typography> | |||
| )} | |||
| {defaultInputs?.projectActualEnd && ( | |||
| <Typography variant="caption"> | |||
| {t("Project End Date: {{date}}", { | |||
| date: dayjs(defaultInputs.projectActualEnd).format( | |||
| OUTPUT_DATE_FORMAT, | |||
| ), | |||
| })} | |||
| </Typography> | |||
| )} | |||
| </Stack> | |||
| )} | |||
| <Stack direction="row" gap={1}> | |||
| {/* {!formProps.getValues("projectActualStart") && ( */} | |||
| <Button | |||
| variant="outlined" | |||
| startIcon={<Delete />} | |||
| color="error" | |||
| onClick={handleDelete} | |||
| name={buttonData.buttonName} | |||
| type="submit" | |||
| variant="contained" | |||
| startIcon={buttonData.buttonIcon} | |||
| color={buttonData.buttonColor} | |||
| > | |||
| {t("Delete Project")} | |||
| {t(buttonData.buttonText)} | |||
| </Button> | |||
| )} | |||
| </Stack> | |||
| </Grid> | |||
| )} | |||
| {!( | |||
| // formProps.getValues("projectActualStart") && | |||
| // formProps.getValues("projectActualEnd") | |||
| ( | |||
| formProps.getValues("projectStatus")?.toLowerCase() === | |||
| "completed" || | |||
| formProps.getValues("projectStatus")?.toLowerCase() === | |||
| "deleted" | |||
| ) | |||
| ) && | |||
| abilities.includes(DELETE_PROJECT) && ( | |||
| <Button | |||
| variant="outlined" | |||
| startIcon={<Delete />} | |||
| color="error" | |||
| onClick={handleDelete} | |||
| > | |||
| {t("Delete Project")} | |||
| </Button> | |||
| )} | |||
| </Stack> | |||
| </Grid> | |||
| )} | |||
| <Tabs | |||
| value={tabIndex} | |||
| onChange={handleTabChange} | |||
| @@ -658,9 +705,7 @@ const CreateProject: React.FC<Props> = ({ | |||
| variant="contained" | |||
| startIcon={<Check />} | |||
| type="submit" | |||
| disabled={ | |||
| disableChecking() | |||
| } | |||
| disabled={disableChecking()} | |||
| > | |||
| {isEditMode ? t("Save") : t("Confirm")} | |||
| </Button> | |||