| @@ -13,6 +13,7 @@ import { | |||
| fetchProjectWithTasks, | |||
| } from "@/app/api/projects"; | |||
| import { fetchHolidays } from "@/app/api/holidays"; | |||
| import { fetchAllTasks } from "@/app/api/tasks"; | |||
| export const metadata: Metadata = { | |||
| title: "User Workspace", | |||
| @@ -27,6 +28,7 @@ const Home: React.FC = async () => { | |||
| fetchHolidays(); | |||
| fetchTeamMemberTimesheets(); | |||
| fetchTeamMemberLeaves(); | |||
| fetchAllTasks(); | |||
| return ( | |||
| <I18nProvider namespaces={["home", "common"]}> | |||
| @@ -51,7 +51,9 @@ export const preloadAllTasks = () => { | |||
| }; | |||
| export const fetchAllTasks = cache(async () => { | |||
| return serverFetchJson<Task[]>(`${BASE_API_URL}/tasks`); | |||
| return serverFetchJson<Task[]>(`${BASE_API_URL}/tasks`, { | |||
| next: { tags: ["tasks"] }, | |||
| }); | |||
| }); | |||
| export const fetchTaskTemplateDetail = cache(async (id: string) => { | |||
| @@ -43,7 +43,9 @@ export const validateTimeEntry = ( | |||
| error.taskId = "Required"; | |||
| } | |||
| } else { | |||
| if (!entry.remark) { | |||
| if (entry.taskGroupId && !entry.taskId) { | |||
| error.taskId = "Required"; | |||
| } else if (!entry.remark) { | |||
| error.remark = "Required for non-billable tasks"; | |||
| } | |||
| } | |||
| @@ -27,11 +27,13 @@ import { | |||
| import { manhourFormatter } from "@/app/utils/formatUtil"; | |||
| import { AssignedProject, ProjectWithTasks } from "@/app/api/projects"; | |||
| import uniqBy from "lodash/uniqBy"; | |||
| import { TaskGroup } from "@/app/api/tasks"; | |||
| import { Task, TaskGroup } from "@/app/api/tasks"; | |||
| import dayjs from "dayjs"; | |||
| import isBetween from "dayjs/plugin/isBetween"; | |||
| import ProjectSelect from "../TimesheetTable/ProjectSelect"; | |||
| import TaskGroupSelect from "../TimesheetTable/TaskGroupSelect"; | |||
| import TaskGroupSelect, { | |||
| TaskGroupSelectWithoutProject, | |||
| } from "../TimesheetTable/TaskGroupSelect"; | |||
| import TaskSelect from "../TimesheetTable/TaskSelect"; | |||
| import { | |||
| DAILY_NORMAL_MAX_HOURS, | |||
| @@ -54,6 +56,7 @@ interface Props { | |||
| assignedProjects: AssignedProject[]; | |||
| fastEntryEnabled?: boolean; | |||
| leaveTypes: LeaveType[]; | |||
| miscTasks: Task[]; | |||
| } | |||
| export type TimeLeaveRow = Partial< | |||
| @@ -71,6 +74,7 @@ const TimeLeaveInputTable: React.FC<Props> = ({ | |||
| isHoliday, | |||
| fastEntryEnabled, | |||
| leaveTypes, | |||
| miscTasks, | |||
| }) => { | |||
| const { t } = useTranslation("home"); | |||
| const taskGroupsByProject = useMemo(() => { | |||
| @@ -92,6 +96,14 @@ const TimeLeaveInputTable: React.FC<Props> = ({ | |||
| }; | |||
| }, {}); | |||
| }, [allProjects]); | |||
| const taskGroupsWithoutProject = useMemo( | |||
| () => | |||
| uniqBy( | |||
| miscTasks.map((t) => t.taskGroup), | |||
| "id", | |||
| ), | |||
| [miscTasks], | |||
| ); | |||
| // To check for start / end planned dates | |||
| const milestonesByProject = useMemo(() => { | |||
| @@ -314,31 +326,62 @@ const TimeLeaveInputTable: React.FC<Props> = ({ | |||
| editable: true, | |||
| renderEditCell(params: GridRenderEditCellParams<TimeLeaveRow, number>) { | |||
| if (params.row.type === "timeEntry") { | |||
| return ( | |||
| <TaskGroupSelect | |||
| projectId={params.row.projectId} | |||
| value={params.value} | |||
| taskGroupsByProject={taskGroupsByProject} | |||
| onTaskGroupSelect={(taskGroupId) => { | |||
| params.api.setEditCellValue({ | |||
| id: params.id, | |||
| field: params.field, | |||
| value: taskGroupId, | |||
| }); | |||
| params.api.setCellFocus(params.id, "taskId"); | |||
| }} | |||
| /> | |||
| ); | |||
| if (params.row.projectId) { | |||
| return ( | |||
| <TaskGroupSelect | |||
| projectId={params.row.projectId} | |||
| value={params.value} | |||
| taskGroupsByProject={taskGroupsByProject} | |||
| onTaskGroupSelect={(taskGroupId) => { | |||
| params.api.setEditCellValue({ | |||
| id: params.id, | |||
| field: params.field, | |||
| value: taskGroupId, | |||
| }); | |||
| params.api.setCellFocus(params.id, "taskId"); | |||
| }} | |||
| /> | |||
| ); | |||
| } else { | |||
| return ( | |||
| <TaskGroupSelectWithoutProject | |||
| value={params.value} | |||
| onTaskGroupSelect={(taskGroupId) => { | |||
| params.api.setEditCellValue({ | |||
| id: params.id, | |||
| field: params.field, | |||
| value: taskGroupId, | |||
| }); | |||
| params.api.setCellFocus(params.id, "taskId"); | |||
| }} | |||
| taskGroups={taskGroupsWithoutProject} | |||
| /> | |||
| ); | |||
| } | |||
| } else { | |||
| return <DisabledEdit />; | |||
| } | |||
| }, | |||
| valueFormatter(params) { | |||
| const taskGroups = params.id | |||
| ? taskGroupsByProject[params.api.getRow(params.id).projectId] || [] | |||
| : []; | |||
| const taskGroup = taskGroups.find((tg) => tg.value === params.value); | |||
| return taskGroup ? taskGroup.label : t("None"); | |||
| if (!params.id) { | |||
| return null; | |||
| } | |||
| const projectId = params.api.getRow(params.id).projectId; | |||
| if (projectId) { | |||
| const taskGroups = | |||
| taskGroupsByProject[params.api.getRow(params.id).projectId] || []; | |||
| const taskGroup = taskGroups.find( | |||
| (tg) => tg.value === params.value, | |||
| ); | |||
| return taskGroup ? taskGroup.label : t("None"); | |||
| } else { | |||
| const taskGroupId = params.value; | |||
| return ( | |||
| taskGroupsWithoutProject.find((tg) => tg.id === taskGroupId) | |||
| ?.name || t("None") | |||
| ); | |||
| } | |||
| }, | |||
| }, | |||
| { | |||
| @@ -362,6 +405,7 @@ const TimeLeaveInputTable: React.FC<Props> = ({ | |||
| }); | |||
| params.api.setCellFocus(params.id, "inputHours"); | |||
| }} | |||
| miscTasks={miscTasks} | |||
| /> | |||
| ); | |||
| } else { | |||
| @@ -373,12 +417,11 @@ const TimeLeaveInputTable: React.FC<Props> = ({ | |||
| ? params.api.getRow(params.id).projectId | |||
| : undefined; | |||
| const task = projectId | |||
| ? allProjects | |||
| .find((p) => p.id === projectId) | |||
| ?.tasks.find((t) => t.id === params.value) | |||
| : undefined; | |||
| const task = ( | |||
| projectId | |||
| ? allProjects.find((p) => p.id === projectId)?.tasks || [] | |||
| : miscTasks | |||
| ).find((t) => t.id === params.value); | |||
| return task ? task.name : t("None"); | |||
| }, | |||
| }, | |||
| @@ -475,6 +518,8 @@ const TimeLeaveInputTable: React.FC<Props> = ({ | |||
| leaveTypes, | |||
| assignedProjects, | |||
| taskGroupsByProject, | |||
| taskGroupsWithoutProject, | |||
| miscTasks, | |||
| ], | |||
| ); | |||
| @@ -23,6 +23,7 @@ import { getHolidayForDate } from "@/app/utils/holidayUtils"; | |||
| import FastTimeEntryModal from "../TimesheetTable/FastTimeEntryModal"; | |||
| import { LeaveType } from "@/app/api/timesheets"; | |||
| import LeaveEntryCard from "../LeaveTable/LeaveEntryCard"; | |||
| import { Task } from "@/app/api/tasks"; | |||
| interface Props { | |||
| date: string; | |||
| @@ -31,6 +32,7 @@ interface Props { | |||
| companyHolidays: HolidaysResult[]; | |||
| fastEntryEnabled?: boolean; | |||
| leaveTypes: LeaveType[]; | |||
| miscTasks: Task[]; | |||
| } | |||
| const TimeLeaveMobileEntry: React.FC<Props> = ({ | |||
| @@ -40,6 +42,7 @@ const TimeLeaveMobileEntry: React.FC<Props> = ({ | |||
| companyHolidays, | |||
| fastEntryEnabled, | |||
| leaveTypes, | |||
| miscTasks, | |||
| }) => { | |||
| const { | |||
| t, | |||
| @@ -222,7 +225,9 @@ const TimeLeaveMobileEntry: React.FC<Props> = ({ | |||
| ? projectMap[entry.projectId] | |||
| : undefined; | |||
| const task = project?.tasks.find((t) => t.id === entry.taskId); | |||
| const task = (project ? project.tasks : miscTasks).find( | |||
| (t) => t.id === entry.taskId, | |||
| ); | |||
| return ( | |||
| <TimeEntryCard | |||
| @@ -269,7 +274,7 @@ const TimeLeaveMobileEntry: React.FC<Props> = ({ | |||
| onClose={closeEditTimeModal} | |||
| onSave={onSaveTimeEntry} | |||
| isHoliday={Boolean(isHoliday)} | |||
| fastEntryEnabled={fastEntryEnabled} | |||
| miscTasks={miscTasks} | |||
| {...editTimeModalProps} | |||
| /> | |||
| <LeaveEditModal | |||
| @@ -38,6 +38,7 @@ import mapValues from "lodash/mapValues"; | |||
| import DateHoursList from "../DateHoursTable/DateHoursList"; | |||
| import TimeLeaveInputTable from "./TimeLeaveInputTable"; | |||
| import TimeLeaveMobileEntry from "./TimeLeaveMobileEntry"; | |||
| import { Task } from "@/app/api/tasks"; | |||
| interface Props { | |||
| isOpen: boolean; | |||
| @@ -50,6 +51,7 @@ interface Props { | |||
| fastEntryEnabled?: boolean; | |||
| leaveTypes: LeaveType[]; | |||
| isFullTime: boolean; | |||
| miscTasks: Task[]; | |||
| } | |||
| const modalSx: SxProps = { | |||
| @@ -72,7 +74,8 @@ const TimeLeaveModal: React.FC<Props> = ({ | |||
| companyHolidays, | |||
| fastEntryEnabled, | |||
| leaveTypes, | |||
| isFullTime | |||
| isFullTime, | |||
| miscTasks, | |||
| }) => { | |||
| const { t } = useTranslation("home"); | |||
| @@ -212,6 +215,7 @@ const TimeLeaveModal: React.FC<Props> = ({ | |||
| allProjects, | |||
| fastEntryEnabled, | |||
| leaveTypes, | |||
| miscTasks, | |||
| }} | |||
| /> | |||
| </Box> | |||
| @@ -261,6 +265,7 @@ const TimeLeaveModal: React.FC<Props> = ({ | |||
| companyHolidays, | |||
| fastEntryEnabled, | |||
| leaveTypes, | |||
| miscTasks, | |||
| }} | |||
| errorComponent={errorComponent} | |||
| /> | |||
| @@ -68,7 +68,7 @@ const getID = () => { | |||
| }; | |||
| const MISC_TASK_GROUP_ID = 5; | |||
| const FAST_ENTRY_TASK_ID = 40; | |||
| const FAST_ENTRY_TASK_ID = 43; | |||
| const FastTimeEntryModal: React.FC<Props> = ({ | |||
| onSave, | |||
| @@ -140,8 +140,8 @@ const FastTimeEntryModal: React.FC<Props> = ({ | |||
| projectId, | |||
| inputHours: hour, | |||
| otHours: othour, | |||
| taskGroupId: projectId ? MISC_TASK_GROUP_ID : undefined, | |||
| taskId: projectId ? FAST_ENTRY_TASK_ID : undefined, | |||
| taskGroupId: MISC_TASK_GROUP_ID, | |||
| taskId: FAST_ENTRY_TASK_ID, | |||
| remark, | |||
| }; | |||
| }), | |||
| @@ -1,5 +1,5 @@ | |||
| import React, { useCallback } from "react"; | |||
| import { MenuItem, Select, SelectChangeEvent } from "@mui/material"; | |||
| import { MenuItem, MenuProps, Select, SelectChangeEvent } from "@mui/material"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import { TaskGroup } from "@/app/api/tasks"; | |||
| @@ -16,6 +16,22 @@ interface Props { | |||
| error?: boolean; | |||
| } | |||
| const menuProps: Partial<MenuProps> = { | |||
| slotProps: { | |||
| paper: { | |||
| sx: { maxHeight: 400 }, | |||
| }, | |||
| }, | |||
| anchorOrigin: { | |||
| vertical: "bottom", | |||
| horizontal: "left", | |||
| }, | |||
| transformOrigin: { | |||
| vertical: "top", | |||
| horizontal: "left", | |||
| }, | |||
| }; | |||
| const TaskGroupSelect: React.FC<Props> = ({ | |||
| value, | |||
| projectId, | |||
| @@ -43,21 +59,7 @@ const TaskGroupSelect: React.FC<Props> = ({ | |||
| value={value || ""} | |||
| onChange={onChange} | |||
| sx={{ width: "100%" }} | |||
| MenuProps={{ | |||
| slotProps: { | |||
| paper: { | |||
| sx: { maxHeight: 400 }, | |||
| }, | |||
| }, | |||
| anchorOrigin: { | |||
| vertical: "bottom", | |||
| horizontal: "left", | |||
| }, | |||
| transformOrigin: { | |||
| vertical: "top", | |||
| horizontal: "left", | |||
| }, | |||
| }} | |||
| MenuProps={menuProps} | |||
| > | |||
| {taskGroups.length === 0 && <MenuItem value={""}>{t("None")}</MenuItem>} | |||
| {taskGroups.map((taskGroup) => ( | |||
| @@ -73,4 +75,46 @@ const TaskGroupSelect: React.FC<Props> = ({ | |||
| ); | |||
| }; | |||
| type TaskGroupSelectWithoutProjectProps = Pick< | |||
| Props, | |||
| "value" | "onTaskGroupSelect" | "error" | |||
| > & { taskGroups: TaskGroup[] }; | |||
| export const TaskGroupSelectWithoutProject: React.FC< | |||
| TaskGroupSelectWithoutProjectProps | |||
| > = ({ value, onTaskGroupSelect, error, taskGroups }) => { | |||
| const { t } = useTranslation("home"); | |||
| const onChange = useCallback( | |||
| (event: SelectChangeEvent<number>) => { | |||
| const newValue = event.target.value; | |||
| onTaskGroupSelect(newValue); | |||
| }, | |||
| [onTaskGroupSelect], | |||
| ); | |||
| return ( | |||
| <Select | |||
| error={error} | |||
| displayEmpty | |||
| disabled={taskGroups.length === 0} | |||
| value={value || ""} | |||
| onChange={onChange} | |||
| sx={{ width: "100%" }} | |||
| MenuProps={menuProps} | |||
| > | |||
| {<MenuItem value={""}>{t("None")}</MenuItem>} | |||
| {taskGroups.map((taskGroup) => ( | |||
| <MenuItem | |||
| key={taskGroup.id} | |||
| value={taskGroup.id} | |||
| sx={{ whiteSpace: "wrap" }} | |||
| > | |||
| {taskGroup.name} | |||
| </MenuItem> | |||
| ))} | |||
| </Select> | |||
| ); | |||
| }; | |||
| export default TaskGroupSelect; | |||
| @@ -2,6 +2,7 @@ import React, { useCallback } from "react"; | |||
| import { MenuItem, Select, SelectChangeEvent } from "@mui/material"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import { ProjectWithTasks } from "@/app/api/projects"; | |||
| import { Task } from "@/app/api/tasks"; | |||
| interface Props { | |||
| allProjects: ProjectWithTasks[]; | |||
| @@ -10,6 +11,7 @@ interface Props { | |||
| taskGroupId: number | undefined; | |||
| onTaskSelect: (taskId: number | string) => void; | |||
| error?: boolean; | |||
| miscTasks?: Task[]; | |||
| } | |||
| const TaskSelect: React.FC<Props> = ({ | |||
| @@ -18,14 +20,15 @@ const TaskSelect: React.FC<Props> = ({ | |||
| projectId, | |||
| taskGroupId, | |||
| onTaskSelect, | |||
| error | |||
| error, | |||
| miscTasks, | |||
| }) => { | |||
| const { t } = useTranslation("home"); | |||
| const project = allProjects.find((p) => p.id === projectId); | |||
| const tasks = project | |||
| ? project.tasks.filter((task) => task.taskGroup.id === taskGroupId) | |||
| : []; | |||
| const tasks = (project ? project.tasks : miscTasks || []).filter( | |||
| (task) => task.taskGroup.id === taskGroupId, | |||
| ); | |||
| const onChange = useCallback( | |||
| (event: SelectChangeEvent<number>) => { | |||
| @@ -17,9 +17,11 @@ import { Controller, useForm } from "react-hook-form"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import ProjectSelect from "./ProjectSelect"; | |||
| import { AssignedProject, ProjectWithTasks } from "@/app/api/projects"; | |||
| import TaskGroupSelect from "./TaskGroupSelect"; | |||
| import TaskGroupSelect, { | |||
| TaskGroupSelectWithoutProject, | |||
| } from "./TaskGroupSelect"; | |||
| import TaskSelect from "./TaskSelect"; | |||
| import { TaskGroup } from "@/app/api/tasks"; | |||
| import { Task, TaskGroup } from "@/app/api/tasks"; | |||
| import uniqBy from "lodash/uniqBy"; | |||
| import { roundToNearestQuarter } from "@/app/utils/manhourUtils"; | |||
| import { shortDateFormatter } from "@/app/utils/formatUtil"; | |||
| @@ -37,7 +39,7 @@ export interface Props extends Omit<ModalProps, "children"> { | |||
| modalSx?: SxProps; | |||
| recordDate?: string; | |||
| isHoliday?: boolean; | |||
| fastEntryEnabled?: boolean; | |||
| miscTasks: Task[]; | |||
| } | |||
| const modalSx: SxProps = { | |||
| @@ -63,7 +65,7 @@ const TimesheetEditModal: React.FC<Props> = ({ | |||
| modalSx: mSx, | |||
| recordDate, | |||
| isHoliday, | |||
| fastEntryEnabled, | |||
| miscTasks, | |||
| }) => { | |||
| const { | |||
| t, | |||
| @@ -90,6 +92,15 @@ const TimesheetEditModal: React.FC<Props> = ({ | |||
| }, {}); | |||
| }, [allProjects]); | |||
| const taskGroupsWithoutProject = useMemo( | |||
| () => | |||
| uniqBy( | |||
| miscTasks.map((t) => t.taskGroup), | |||
| "id", | |||
| ), | |||
| [miscTasks], | |||
| ); | |||
| const { | |||
| register, | |||
| control, | |||
| @@ -174,23 +185,35 @@ const TimesheetEditModal: React.FC<Props> = ({ | |||
| <Controller | |||
| control={control} | |||
| name="taskGroupId" | |||
| render={({ field }) => ( | |||
| <TaskGroupSelect | |||
| error={Boolean(formState.errors.taskGroupId)} | |||
| projectId={projectId} | |||
| taskGroupsByProject={taskGroupsByProject} | |||
| value={field.value} | |||
| onTaskGroupSelect={(newId) => { | |||
| field.onChange(newId ?? null); | |||
| }} | |||
| /> | |||
| )} | |||
| render={({ field }) => | |||
| projectId ? ( | |||
| <TaskGroupSelect | |||
| error={Boolean(formState.errors.taskGroupId)} | |||
| projectId={projectId} | |||
| taskGroupsByProject={taskGroupsByProject} | |||
| value={field.value} | |||
| onTaskGroupSelect={(newId) => { | |||
| field.onChange(newId ?? null); | |||
| }} | |||
| /> | |||
| ) : ( | |||
| <TaskGroupSelectWithoutProject | |||
| value={field.value} | |||
| onTaskGroupSelect={(newId) => { | |||
| field.onChange(newId ?? null); | |||
| if (!newId) { | |||
| setValue("taskId", undefined); | |||
| } | |||
| }} | |||
| taskGroups={taskGroupsWithoutProject} | |||
| /> | |||
| ) | |||
| } | |||
| rules={{ | |||
| validate: (id) => { | |||
| if (!projectId) { | |||
| return !id; | |||
| return true; | |||
| } | |||
| if (fastEntryEnabled) return true; | |||
| const taskGroups = taskGroupsByProject[projectId]; | |||
| return taskGroups.some((tg) => tg.value === id); | |||
| }, | |||
| @@ -213,17 +236,23 @@ const TimesheetEditModal: React.FC<Props> = ({ | |||
| onTaskSelect={(newId) => { | |||
| field.onChange(newId ?? null); | |||
| }} | |||
| miscTasks={miscTasks} | |||
| /> | |||
| )} | |||
| rules={{ | |||
| validate: (id) => { | |||
| if (!projectId) { | |||
| return !id; | |||
| } | |||
| if (fastEntryEnabled) return true; | |||
| const projectTasks = allProjects.find((p) => p.id === projectId) | |||
| ?.tasks; | |||
| return Boolean(projectTasks?.some((task) => task.id === id)); | |||
| const tasks = projectId | |||
| ? allProjects.find((p) => p.id === projectId)?.tasks | |||
| : miscTasks; | |||
| return taskGroupId | |||
| ? Boolean( | |||
| tasks?.some( | |||
| (task) => | |||
| task.id === id && task.taskGroup.id === taskGroupId, | |||
| ), | |||
| ) | |||
| : !id; | |||
| }, | |||
| }} | |||
| /> | |||
| @@ -25,6 +25,7 @@ import { HolidaysResult } from "@/app/api/holidays"; | |||
| import { TimesheetAmendmentModal } from "../TimesheetAmendment/TimesheetAmendmentModal"; | |||
| import TimeLeaveModal from "../TimeLeaveModal/TimeLeaveModal"; | |||
| import LeaveModal from "../LeaveModal"; | |||
| import { Task } from "@/app/api/tasks"; | |||
| export interface Props { | |||
| leaveTypes: LeaveType[]; | |||
| @@ -39,6 +40,7 @@ export interface Props { | |||
| maintainNormalStaffWorkspaceAbility: boolean; | |||
| maintainManagementStaffWorkspaceAbility: boolean; | |||
| isFullTime: boolean; | |||
| miscTasks: Task[]; | |||
| } | |||
| const menuItemSx: SxProps = { | |||
| @@ -59,6 +61,7 @@ const UserWorkspacePage: React.FC<Props> = ({ | |||
| maintainNormalStaffWorkspaceAbility, | |||
| maintainManagementStaffWorkspaceAbility, | |||
| isFullTime, | |||
| miscTasks | |||
| }) => { | |||
| const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null); | |||
| @@ -189,6 +192,7 @@ const UserWorkspacePage: React.FC<Props> = ({ | |||
| timesheetRecords={defaultTimesheets} | |||
| leaveRecords={defaultLeaveRecords} | |||
| isFullTime={isFullTime} | |||
| miscTasks={miscTasks} | |||
| /> | |||
| <LeaveModal | |||
| open={isLeaveCalendarVisible} | |||
| @@ -17,6 +17,7 @@ import { | |||
| MAINTAIN_NORMAL_STAFF_WORKSPACE, | |||
| MAINTAIN_MANAGEMENT_STAFF_WORKSPACE, | |||
| } from "@/middleware"; | |||
| import { fetchAllTasks } from "@/app/api/tasks"; | |||
| const UserWorkspaceWrapper: React.FC = async () => { | |||
| const [ | |||
| @@ -30,6 +31,7 @@ const UserWorkspaceWrapper: React.FC = async () => { | |||
| holidays, | |||
| abilities, | |||
| userStaff, | |||
| allTasks, | |||
| ] = await Promise.all([ | |||
| fetchTeamMemberLeaves(), | |||
| fetchTeamMemberTimesheets(), | |||
| @@ -41,6 +43,7 @@ const UserWorkspaceWrapper: React.FC = async () => { | |||
| fetchHolidays(), | |||
| getUserAbilities(), | |||
| getUserStaff(), | |||
| fetchAllTasks(), | |||
| ]); | |||
| const fastEntryEnabled = abilities.includes( | |||
| @@ -54,6 +57,8 @@ const UserWorkspaceWrapper: React.FC = async () => { | |||
| ); | |||
| const isFullTime = userStaff?.employType === "FT"; | |||
| const miscTasks = allTasks.filter((t) => t.taskGroup.id === 5); | |||
| return ( | |||
| <UserWorkspacePage | |||
| isFullTime={isFullTime} | |||
| @@ -65,6 +70,7 @@ const UserWorkspaceWrapper: React.FC = async () => { | |||
| defaultLeaveRecords={leaves} | |||
| leaveTypes={leaveTypes} | |||
| holidays={holidays} | |||
| miscTasks={miscTasks} | |||
| // Change to access check | |||
| fastEntryEnabled={fastEntryEnabled} | |||
| maintainNormalStaffWorkspaceAbility={maintainNormalStaffWorkspaceAbility} | |||