@@ -60,6 +60,7 @@ export interface MonthlyWorkHoursReportFilter { | |||||
export interface MonthlyWorkHoursReportRequest { | export interface MonthlyWorkHoursReportRequest { | ||||
id: number; | id: number; | ||||
yearMonth: string; | yearMonth: string; | ||||
holidays: String[]; | |||||
} | } | ||||
// - Project Resource Overconsumption Report | // - Project Resource Overconsumption Report | ||||
export interface ProjectResourceOverconsumptionReportFilter { | export interface ProjectResourceOverconsumptionReportFilter { | ||||
@@ -8,11 +8,11 @@ dayjs.extend(arraySupport); | |||||
const hd = new Holidays("HK"); | const hd = new Holidays("HK"); | ||||
export const getPublicHolidaysForNYears = (years: number = 1) => { | |||||
export const getPublicHolidaysForNYears = (years: number = 1, currYr?: number) => { | |||||
return Array(years) | return Array(years) | ||||
.fill(undefined) | .fill(undefined) | ||||
.flatMap((_, index) => { | .flatMap((_, index) => { | ||||
const currentYear = new Date().getFullYear(); | |||||
const currentYear = currYr ?? new Date().getFullYear(); | |||||
const holidays = hd.getHolidays(currentYear + index); | const holidays = hd.getHolidays(currentYear + index); | ||||
return holidays.map((ele) => { | return holidays.map((ele) => { | ||||
const tempDay = new Date(ele.date); | const tempDay = new Date(ele.date); | ||||
@@ -28,7 +28,7 @@ const ChangePassword: React.FC<PasswordRulesProps> = ({ | |||||
try { | try { | ||||
let haveError = false; | let haveError = false; | ||||
// Minimum eight characters, at least one uppercase letter, one lowercase letter, one number and one special character: | // Minimum eight characters, at least one uppercase letter, one lowercase letter, one number and one special character: | ||||
let regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/ | |||||
let regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&-=+_]{8,}$/ | |||||
if (data.newPassword.length < 8 || data.newPassword.length > 20) { | if (data.newPassword.length < 8 || data.newPassword.length > 20) { | ||||
haveError = true | haveError = true | ||||
@@ -21,7 +21,7 @@ const CostAndExpenseReportWrapper: React.FC & SubComponents = async () => { | |||||
let teams = await fetchTeam() | let teams = await fetchTeam() | ||||
let needAll = true | let needAll = true | ||||
if (role === TEAM_LEAD) { | |||||
if (role.includes(TEAM_LEAD)) { | |||||
needAll = false | needAll = false | ||||
teams = teams.filter((team) => team.id === teamId); | teams = teams.filter((team) => team.id === teamId); | ||||
} | } | ||||
@@ -13,18 +13,20 @@ import { MonthlyWorkHoursReportFilter } from "@/app/api/reports"; | |||||
import { records } from "@/app/api/staff/actions"; | import { records } from "@/app/api/staff/actions"; | ||||
import { StaffResult } from "@/app/api/staff"; | import { StaffResult } from "@/app/api/staff"; | ||||
import dayjs from "dayjs"; | import dayjs from "dayjs"; | ||||
import { getPublicHolidaysForNYears } from "@/app/utils/holidayUtils"; | |||||
interface Props { | interface Props { | ||||
staffs: StaffResult[]; | staffs: StaffResult[]; | ||||
companyHolidays: String[]; | |||||
} | } | ||||
type SearchQuery = Partial<Omit<MonthlyWorkHoursReportFilter, "id">>; | type SearchQuery = Partial<Omit<MonthlyWorkHoursReportFilter, "id">>; | ||||
type SearchParamNames = keyof SearchQuery; | type SearchParamNames = keyof SearchQuery; | ||||
const GenerateMonthlyWorkHoursReport: React.FC<Props> = ({ staffs }) => { | |||||
const GenerateMonthlyWorkHoursReport: React.FC<Props> = ({ staffs, companyHolidays }) => { | |||||
const { t } = useTranslation("report"); | const { t } = useTranslation("report"); | ||||
const staffCombo = staffs.map((staff) => ({label: `${staff.name} - ${staff.staffId}`, value: staff.id})) | const staffCombo = staffs.map((staff) => ({label: `${staff.name} - ${staff.staffId}`, value: staff.id})) | ||||
console.log(companyHolidays) | |||||
const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | ||||
() => [ | () => [ | ||||
@@ -44,6 +46,12 @@ const GenerateMonthlyWorkHoursReport: React.FC<Props> = ({ staffs }) => { | |||||
[t] | [t] | ||||
); | ); | ||||
const holidayList: String[] = [...getPublicHolidaysForNYears(1, 2023).map((item) => dayjs(item.date).format("DD/MM/YYYY")), ...companyHolidays] | |||||
const uniqueHoliday = holidayList.filter((value, index, arr) => index === arr.indexOf(value)); | |||||
console.log(uniqueHoliday) | |||||
return ( | return ( | ||||
<> | <> | ||||
<SearchBox | <SearchBox | ||||
@@ -54,11 +62,13 @@ const GenerateMonthlyWorkHoursReport: React.FC<Props> = ({ staffs }) => { | |||||
let postData = { | let postData = { | ||||
id: query.staff, | id: query.staff, | ||||
yearMonth: dayjs().format("YYYY-MM").toString(), | yearMonth: dayjs().format("YYYY-MM").toString(), | ||||
holidays: uniqueHoliday | |||||
}; | }; | ||||
console.log(query.date.length > 0) | console.log(query.date.length > 0) | ||||
if (query.date.length > 0) { | if (query.date.length > 0) { | ||||
postData.yearMonth = query.date | postData.yearMonth = query.date | ||||
} | } | ||||
console.log(postData) | |||||
const response = await fetchMonthlyWorkHoursReport(postData); | const response = await fetchMonthlyWorkHoursReport(postData); | ||||
if (response) { | if (response) { | ||||
downloadFile( | downloadFile( | ||||
@@ -5,6 +5,8 @@ import { fetchStaff } from "@/app/api/staff"; | |||||
import { getServerSession } from "next-auth"; | import { getServerSession } from "next-auth"; | ||||
import { authOptions } from "@/config/authConfig"; | import { authOptions } from "@/config/authConfig"; | ||||
import { TEAM_LEAD } from "@/middleware"; | import { TEAM_LEAD } from "@/middleware"; | ||||
import { fetchHolidays } from "@/app/api/holidays"; | |||||
import { convertDateArrayToString } from "@/app/utils/formatUtil"; | |||||
interface SubComponents { | interface SubComponents { | ||||
Loading: typeof GenerateMonthlyWorkHoursReportLoading; | Loading: typeof GenerateMonthlyWorkHoursReportLoading; | ||||
} | } | ||||
@@ -14,13 +16,20 @@ const GenerateMonthlyWorkHoursReportWrapper: React.FC & | |||||
const session: any = await getServerSession(authOptions); | const session: any = await getServerSession(authOptions); | ||||
const teamId = session.staff?.teamId; | const teamId = session.staff?.teamId; | ||||
const role = session.role; | const role = session.role; | ||||
const companyHolidays = await fetchHolidays() | |||||
let companyHolidaysList: String[] = [] | |||||
if (companyHolidays.length > 0) { | |||||
companyHolidaysList = companyHolidays.map(item => convertDateArrayToString(item.date, "DD/MM/YYYY")) as String[] | |||||
} | |||||
console.log(companyHolidaysList) | |||||
let staffs = await fetchStaff(); | let staffs = await fetchStaff(); | ||||
if (role === TEAM_LEAD) { | |||||
if (role.includes(TEAM_LEAD)) { | |||||
staffs = staffs.filter((staff) => staff.teamId === teamId); | staffs = staffs.filter((staff) => staff.teamId === teamId); | ||||
} | } | ||||
return <GenerateMonthlyWorkHoursReport staffs={staffs} />; | |||||
return <GenerateMonthlyWorkHoursReport staffs={staffs} companyHolidays={companyHolidaysList} />; | |||||
}; | }; | ||||
GenerateMonthlyWorkHoursReportWrapper.Loading = GenerateMonthlyWorkHoursReportLoading; | GenerateMonthlyWorkHoursReportWrapper.Loading = GenerateMonthlyWorkHoursReportLoading; | ||||
@@ -16,7 +16,7 @@ const ProjectCompletionReportWrapper: React.FC & SubComponents = async () => { | |||||
const teamId = session.staff?.teamId | const teamId = session.staff?.teamId | ||||
const role = session.role | const role = session.role | ||||
return <ProjectCompletionReport teamId={role === TEAM_LEAD && session.staff?.team ? teamId : null}/> | |||||
return <ProjectCompletionReport teamId={role.includes(TEAM_LEAD) && session.staff?.team ? teamId : null}/> | |||||
}; | }; | ||||
ProjectCompletionReportWrapper.Loading = ProjectCompletionReportLoading; | ProjectCompletionReportWrapper.Loading = ProjectCompletionReportLoading; | ||||
@@ -24,7 +24,7 @@ const ResourceOvercomsumptionReportWrapper: React.FC & | |||||
fetchAllSubsidiaries(), | fetchAllSubsidiaries(), | ||||
]); | ]); | ||||
if (role === TEAM_LEAD) { | |||||
if (role.includes(TEAM_LEAD)) { | |||||
needAll = false; | needAll = false; | ||||
teams = teams.filter((team) => team.id === teamId); | teams = teams.filter((team) => team.id === teamId); | ||||
} | } | ||||