@@ -32,7 +32,7 @@ export const truncateMoney = (amount: number | undefined) => { | |||||
const fractionDigits = maximumFractionDigits ?? minimumFractionDigits ?? 0; | const fractionDigits = maximumFractionDigits ?? minimumFractionDigits ?? 0; | ||||
const factor = Math.pow(10, fractionDigits); | const factor = Math.pow(10, fractionDigits); | ||||
const truncatedAmount = Math.floor(amount * factor) / factor; | |||||
const truncatedAmount = Math.round(amount * factor) / factor; | |||||
return truncatedAmount; | return truncatedAmount; | ||||
}; | }; | ||||
@@ -59,7 +59,7 @@ import { | |||||
} from "../Swal/CustomAlerts"; | } from "../Swal/CustomAlerts"; | ||||
import dayjs from "dayjs"; | import dayjs from "dayjs"; | ||||
import { DELETE_PROJECT } from "@/middleware"; | import { DELETE_PROJECT } from "@/middleware"; | ||||
import { OUTPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; | |||||
import { OUTPUT_DATE_FORMAT, sumMoney } from "@/app/utils/formatUtil"; | |||||
import { deleteDraft, loadDraft, saveToLocalStorage } from "@/app/utils/draftUtils"; | import { deleteDraft, loadDraft, saveToLocalStorage } from "@/app/utils/draftUtils"; | ||||
export interface Props { | export interface Props { | ||||
@@ -273,7 +273,7 @@ const CreateProject: React.FC<Props> = ({ | |||||
const onSubmit = useCallback<SubmitHandler<CreateProjectInputs>>( | const onSubmit = useCallback<SubmitHandler<CreateProjectInputs>>( | ||||
async (data, event) => { | async (data, event) => { | ||||
try { | try { | ||||
console.log(data); | |||||
// console.log(data); | |||||
// detect errors | // detect errors | ||||
let hasErrors = false; | let hasErrors = false; | ||||
@@ -374,30 +374,43 @@ const CreateProject: React.FC<Props> = ({ | |||||
data.milestones[parseFloat(key)].startDate = null | data.milestones[parseFloat(key)].startDate = null | ||||
data.milestones[parseFloat(key)].endDate = null | data.milestones[parseFloat(key)].endDate = null | ||||
} | } | ||||
// if ( | |||||
// !Boolean(startDate) || | |||||
// startDate === "Invalid Date" || | |||||
// !Boolean(endDate) || | |||||
// endDate === "Invalid Date" || | |||||
// new Date(startDate) > new Date(endDate) | |||||
// ) { | |||||
// formProps.setError("milestones", { | |||||
// message: "milestones is not valid", | |||||
// type: "invalid", | |||||
// }); | |||||
// setTabIndex(3); | |||||
// hasErrors = true; | |||||
// } | |||||
/* | |||||
unused code for checking the stage start date and end date | |||||
if ( | |||||
!Boolean(startDate) || | |||||
startDate === "Invalid Date" || | |||||
!Boolean(endDate) || | |||||
endDate === "Invalid Date" || | |||||
new Date(startDate) > new Date(endDate) | |||||
) { | |||||
formProps.setError("milestones", { | |||||
message: "milestones is not valid", | |||||
type: "invalid", | |||||
}); | |||||
setTabIndex(3); | |||||
hasErrors = true; | |||||
} | |||||
unused code for bulk add milestone payment | |||||
projectTotal += payments.reduce( | projectTotal += payments.reduce( | ||||
(acc, payment) => acc + payment.amount, | (acc, payment) => acc + payment.amount, | ||||
0, | 0, | ||||
); | ); | ||||
**/ | |||||
projectTotal += payments.reduce( | |||||
(acc, p) => sumMoney(acc, p.amount), | |||||
0, | |||||
); | |||||
}); | }); | ||||
// console.log(projectTotal) | |||||
console.log(milestonesKeys) | |||||
if ( | if ( | ||||
projectTotal !== data.expectedProjectFee || | |||||
milestonesKeys.length !== taskGroupKeys.length | |||||
projectTotal !== data.expectedProjectFee | |||||
// || milestonesKeys.length !== taskGroupKeys.length | |||||
) { | ) { | ||||
formProps.setError("milestones", { | formProps.setError("milestones", { | ||||
message: "milestones is not valid", | message: "milestones is not valid", | ||||
@@ -484,7 +497,7 @@ const CreateProject: React.FC<Props> = ({ | |||||
setServerError(t("An error has occurred. Please try again later.")); | setServerError(t("An error has occurred. Please try again later.")); | ||||
} | } | ||||
}, | }, | ||||
[router, t], | |||||
[router, t, draftId], | |||||
); | ); | ||||
const onSubmitError = useCallback<SubmitErrorHandler<CreateProjectInputs>>( | const onSubmitError = useCallback<SubmitErrorHandler<CreateProjectInputs>>( | ||||
@@ -565,6 +578,7 @@ const CreateProject: React.FC<Props> = ({ | |||||
const saveDraft = useCallback(async () => { | const saveDraft = useCallback(async () => { | ||||
const currentTimestamp = Date.now() | const currentTimestamp = Date.now() | ||||
console.log(currentTimestamp) | |||||
saveToLocalStorage(draftId || currentTimestamp, formProps.getValues()); | saveToLocalStorage(draftId || currentTimestamp, formProps.getValues()); | ||||
@@ -83,7 +83,7 @@ const CreateProjectWrapper: React.FC<Props> = async (props) => { | |||||
var filteredTeamLeads = teamId ? teamLeads.filter( | var filteredTeamLeads = teamId ? teamLeads.filter( | ||||
(teamLead) => teamLead.teamId === teamId, | (teamLead) => teamLead.teamId === teamId, | ||||
) : teamLeads | ) : teamLeads | ||||
if (userStaff?.id !== null && userStaff?.id == 1) { | |||||
if (userStaff?.id != null && userStaff?.id == 1) { | |||||
filteredTeamLeads = teamLeads.filter( | filteredTeamLeads = teamLeads.filter( | ||||
(teamLead) => teamLead.teamId === teamId || teamLead.team == "ST", | (teamLead) => teamLead.teamId === teamId || teamLead.team == "ST", | ||||
) | ) | ||||
@@ -23,6 +23,7 @@ import { useFormContext } from "react-hook-form"; | |||||
import { CreateProjectInputs } from "@/app/api/projects/actions"; | import { CreateProjectInputs } from "@/app/api/projects/actions"; | ||||
import MilestoneSection from "./MilestoneSection"; | import MilestoneSection from "./MilestoneSection"; | ||||
import ProjectTotalFee from "./ProjectTotalFee"; | import ProjectTotalFee from "./ProjectTotalFee"; | ||||
import { sumMoney } from "@/app/utils/formatUtil"; | |||||
export interface Props { | export interface Props { | ||||
allTasks: Task[]; | allTasks: Task[]; | ||||
@@ -89,10 +90,17 @@ const Milestone: React.FC<Props> = ({ allTasks, isActive }) => { | |||||
// hasError = true | // hasError = true | ||||
// } | // } | ||||
projectTotal += payments.reduce((acc, payment) => acc + payment.amount, 0) | |||||
// projectTotal += payments.reduce((acc, payment) => acc + payment.amount, 0) | |||||
projectTotal += payments.reduce( | |||||
(acc, p) => sumMoney(acc, p.amount), | |||||
0, | |||||
); | |||||
}) | }) | ||||
console.log(milestonesKeys) | |||||
if (projectTotal !== expectedTotalFee || milestonesKeys.length !== taskGroupsIds.length) { | |||||
// if (projectTotal !== expectedTotalFee || milestonesKeys.length !== taskGroupsIds.length) { | |||||
if (projectTotal !== expectedTotalFee) { | |||||
hasError = true | hasError = true | ||||
} | } | ||||
// console.log(Object.keys(milestones).reduce((acc, key) => acc + milestones[parseFloat(key)].payments.reduce((acc2, value) => acc2 + value.amount, 0), 0)) | // console.log(Object.keys(milestones).reduce((acc, key) => acc + milestones[parseFloat(key)].payments.reduce((acc2, value) => acc2 + value.amount, 0), 0)) | ||||
@@ -242,18 +242,18 @@ const ProjectClientDetails: React.FC<Props> = ({ | |||||
// (acc, wn) => ({ ...acc, [wn.id]: wn.name }), | // (acc, wn) => ({ ...acc, [wn.id]: wn.name }), | ||||
// {}, | // {}, | ||||
// ); | // ); | ||||
const planStart = getValues("projectPlanStart") | |||||
const planEnd = getValues("projectPlanEnd") | |||||
const planStart = watch("projectPlanStart") | |||||
const planEnd = watch("projectPlanEnd") | |||||
useEffect(() => { | useEffect(() => { | ||||
let hasErrors = false | let hasErrors = false | ||||
if( | if( | ||||
!planStart || planStart > planEnd | |||||
!planStart || new Date(planStart) > new Date(planEnd) | |||||
){ | ){ | ||||
hasErrors = true; | hasErrors = true; | ||||
} | } | ||||
if( | if( | ||||
!planEnd || planStart > planEnd | |||||
!planEnd || new Date(planStart) > new Date(planEnd) | |||||
){ | ){ | ||||
hasErrors = true; | hasErrors = true; | ||||
} | } | ||||
@@ -26,7 +26,7 @@ import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; | |||||
import { DemoItem } from "@mui/x-date-pickers/internals/demo"; | import { DemoItem } from "@mui/x-date-pickers/internals/demo"; | ||||
import dayjs from "dayjs"; | import dayjs from "dayjs"; | ||||
import { INPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; | import { INPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; | ||||
import TableModal from "./TableModal"; | |||||
// import TableModal from "./TableModal"; | |||||
import { Preview } from "@mui/icons-material"; | import { Preview } from "@mui/icons-material"; | ||||
import SalaryEffectiveModel from "../EditStaff/SalaryEffectiveModel"; | import SalaryEffectiveModel from "../EditStaff/SalaryEffectiveModel"; | ||||
import TeamHistoryModal from "../EditStaff/TeamHistoryModal"; | import TeamHistoryModal from "../EditStaff/TeamHistoryModal"; | ||||
@@ -13,12 +13,14 @@ interface Props { | |||||
leaveTypes: LeaveType[]; | leaveTypes: LeaveType[]; | ||||
timesheetRecords: RecordTimesheetInput; | timesheetRecords: RecordTimesheetInput; | ||||
companyHolidays: HolidaysResult[]; | companyHolidays: HolidaysResult[]; | ||||
isSaturdayWorker: boolean; | |||||
} | } | ||||
const LeaveTable: React.FC<Props> = ({ | const LeaveTable: React.FC<Props> = ({ | ||||
leaveTypes, | leaveTypes, | ||||
timesheetRecords, | timesheetRecords, | ||||
companyHolidays, | companyHolidays, | ||||
isSaturdayWorker | |||||
}) => { | }) => { | ||||
const { watch } = useFormContext<RecordLeaveInput>(); | const { watch } = useFormContext<RecordLeaveInput>(); | ||||
const currentInput = watch(); | const currentInput = watch(); | ||||
@@ -32,6 +34,7 @@ const LeaveTable: React.FC<Props> = ({ | |||||
timesheetEntries={timesheetRecords} | timesheetEntries={timesheetRecords} | ||||
EntryTableComponent={LeaveEntryTable} | EntryTableComponent={LeaveEntryTable} | ||||
entryTableProps={{ leaveTypes }} | entryTableProps={{ leaveTypes }} | ||||
isSaturdayWorker={isSaturdayWorker} | |||||
/> | /> | ||||
); | ); | ||||
}; | }; | ||||
@@ -110,10 +110,19 @@ const NavigationContent: React.FC<Props> = ({ abilities, username }) => { | |||||
path: "/home", | path: "/home", | ||||
showOnMobile: true, | showOnMobile: true, | ||||
}, | }, | ||||
// { | |||||
// icon: <SummarizeIcon />, | |||||
// label: "Financial Summary", | |||||
// path: "/dashboard/ProjectFinancialSummary", | |||||
// isHidden: ![VIEW_DASHBOARD_ALL, VIEW_DASHBOARD_SELF].some((ability) => | |||||
// abilities!.includes(ability), | |||||
// ), | |||||
// showOnMobile: false, | |||||
// }, | |||||
{ | { | ||||
icon: <SummarizeIcon />, | icon: <SummarizeIcon />, | ||||
label: "Financial Summary", | label: "Financial Summary", | ||||
path: "/dashboard/ProjectFinancialSummary", | |||||
path: "/dashboard/ProjectFinancialSummaryV2", | |||||
isHidden: ![VIEW_DASHBOARD_ALL, VIEW_DASHBOARD_SELF].some((ability) => | isHidden: ![VIEW_DASHBOARD_ALL, VIEW_DASHBOARD_SELF].some((ability) => | ||||
abilities!.includes(ability), | abilities!.includes(ability), | ||||
), | ), | ||||
@@ -172,16 +181,6 @@ const NavigationContent: React.FC<Props> = ({ abilities, username }) => { | |||||
}, | }, | ||||
], | ], | ||||
}, | }, | ||||
// { | |||||
// icon: <SummarizeIcon />, | |||||
// label: "Financial Summary", | |||||
// path: "/dashboard/ProjectFinancialSummaryV2", | |||||
// isHidden: ![VIEW_DASHBOARD_ALL, VIEW_DASHBOARD_SELF].some((ability) => | |||||
// abilities!.includes(ability), | |||||
// ), | |||||
// showOnMobile: true, | |||||
// }, | |||||
// No Claim function in Breaur, will be implement later | // No Claim function in Breaur, will be implement later | ||||
// { | // { | ||||