diff --git a/src/app/api/projects/index.ts b/src/app/api/projects/index.ts index 6833571..15efcb9 100644 --- a/src/app/api/projects/index.ts +++ b/src/app/api/projects/index.ts @@ -75,6 +75,7 @@ export interface WorkNature { export interface ProjectWithTasks { id: number; code: string; + status?: string; name: string; tasks: Task[]; milestones: { diff --git a/src/components/LeaveModal/LeaveModal.tsx b/src/components/LeaveModal/LeaveModal.tsx index e8f32d1..0d5b81c 100644 --- a/src/components/LeaveModal/LeaveModal.tsx +++ b/src/components/LeaveModal/LeaveModal.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useMemo } from "react"; +import React, { useCallback, useEffect, useMemo } from "react"; import { Box, Button, @@ -78,6 +78,9 @@ const LeaveModal: React.FC = ({ }, [defaultLeaveRecords]); const formProps = useForm({ defaultValues }); + useEffect(() => { + formProps.reset(defaultValues); + }, [defaultValues, formProps]); const onSubmit = useCallback>( async (data) => { diff --git a/src/components/TimesheetAmendment/TimesheetAmendment.tsx b/src/components/TimesheetAmendment/TimesheetAmendment.tsx index fe1d9ea..70fd912 100644 --- a/src/components/TimesheetAmendment/TimesheetAmendment.tsx +++ b/src/components/TimesheetAmendment/TimesheetAmendment.tsx @@ -4,7 +4,15 @@ import { HolidaysResult } from "@/app/api/holidays"; import { LeaveType, TeamLeaves, TeamTimeSheets } from "@/app/api/timesheets"; import dayGridPlugin from "@fullcalendar/daygrid"; import interactionPlugin from "@fullcalendar/interaction"; -import { Autocomplete, Stack, TextField, useTheme } from "@mui/material"; +import { + Autocomplete, + Menu, + MenuItem, + Stack, + SxProps, + TextField, + useTheme, +} from "@mui/material"; import { useTranslation } from "react-i18next"; import transform from "lodash/transform"; import { @@ -33,6 +41,7 @@ import LeaveEditModal from "../LeaveTable/LeaveEditModal"; import dayjs from "dayjs"; import { checkTotalHours } from "@/app/api/timesheets/utils"; import unionBy from "lodash/unionBy"; +import { Luggage, MoreTime } from "@mui/icons-material"; export interface Props { leaveTypes: LeaveType[]; @@ -56,6 +65,11 @@ interface EventClickArg { }; } +const menuItemSx: SxProps = { + gap: 1, + color: "neutral.700", +}; + const TimesheetAmendment: React.FC = ({ teamTimesheets, teamLeaves, @@ -192,6 +206,32 @@ const TimesheetAmendment: React.FC = ({ setLeaveEditModalOpen(false); }, []); + // New time / leave menu + const [anchorEl, setAnchorEl] = useState(null); + const [selectedDateInfo, setSelectedDateInfo] = useState< + { dateStr: string; isHoliday: boolean } | undefined + >(); + const handleCloseActionMenu = useCallback(() => { + setAnchorEl(null); + setSelectedDateInfo(undefined); + }, []); + const openNewTimeEditModal = useCallback(() => { + openEditModal( + undefined, + selectedDateInfo?.dateStr, + selectedDateInfo?.isHoliday, + ); + setAnchorEl(null); + }, [openEditModal, selectedDateInfo]); + const openNewLeaveEditModal = useCallback(() => { + openLeaveEditModal( + undefined, + selectedDateInfo?.dateStr, + selectedDateInfo?.isHoliday, + ); + setAnchorEl(null); + }, [openLeaveEditModal, selectedDateInfo]); + // calendar related const holidays = useMemo(() => { return [ @@ -289,13 +329,17 @@ const TimesheetAmendment: React.FC = ({ ); const handleDateClick = useCallback( - (e: { dateStr: string }) => { + (e: { dateStr: string; dayEl: HTMLElement }) => { const dayJsObj = dayjs(e.dateStr); const holiday = getHolidayForDate(e.dateStr, companyHolidays); const isHoliday = holiday || dayJsObj.day() === 0 || dayJsObj.day() === 6; - openEditModal(undefined, e.dateStr, Boolean(isHoliday)); + setSelectedDateInfo({ + dateStr: e.dateStr, + isHoliday: Boolean(isHoliday), + }); + setAnchorEl(e.dayEl); }, - [companyHolidays, openEditModal], + [companyHolidays], ); const checkTotalHoursForDate = useCallback( @@ -413,6 +457,28 @@ const TimesheetAmendment: React.FC = ({ onSave={handleSaveLeave} {...leaveEditModalProps} /> + + + + {t("Enter Time")} + + + + {t("Record Leave")} + + ); }; diff --git a/src/components/TimesheetModal/TimesheetModal.tsx b/src/components/TimesheetModal/TimesheetModal.tsx index 46bedf8..23a4349 100644 --- a/src/components/TimesheetModal/TimesheetModal.tsx +++ b/src/components/TimesheetModal/TimesheetModal.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useMemo } from "react"; +import React, { useCallback, useEffect, useMemo } from "react"; import { Box, Button, @@ -82,6 +82,9 @@ const TimesheetModal: React.FC = ({ }, [defaultTimesheets]); const formProps = useForm({ defaultValues }); + useEffect(() => { + formProps.reset(defaultValues); + }, [defaultValues, formProps]); const onSubmit = useCallback>( async (data) => { diff --git a/src/components/TimesheetTable/ProjectSelect.tsx b/src/components/TimesheetTable/ProjectSelect.tsx index 8bed209..edc04db 100644 --- a/src/components/TimesheetTable/ProjectSelect.tsx +++ b/src/components/TimesheetTable/ProjectSelect.tsx @@ -18,6 +18,7 @@ interface CommonProps { assignedProjects: AssignedProject[]; error?: boolean; multiple?: boolean; + showOnlyOngoing?: boolean; } interface SingleAutocompleteProps extends CommonProps { @@ -51,6 +52,7 @@ const getGroupName = (t: TFunction, groupName: string): string => { const AutocompleteProjectSelect: React.FC = ({ allProjects, + showOnlyOngoing = true, assignedProjects, value, onProjectSelect, @@ -58,9 +60,15 @@ const AutocompleteProjectSelect: React.FC = ({ multiple, }) => { const { t } = useTranslation("home"); + const allFilteredProjects = useMemo(() => { + return showOnlyOngoing + ? allProjects.filter((p) => p.status === "On-going") + : allProjects; + }, [showOnlyOngoing, allProjects]); + const nonAssignedProjects = useMemo(() => { - return differenceBy(allProjects, assignedProjects, "id"); - }, [allProjects, assignedProjects]); + return differenceBy(allFilteredProjects, assignedProjects, "id"); + }, [allFilteredProjects, assignedProjects]); const options = useMemo(() => { return [