|
|
@@ -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> |
|
|
|