@@ -1,4 +1,10 @@ | |||
import Holidays from "date-holidays"; | |||
import { HolidaysResult } from "../api/holidays"; | |||
import dayjs from "dayjs"; | |||
import arraySupport from "dayjs/plugin/arraySupport"; | |||
import { INPUT_DATE_FORMAT } from "./formatUtil"; | |||
dayjs.extend(arraySupport); | |||
const hd = new Holidays("HK"); | |||
@@ -47,3 +53,20 @@ export const getPublicHolidaysForNYears = (years: number = 1) => { | |||
}); | |||
}); | |||
}; | |||
export const getHolidayForDate = ( | |||
date: string, | |||
companyHolidays: HolidaysResult[] = [], | |||
) => { | |||
const currentYearHolidays: { date: string; title: string }[] = companyHolidays | |||
.map((h) => ({ | |||
title: h.name, | |||
// Dayjs use 0-index for months, but not our API | |||
date: dayjs([h.date[0], h.date[1] - 1, h.date[2]]).format( | |||
INPUT_DATE_FORMAT, | |||
), | |||
})) | |||
.concat(getPublicHolidaysForNYears(1).concat()); | |||
return currentYearHolidays.find((h) => h.date === date); | |||
}; |
@@ -0,0 +1,3 @@ | |||
export const roundToNearestQuarter = (n: number): number => { | |||
return Math.round(n / 0.25) * 0.25; | |||
}; |
@@ -20,9 +20,12 @@ import { | |||
LEAVE_DAILY_MAX_HOURS, | |||
TIMESHEET_DAILY_MAX_HOURS, | |||
} from "@/app/api/timesheets/utils"; | |||
import { HolidaysResult } from "@/app/api/holidays"; | |||
import { getHolidayForDate } from "@/app/utils/holidayUtils"; | |||
interface Props<EntryComponentProps = object> { | |||
days: string[]; | |||
companyHolidays: HolidaysResult[]; | |||
leaveEntries: RecordLeaveInput; | |||
timesheetEntries: RecordTimesheetInput; | |||
EntryComponent: React.FunctionComponent< | |||
@@ -37,6 +40,7 @@ function DateHoursList<EntryTableProps>({ | |||
timesheetEntries, | |||
EntryComponent, | |||
entryComponentProps, | |||
companyHolidays, | |||
}: Props<EntryTableProps>) { | |||
const { | |||
t, | |||
@@ -69,6 +73,11 @@ function DateHoursList<EntryTableProps>({ | |||
<Box overflow="scroll" flex={1}> | |||
{days.map((day, index) => { | |||
const dayJsObj = dayjs(day); | |||
const holiday = getHolidayForDate(day, companyHolidays); | |||
const isHoliday = | |||
holiday || dayJsObj.day() === 0 || dayJsObj.day() === 6; | |||
const leaves = leaveEntries[day]; | |||
const leaveHours = | |||
leaves?.reduce((acc, entry) => acc + entry.inputHours, 0) || 0; | |||
@@ -97,10 +106,16 @@ function DateHoursList<EntryTableProps>({ | |||
variant="overline" | |||
component="div" | |||
sx={{ | |||
color: dayJsObj.day() === 0 ? "error.main" : undefined, | |||
color: isHoliday ? "error.main" : undefined, | |||
}} | |||
> | |||
{shortDateFormatter(language).format(dayJsObj.toDate())} | |||
{holiday && ( | |||
<Typography | |||
marginInlineStart={1} | |||
variant="caption" | |||
>{`(${holiday.title})`}</Typography> | |||
)} | |||
</Typography> | |||
<Stack spacing={1}> | |||
<Box | |||
@@ -15,6 +15,7 @@ import { | |||
TableHead, | |||
TableRow, | |||
Tooltip, | |||
Typography, | |||
} from "@mui/material"; | |||
import dayjs from "dayjs"; | |||
import React, { useState } from "react"; | |||
@@ -23,11 +24,14 @@ import { | |||
LEAVE_DAILY_MAX_HOURS, | |||
TIMESHEET_DAILY_MAX_HOURS, | |||
} from "@/app/api/timesheets/utils"; | |||
import { HolidaysResult } from "@/app/api/holidays"; | |||
import { getHolidayForDate } from "@/app/utils/holidayUtils"; | |||
interface Props<EntryTableProps = object> { | |||
days: string[]; | |||
leaveEntries: RecordLeaveInput; | |||
timesheetEntries: RecordTimesheetInput; | |||
companyHolidays: HolidaysResult[]; | |||
EntryTableComponent: React.FunctionComponent< | |||
EntryTableProps & { day: string } | |||
>; | |||
@@ -40,6 +44,7 @@ function DateHoursTable<EntryTableProps>({ | |||
entryTableProps, | |||
leaveEntries, | |||
timesheetEntries, | |||
companyHolidays, | |||
}: Props<EntryTableProps>) { | |||
const { t } = useTranslation("home"); | |||
@@ -61,6 +66,7 @@ function DateHoursTable<EntryTableProps>({ | |||
<DayRow | |||
key={`${day}${index}`} | |||
day={day} | |||
companyHolidays={companyHolidays} | |||
leaveEntries={leaveEntries} | |||
timesheetEntries={timesheetEntries} | |||
EntryTableComponent={EntryTableComponent} | |||
@@ -80,8 +86,10 @@ function DayRow<EntryTableProps>({ | |||
timesheetEntries, | |||
entryTableProps, | |||
EntryTableComponent, | |||
companyHolidays | |||
}: { | |||
day: string; | |||
companyHolidays: HolidaysResult[]; | |||
leaveEntries: RecordLeaveInput; | |||
timesheetEntries: RecordTimesheetInput; | |||
EntryTableComponent: React.FunctionComponent< | |||
@@ -96,6 +104,9 @@ function DayRow<EntryTableProps>({ | |||
const dayJsObj = dayjs(day); | |||
const [open, setOpen] = useState(false); | |||
const holiday = getHolidayForDate(day, companyHolidays); | |||
const isHoliday = holiday || dayJsObj.day() === 0 || dayJsObj.day() === 6; | |||
const leaves = leaveEntries[day]; | |||
const leaveHours = | |||
leaves?.reduce((acc, entry) => acc + entry.inputHours, 0) || 0; | |||
@@ -125,10 +136,14 @@ function DayRow<EntryTableProps>({ | |||
{open ? <KeyboardArrowUp /> : <KeyboardArrowDown />} | |||
</IconButton> | |||
</TableCell> | |||
<TableCell | |||
sx={{ color: dayJsObj.day() === 0 ? "error.main" : undefined }} | |||
> | |||
<TableCell sx={{ color: isHoliday ? "error.main" : undefined }}> | |||
{shortDateFormatter(language).format(dayJsObj.toDate())} | |||
{holiday && ( | |||
<Typography | |||
display="block" | |||
variant="caption" | |||
>{`(${holiday.title})`}</Typography> | |||
)} | |||
</TableCell> | |||
{/* Timesheet */} | |||
<TableCell>{manhourFormatter.format(timesheetHours)}</TableCell> | |||
@@ -25,6 +25,7 @@ import { LeaveType } from "@/app/api/timesheets"; | |||
import FullscreenModal from "../FullscreenModal"; | |||
import MobileLeaveTable from "../LeaveTable/MobileLeaveTable"; | |||
import useIsMobile from "@/app/utils/useIsMobile"; | |||
import { HolidaysResult } from "@/app/api/holidays"; | |||
interface Props { | |||
isOpen: boolean; | |||
@@ -33,6 +34,7 @@ interface Props { | |||
defaultLeaveRecords?: RecordLeaveInput; | |||
leaveTypes: LeaveType[]; | |||
timesheetRecords: RecordTimesheetInput; | |||
companyHolidays: HolidaysResult[]; | |||
} | |||
const modalSx: SxProps = { | |||
@@ -52,6 +54,7 @@ const LeaveModal: React.FC<Props> = ({ | |||
defaultLeaveRecords, | |||
timesheetRecords, | |||
leaveTypes, | |||
companyHolidays, | |||
}) => { | |||
const { t } = useTranslation("home"); | |||
@@ -127,6 +130,7 @@ const LeaveModal: React.FC<Props> = ({ | |||
}} | |||
> | |||
<LeaveTable | |||
companyHolidays={companyHolidays} | |||
leaveTypes={leaveTypes} | |||
timesheetRecords={timesheetRecords} | |||
/> | |||
@@ -165,6 +169,7 @@ const LeaveModal: React.FC<Props> = ({ | |||
{t("Record Leave")} | |||
</Typography> | |||
<MobileLeaveTable | |||
companyHolidays={companyHolidays} | |||
leaveTypes={leaveTypes} | |||
timesheetRecords={timesheetRecords} | |||
/> | |||
@@ -1,5 +1,6 @@ | |||
import { LeaveType } from "@/app/api/timesheets"; | |||
import { LeaveEntry } from "@/app/api/timesheets/actions"; | |||
import { roundToNearestQuarter } from "@/app/utils/manhourUtils"; | |||
import { Check, Delete } from "@mui/icons-material"; | |||
import { | |||
Box, | |||
@@ -98,7 +99,7 @@ const LeaveEditModal: React.FC<Props> = ({ | |||
label={t("Hours")} | |||
fullWidth | |||
{...register("inputHours", { | |||
valueAsNumber: true, | |||
setValueAs: (value) => roundToNearestQuarter(parseFloat(value)), | |||
validate: (value) => value > 0, | |||
})} | |||
error={Boolean(formState.errors.inputHours)} | |||
@@ -22,6 +22,7 @@ import dayjs from "dayjs"; | |||
import isBetween from "dayjs/plugin/isBetween"; | |||
import { LeaveType } from "@/app/api/timesheets"; | |||
import { isValidLeaveEntry } from "@/app/api/timesheets/utils"; | |||
import { roundToNearestQuarter } from "@/app/utils/manhourUtils"; | |||
dayjs.extend(isBetween); | |||
@@ -173,6 +174,9 @@ const EntryInputTable: React.FC<Props> = ({ day, leaveTypes }) => { | |||
width: 150, | |||
editable: true, | |||
type: "number", | |||
valueParser(value) { | |||
return value ? roundToNearestQuarter(value) : value; | |||
}, | |||
valueFormatter(params) { | |||
return manhourFormatter.format(params.value); | |||
}, | |||
@@ -7,19 +7,26 @@ import { useFormContext } from "react-hook-form"; | |||
import LeaveEntryTable from "./LeaveEntryTable"; | |||
import { LeaveType } from "@/app/api/timesheets"; | |||
import DateHoursTable from "../DateHoursTable"; | |||
import { HolidaysResult } from "@/app/api/holidays"; | |||
interface Props { | |||
leaveTypes: LeaveType[]; | |||
timesheetRecords: RecordTimesheetInput; | |||
companyHolidays: HolidaysResult[]; | |||
} | |||
const LeaveTable: React.FC<Props> = ({ leaveTypes, timesheetRecords }) => { | |||
const LeaveTable: React.FC<Props> = ({ | |||
leaveTypes, | |||
timesheetRecords, | |||
companyHolidays, | |||
}) => { | |||
const { watch } = useFormContext<RecordLeaveInput>(); | |||
const currentInput = watch(); | |||
const days = Object.keys(currentInput); | |||
return ( | |||
<DateHoursTable | |||
companyHolidays={companyHolidays} | |||
days={days} | |||
leaveEntries={currentInput} | |||
timesheetEntries={timesheetRecords} | |||
@@ -1,33 +1,35 @@ | |||
import { LeaveType } from "@/app/api/timesheets"; | |||
import { LeaveEntry, RecordLeaveInput } from "@/app/api/timesheets/actions"; | |||
import { manhourFormatter, shortDateFormatter } from "@/app/utils/formatUtil"; | |||
import { Add, Edit } from "@mui/icons-material"; | |||
import { | |||
Box, | |||
Button, | |||
Card, | |||
CardContent, | |||
IconButton, | |||
Typography, | |||
} from "@mui/material"; | |||
import { shortDateFormatter } from "@/app/utils/formatUtil"; | |||
import { Add } from "@mui/icons-material"; | |||
import { Box, Button, Typography } from "@mui/material"; | |||
import dayjs from "dayjs"; | |||
import React, { useCallback, useMemo, useState } from "react"; | |||
import { useFormContext } from "react-hook-form"; | |||
import { useTranslation } from "react-i18next"; | |||
import LeaveEditModal, { Props as LeaveEditModalProps } from "./LeaveEditModal"; | |||
import LeaveEntryCard from "./LeaveEntryCard"; | |||
import { HolidaysResult } from "@/app/api/holidays"; | |||
import { getHolidayForDate } from "@/app/utils/holidayUtils"; | |||
interface Props { | |||
date: string; | |||
leaveTypes: LeaveType[]; | |||
companyHolidays: HolidaysResult[]; | |||
} | |||
const MobileLeaveEntry: React.FC<Props> = ({ date, leaveTypes }) => { | |||
const MobileLeaveEntry: React.FC<Props> = ({ | |||
date, | |||
leaveTypes, | |||
companyHolidays, | |||
}) => { | |||
const { | |||
t, | |||
i18n: { language }, | |||
} = useTranslation("home"); | |||
const dayJsObj = dayjs(date); | |||
const holiday = getHolidayForDate(date, companyHolidays); | |||
const isHoliday = holiday || dayJsObj.day() === 0 || dayJsObj.day() === 6; | |||
const leaveTypeMap = useMemo<{ [id: LeaveType["id"]]: LeaveType }>(() => { | |||
return leaveTypes.reduce( | |||
@@ -91,9 +93,15 @@ const MobileLeaveEntry: React.FC<Props> = ({ date, leaveTypes }) => { | |||
<Typography | |||
paddingInline={2} | |||
variant="overline" | |||
color={dayJsObj.day() === 0 ? "error.main" : undefined} | |||
color={isHoliday ? "error.main" : undefined} | |||
> | |||
{shortDateFormatter(language).format(dayJsObj.toDate())} | |||
{holiday && ( | |||
<Typography | |||
marginInlineStart={1} | |||
variant="caption" | |||
>{`(${holiday.title})`}</Typography> | |||
)} | |||
</Typography> | |||
<Box | |||
paddingInline={2} | |||
@@ -7,15 +7,18 @@ import { useFormContext } from "react-hook-form"; | |||
import { LeaveType } from "@/app/api/timesheets"; | |||
import MobileLeaveEntry from "./MobileLeaveEntry"; | |||
import DateHoursList from "../DateHoursTable/DateHoursList"; | |||
import { HolidaysResult } from "@/app/api/holidays"; | |||
interface Props { | |||
leaveTypes: LeaveType[]; | |||
timesheetRecords: RecordTimesheetInput; | |||
companyHolidays: HolidaysResult[]; | |||
} | |||
const MobileLeaveTable: React.FC<Props> = ({ | |||
timesheetRecords, | |||
leaveTypes, | |||
companyHolidays, | |||
}) => { | |||
const { watch } = useFormContext<RecordLeaveInput>(); | |||
const currentInput = watch(); | |||
@@ -24,10 +27,11 @@ const MobileLeaveTable: React.FC<Props> = ({ | |||
return ( | |||
<DateHoursList | |||
days={days} | |||
companyHolidays={companyHolidays} | |||
leaveEntries={currentInput} | |||
timesheetEntries={timesheetRecords} | |||
EntryComponent={MobileLeaveEntry} | |||
entryComponentProps={{ leaveTypes }} | |||
entryComponentProps={{ leaveTypes, companyHolidays }} | |||
/> | |||
); | |||
}; | |||
@@ -25,6 +25,7 @@ import { AssignedProject, ProjectWithTasks } from "@/app/api/projects"; | |||
import FullscreenModal from "../FullscreenModal"; | |||
import MobileTimesheetTable from "../TimesheetTable/MobileTimesheetTable"; | |||
import useIsMobile from "@/app/utils/useIsMobile"; | |||
import { HolidaysResult } from "@/app/api/holidays"; | |||
interface Props { | |||
isOpen: boolean; | |||
@@ -34,6 +35,7 @@ interface Props { | |||
username: string; | |||
defaultTimesheets?: RecordTimesheetInput; | |||
leaveRecords: RecordLeaveInput; | |||
companyHolidays: HolidaysResult[]; | |||
} | |||
const modalSx: SxProps = { | |||
@@ -54,6 +56,7 @@ const TimesheetModal: React.FC<Props> = ({ | |||
username, | |||
defaultTimesheets, | |||
leaveRecords, | |||
companyHolidays, | |||
}) => { | |||
const { t } = useTranslation("home"); | |||
@@ -129,6 +132,7 @@ const TimesheetModal: React.FC<Props> = ({ | |||
}} | |||
> | |||
<TimesheetTable | |||
companyHolidays={companyHolidays} | |||
assignedProjects={assignedProjects} | |||
allProjects={allProjects} | |||
leaveRecords={leaveRecords} | |||
@@ -168,6 +172,7 @@ const TimesheetModal: React.FC<Props> = ({ | |||
{t("Timesheet Input")} | |||
</Typography> | |||
<MobileTimesheetTable | |||
companyHolidays={companyHolidays} | |||
assignedProjects={assignedProjects} | |||
allProjects={allProjects} | |||
leaveRecords={leaveRecords} | |||
@@ -28,6 +28,7 @@ import ProjectSelect from "./ProjectSelect"; | |||
import TaskGroupSelect from "./TaskGroupSelect"; | |||
import TaskSelect from "./TaskSelect"; | |||
import { isValidTimeEntry } from "@/app/api/timesheets/utils"; | |||
import { roundToNearestQuarter } from "@/app/utils/manhourUtils"; | |||
dayjs.extend(isBetween); | |||
@@ -308,6 +309,9 @@ const EntryInputTable: React.FC<Props> = ({ | |||
width: 100, | |||
editable: true, | |||
type: "number", | |||
valueParser(value) { | |||
return value ? roundToNearestQuarter(value) : value; | |||
}, | |||
valueFormatter(params) { | |||
return manhourFormatter.format(params.value || 0); | |||
}, | |||
@@ -318,6 +322,9 @@ const EntryInputTable: React.FC<Props> = ({ | |||
width: 150, | |||
editable: true, | |||
type: "number", | |||
valueParser(value) { | |||
return value ? roundToNearestQuarter(value) : value; | |||
}, | |||
valueFormatter(params) { | |||
return manhourFormatter.format(params.value || 0); | |||
}, | |||
@@ -18,17 +18,21 @@ import TimesheetEditModal, { | |||
Props as TimesheetEditModalProps, | |||
} from "./TimesheetEditModal"; | |||
import TimeEntryCard from "./TimeEntryCard"; | |||
import { HolidaysResult } from "@/app/api/holidays"; | |||
import { getHolidayForDate } from "@/app/utils/holidayUtils"; | |||
interface Props { | |||
date: string; | |||
allProjects: ProjectWithTasks[]; | |||
assignedProjects: AssignedProject[]; | |||
companyHolidays: HolidaysResult[]; | |||
} | |||
const MobileTimesheetEntry: React.FC<Props> = ({ | |||
date, | |||
allProjects, | |||
assignedProjects, | |||
companyHolidays, | |||
}) => { | |||
const { | |||
t, | |||
@@ -44,6 +48,9 @@ const MobileTimesheetEntry: React.FC<Props> = ({ | |||
}, [allProjects]); | |||
const dayJsObj = dayjs(date); | |||
const holiday = getHolidayForDate(date, companyHolidays); | |||
const isHoliday = holiday || dayJsObj.day() === 0 || dayJsObj.day() === 6; | |||
const { watch, setValue } = useFormContext<RecordTimesheetInput>(); | |||
const currentEntries = watch(date); | |||
@@ -99,9 +106,15 @@ const MobileTimesheetEntry: React.FC<Props> = ({ | |||
<Typography | |||
paddingInline={2} | |||
variant="overline" | |||
color={dayJsObj.day() === 0 ? "error.main" : undefined} | |||
color={isHoliday ? "error.main" : undefined} | |||
> | |||
{shortDateFormatter(language).format(dayJsObj.toDate())} | |||
{holiday && ( | |||
<Typography | |||
marginInlineStart={1} | |||
variant="caption" | |||
>{`(${holiday.title})`}</Typography> | |||
)} | |||
</Typography> | |||
<Box | |||
paddingInline={2} | |||
@@ -7,17 +7,20 @@ import { useFormContext } from "react-hook-form"; | |||
import DateHoursList from "../DateHoursTable/DateHoursList"; | |||
import { AssignedProject, ProjectWithTasks } from "@/app/api/projects"; | |||
import MobileTimesheetEntry from "./MobileTimesheetEntry"; | |||
import { HolidaysResult } from "@/app/api/holidays"; | |||
interface Props { | |||
allProjects: ProjectWithTasks[]; | |||
assignedProjects: AssignedProject[]; | |||
leaveRecords: RecordLeaveInput; | |||
companyHolidays: HolidaysResult[]; | |||
} | |||
const MobileTimesheetTable: React.FC<Props> = ({ | |||
allProjects, | |||
assignedProjects, | |||
leaveRecords, | |||
companyHolidays, | |||
}) => { | |||
const { watch } = useFormContext<RecordTimesheetInput>(); | |||
const currentInput = watch(); | |||
@@ -26,10 +29,11 @@ const MobileTimesheetTable: React.FC<Props> = ({ | |||
return ( | |||
<DateHoursList | |||
days={days} | |||
companyHolidays={companyHolidays} | |||
leaveEntries={leaveRecords} | |||
timesheetEntries={currentInput} | |||
EntryComponent={MobileTimesheetEntry} | |||
entryComponentProps={{ allProjects, assignedProjects }} | |||
entryComponentProps={{ allProjects, assignedProjects, companyHolidays }} | |||
/> | |||
); | |||
}; | |||
@@ -20,6 +20,7 @@ import TaskGroupSelect from "./TaskGroupSelect"; | |||
import TaskSelect from "./TaskSelect"; | |||
import { TaskGroup } from "@/app/api/tasks"; | |||
import uniqBy from "lodash/uniqBy"; | |||
import { roundToNearestQuarter } from "@/app/utils/manhourUtils"; | |||
export interface Props extends Omit<ModalProps, "children"> { | |||
onSave: (leaveEntry: TimeEntry) => void; | |||
@@ -196,8 +197,9 @@ const TimesheetEditModal: React.FC<Props> = ({ | |||
label={t("Hours")} | |||
fullWidth | |||
{...register("inputHours", { | |||
valueAsNumber: true, | |||
validate: (value) => Boolean(value || otHours), | |||
setValueAs: (value) => roundToNearestQuarter(parseFloat(value)), | |||
validate: (value) => | |||
value ? value > 0 : Boolean(value || otHours), | |||
})} | |||
error={Boolean(formState.errors.inputHours)} | |||
/> | |||
@@ -206,7 +208,8 @@ const TimesheetEditModal: React.FC<Props> = ({ | |||
label={t("Other Hours")} | |||
fullWidth | |||
{...register("otHours", { | |||
valueAsNumber: true, | |||
setValueAs: (value) => roundToNearestQuarter(parseFloat(value)), | |||
validate: (value) => (value ? value > 0 : true), | |||
})} | |||
error={Boolean(formState.errors.otHours)} | |||
/> | |||
@@ -7,17 +7,20 @@ import { useFormContext } from "react-hook-form"; | |||
import EntryInputTable from "./EntryInputTable"; | |||
import { AssignedProject, ProjectWithTasks } from "@/app/api/projects"; | |||
import DateHoursTable from "../DateHoursTable"; | |||
import { HolidaysResult } from "@/app/api/holidays"; | |||
interface Props { | |||
allProjects: ProjectWithTasks[]; | |||
assignedProjects: AssignedProject[]; | |||
leaveRecords: RecordLeaveInput; | |||
companyHolidays: HolidaysResult[]; | |||
} | |||
const TimesheetTable: React.FC<Props> = ({ | |||
allProjects, | |||
assignedProjects, | |||
leaveRecords, | |||
companyHolidays, | |||
}) => { | |||
const { watch } = useFormContext<RecordTimesheetInput>(); | |||
const currentInput = watch(); | |||
@@ -25,6 +28,7 @@ const TimesheetTable: React.FC<Props> = ({ | |||
return ( | |||
<DateHoursTable | |||
companyHolidays={companyHolidays} | |||
days={days} | |||
leaveEntries={leaveRecords} | |||
timesheetEntries={currentInput} | |||
@@ -37,7 +37,7 @@ const UserWorkspacePage: React.FC<Props> = ({ | |||
username, | |||
defaultLeaveRecords, | |||
defaultTimesheets, | |||
holidays | |||
holidays, | |||
}) => { | |||
const [isTimeheetModalVisible, setTimeheetModalVisible] = useState(false); | |||
const [isLeaveModalVisible, setLeaveModalVisible] = useState(false); | |||
@@ -106,6 +106,7 @@ const UserWorkspacePage: React.FC<Props> = ({ | |||
leaveTypes={leaveTypes} | |||
/> | |||
<TimesheetModal | |||
companyHolidays={holidays} | |||
isOpen={isTimeheetModalVisible} | |||
onClose={handleCloseTimesheetModal} | |||
allProjects={allProjects} | |||
@@ -115,6 +116,7 @@ const UserWorkspacePage: React.FC<Props> = ({ | |||
leaveRecords={defaultLeaveRecords} | |||
/> | |||
<LeaveModal | |||
companyHolidays={holidays} | |||
leaveTypes={leaveTypes} | |||
isOpen={isLeaveModalVisible} | |||
onClose={handleCloseLeaveModal} | |||