From 169a2ea07a0e457f0f785444a0fe54c25d19c129 Mon Sep 17 00:00:00 2001 From: AKILIMAILI CIZUNGU Innocent <51681130+Innocent-Akim@users.noreply.github.com> Date: Sat, 30 Nov 2024 21:41:01 +0200 Subject: [PATCH] Feat(timesheet): Add TimesheetDetailModal for displaying pending (#3382) * feat(timesheet): add TimesheetDetailModal for displaying pending timesheet details * fix: coderabbitai --- .../[memberId]/components/CalendarView.tsx | 2 +- .../[memberId]/components/TimesheetCard.tsx | 119 +++++++++++++++++- .../components/TimesheetDetailModal.tsx | 41 ++++++ .../[locale]/timesheet/[memberId]/page.tsx | 27 +++- apps/web/app/hooks/features/useTimesheet.ts | 3 +- .../calendar/table-time-sheet.tsx | 2 +- 6 files changed, 187 insertions(+), 7 deletions(-) create mode 100644 apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetDetailModal.tsx diff --git a/apps/web/app/[locale]/timesheet/[memberId]/components/CalendarView.tsx b/apps/web/app/[locale]/timesheet/[memberId]/components/CalendarView.tsx index ca6cd2900..584cf19df 100644 --- a/apps/web/app/[locale]/timesheet/[memberId]/components/CalendarView.tsx +++ b/apps/web/app/[locale]/timesheet/[memberId]/components/CalendarView.tsx @@ -10,7 +10,7 @@ import { EmployeeAvatar } from "./CompactTimesheetComponent"; import { formatDate } from "@/app/helpers"; import { ClockIcon } from "lucide-react"; -export function CalendarView({ data }: { data?: GroupedTimesheet[] }) { +export function CalendarView({ data, loading }: { data?: GroupedTimesheet[], loading: boolean }) { const t = useTranslations(); return (
diff --git a/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetCard.tsx b/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetCard.tsx index 131b88f61..251ce3e8a 100644 --- a/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetCard.tsx +++ b/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetCard.tsx @@ -1,9 +1,17 @@ +import { formatDate } from '@/app/helpers'; +import { DisplayTimeForTimesheet, TaskNameInfoDisplay, TotalDurationByDate, TotalTimeDisplay } from '@/lib/features'; import { clsxm } from '@app/utils'; +import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@components/ui/accordion'; +import { Badge } from '@components/ui/badge'; import { ArrowRightIcon } from 'assets/svg'; -import { Button, Card } from 'lib/components'; +import { Button, Card, statusColor } from 'lib/components'; import { useTranslations } from 'next-intl'; import { ReactNode } from 'react'; +import { EmployeeAvatar } from './CompactTimesheetComponent'; +import { useTimesheet } from '@/app/hooks/features/useTimesheet'; +import { useTimelogFilterOptions } from '@/app/hooks'; +import { TimesheetLog, TimesheetStatus } from '@/app/interfaces'; interface ITimesheetCard { title?: string; @@ -64,3 +72,112 @@ export function TimesheetCard({ ...props }: ITimesheetCard) { ) } + + + +export const TimesheetCardDetail = ({ data }: { data?: Record }) => { + + const { getStatusTimesheet, groupByDate } = useTimesheet({}); + const { timesheetGroupByDays } = useTimelogFilterOptions(); + const timesheetGroupByDate = groupByDate(data?.PENDING || []) + const t = useTranslations(); + return ( +
+ {timesheetGroupByDate.map((plan, index) => { + return
+
+
+ {timesheetGroupByDays === 'Weekly' && ( + Week {index + 1} + )} + {formatDate(plan.date)} +
+ +
+ + {Object.entries(getStatusTimesheet(plan.tasks)).map(([status, rows]) => { + return rows.length > 0 && status && + +
+
+
+
+ + {status === 'DENIED' ? 'REJECTED' : status} + + ({rows.length}) +
+ + {t('timer.TOTAL_HOURS')} + + +
+
+
+ + {rows.map((task) => ( +
+
+ +
+
+ + {task.employee.fullName} +
+ +
+ ))} +
+
+ })} +
+
+ })} +
+ ) +} diff --git a/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetDetailModal.tsx b/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetDetailModal.tsx new file mode 100644 index 000000000..d02ca47ce --- /dev/null +++ b/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetDetailModal.tsx @@ -0,0 +1,41 @@ +import { TimesheetLog, TimesheetStatus } from '@/app/interfaces'; +import { Modal } from '@/lib/components'; +import React from 'react' +import { TimesheetCardDetail } from './TimesheetCard'; +import { useTranslations } from 'next-intl'; + +export interface IAddTaskModalProps { + isOpen: boolean; + closeModal: () => void; + timesheet?: Record +} + +function TimesheetDetailModal({ closeModal, isOpen, timesheet }: IAddTaskModalProps) { + const t = useTranslations() + + return ( + +
+
+ { + timesheet?.PENDING.length === 0 ? ( +
+

{t('pages.timesheet.NO_ENTRIES_FOUND')}

+
+ ) : + } +
+
+ +
+ + ) +} + +export default TimesheetDetailModal diff --git a/apps/web/app/[locale]/timesheet/[memberId]/page.tsx b/apps/web/app/[locale]/timesheet/[memberId]/page.tsx index a90e0378a..20de348bc 100644 --- a/apps/web/app/[locale]/timesheet/[memberId]/page.tsx +++ b/apps/web/app/[locale]/timesheet/[memberId]/page.tsx @@ -22,6 +22,7 @@ import { GoSearch } from 'react-icons/go'; import { getGreeting } from '@/app/helpers'; import { useTimesheet } from '@/app/hooks/features/useTimesheet'; import { endOfDay, startOfDay } from 'date-fns'; +import TimesheetDetailModal from './components/TimesheetDetailModal'; type TimesheetViewMode = 'ListView' | 'CalendarView'; @@ -73,6 +74,13 @@ const TimeSheet = React.memo(function TimeSheetPage({ params }: { params: { memb openModal: openManualTimeModal, closeModal: closeManualTimeModal } = useModal(); + + const { + isOpen: isTimesheetDetailOpen, + openModal: openTimesheetDetail, + closeModal: closeTimesheetDetail + } = useModal(); + const username = user?.name || user?.firstName || user?.lastName || user?.username; const [timesheetNavigator, setTimesheetNavigator] = useLocalStorageState( @@ -95,6 +103,13 @@ const TimeSheet = React.memo(function TimeSheetPage({ params }: { params: { memb ); return ( <> + {isTimesheetDetailOpen + && } + } classNameIcon="bg-[#FBB650] shadow-[#fbb75095]" + onClick={() => openTimesheetDetail()} /> */}
{timesheetNavigator === 'ListView' ? ( - + ) : ( - + )}
diff --git a/apps/web/app/hooks/features/useTimesheet.ts b/apps/web/app/hooks/features/useTimesheet.ts index 4afc705b2..91e320c53 100644 --- a/apps/web/app/hooks/features/useTimesheet.ts +++ b/apps/web/app/hooks/features/useTimesheet.ts @@ -291,6 +291,7 @@ export function useTimesheet({ createTimesheet, loadingCreateTimesheet, updateTimesheet, - loadingUpdateTimesheet + loadingUpdateTimesheet, + groupByDate }; } diff --git a/apps/web/lib/features/integrations/calendar/table-time-sheet.tsx b/apps/web/lib/features/integrations/calendar/table-time-sheet.tsx index 746940e0f..2ee67b72e 100644 --- a/apps/web/lib/features/integrations/calendar/table-time-sheet.tsx +++ b/apps/web/lib/features/integrations/calendar/table-time-sheet.tsx @@ -584,7 +584,7 @@ export const StatusTask = ({ timesheet }: { timesheet: TimesheetLog }) => { ); }; -const getBadgeColor = (timesheetStatus: TimesheetStatus | null) => { +export const getBadgeColor = (timesheetStatus: TimesheetStatus | null) => { switch (timesheetStatus) { case 'DRAFT': return 'bg-gray-300';