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