diff --git a/.cspell.json b/.cspell.json index eb482a503..a650d982e 100644 --- a/.cspell.json +++ b/.cspell.json @@ -110,6 +110,7 @@ "deserunt", "digitaloceanspaces", "dimesions", + "Ipredefine", "discrepenancy", "dolor", "dolore", diff --git a/apps/web/app/[locale]/dashboard/team-dashboard/[teamId]/components/date-range-picker.tsx b/apps/web/app/[locale]/dashboard/team-dashboard/[teamId]/components/date-range-picker.tsx index 842649d82..25ed7cbc0 100644 --- a/apps/web/app/[locale]/dashboard/team-dashboard/[teamId]/components/date-range-picker.tsx +++ b/apps/web/app/[locale]/dashboard/team-dashboard/[teamId]/components/date-range-picker.tsx @@ -23,6 +23,7 @@ import { import { DateRange } from 'react-day-picker'; import { useTranslations } from 'next-intl'; import { SettingsIcon } from './team-icon'; +import { TranslationHooks } from 'next-intl'; import { CalendarIcon } from '@radix-ui/react-icons'; interface DateRangePickerProps { @@ -51,100 +52,6 @@ export function DateRangePicker({ className, onDateRangeChange }: DateRangePicke } }; - const predefinedRanges = [ - { - label: t('common.TODAY'), - action: () => { - const today = new Date(); - handleDateRangeChange({ from: today, to: today }); - }, - isSelected: (range: DateRange | undefined) => { - if (!range?.from || !range?.to) return false; - const today = new Date(); - return isEqual(range.from, today) && isEqual(range.to, today); - } - }, - { - label: t('common.YESTERDAY'), - action: () => { - const yesterday = subDays(new Date(), 1); - handleDateRangeChange({ from: yesterday, to: yesterday }); - }, - isSelected: (range: DateRange | undefined) => { - if (!range?.from || !range?.to) return false; - const yesterday = subDays(new Date(), 1); - return isEqual(range.from, yesterday) && isEqual(range.to, yesterday); - } - }, - { - label: t('common.THIS_WEEK'), - action: () => { - const today = new Date(); - handleDateRangeChange({ - from: startOfWeek(today, { weekStartsOn: 1 }), - to: endOfWeek(today, { weekStartsOn: 1 }) - }); - }, - isSelected: (range: DateRange | undefined) => { - if (!range?.from || !range?.to) return false; - const today = new Date(); - const weekStart = startOfWeek(today, { weekStartsOn: 1 }); - const weekEnd = endOfWeek(today, { weekStartsOn: 1 }); - return isEqual(range.from, weekStart) && isEqual(range.to, weekEnd); - } - }, - { - label: t('common.LAST_WEEK'), - action: () => { - const lastWeek = subWeeks(new Date(), 1); - handleDateRangeChange({ - from: startOfWeek(lastWeek, { weekStartsOn: 1 }), - to: endOfWeek(lastWeek, { weekStartsOn: 1 }) - }); - }, - isSelected: (range: DateRange | undefined) => { - if (!range?.from || !range?.to) return false; - const lastWeek = subWeeks(new Date(), 1); - const weekStart = startOfWeek(lastWeek, { weekStartsOn: 1 }); - const weekEnd = endOfWeek(lastWeek, { weekStartsOn: 1 }); - return isEqual(range.from, weekStart) && isEqual(range.to, weekEnd); - } - }, - { - label: t('common.THIS_MONTH'), - action: () => { - const today = new Date(); - handleDateRangeChange({ - from: startOfMonth(today), - to: endOfMonth(today) - }); - }, - isSelected: (range: DateRange | undefined) => { - if (!range?.from || !range?.to) return false; - const today = new Date(); - const monthStart = startOfMonth(today); - const monthEnd = endOfMonth(today); - return isEqual(range.from, monthStart) && isEqual(range.to, monthEnd); - } - }, - { - label: t('common.LAST_MONTH'), - action: () => { - const lastMonth = subMonths(new Date(), 1); - handleDateRangeChange({ - from: startOfMonth(lastMonth), - to: endOfMonth(lastMonth) - }); - }, - isSelected: (range: DateRange | undefined) => { - if (!range?.from || !range?.to) return false; - const lastMonth = subMonths(new Date(), 1); - const monthStart = startOfMonth(lastMonth); - const monthEnd = endOfMonth(lastMonth); - return isEqual(range.from, monthStart) && isEqual(range.to, monthEnd); - } - } - ]; const formatDateRange = (range: DateRange) => { if (!range.from) return 'Select date range'; @@ -219,23 +126,8 @@ export function DateRangePicker({ className, onDateRangeChange }: DateRangePicke disabled={(date) => date >= startOfDay(new Date())} /> -
- {predefinedRanges.map((range) => ( - - ))} +
+
@@ -262,3 +154,124 @@ export function DateRangePicker({ className, onDateRangeChange }: DateRangePicke ); } +interface PredefinedRangeProps { + handleDateRangeChange: (range: DateRange | undefined) => void; + t: TranslationHooks; + dateRange: DateRange | undefined; +} + +type DateRangeGetter = () => { from: Date; to: Date }; + +const createRangeHelper = (handleDateRangeChange: (range: DateRange | undefined) => void) => { + return (getRange: DateRangeGetter) => { + const range = getRange(); + return { + action: () => { + const newRange = { + from: new Date(range.from), + to: new Date(range.to) + }; + handleDateRangeChange(newRange); + }, + isSelected: (currentRange: DateRange | undefined) => { + if (!currentRange?.from || !currentRange?.to) return false; + return isEqual( + startOfDay(currentRange.from), + startOfDay(range.from) + ) && isEqual( + startOfDay(currentRange.to), + startOfDay(range.to) + ); + } + }; + }; +}; + +const PredefinedRanges = ({ handleDateRangeChange, t, dateRange }: PredefinedRangeProps) => { + const weekOptions = { weekStartsOn: 1 as const }; + + const createRange = React.useMemo( + () => createRangeHelper(handleDateRangeChange), + [handleDateRangeChange] + ); + + const predefinedRanges = React.useMemo( + () => [ + { + label: t('common.TODAY'), + ...createRange(() => { + const today = new Date(); + return { from: today, to: today }; + }) + }, + { + label: t('common.YESTERDAY'), + ...createRange(() => { + const yesterday = subDays(new Date(), 1); + return { from: yesterday, to: yesterday }; + }) + }, + { + label: t('common.THIS_WEEK'), + ...createRange(() => { + const today = new Date(); + return { + from: startOfWeek(today, weekOptions), + to: endOfWeek(today, weekOptions) + }; + }) + }, + { + label: t('common.LAST_WEEK'), + ...createRange(() => { + const lastWeek = subWeeks(new Date(), 1); + return { + from: startOfWeek(lastWeek, weekOptions), + to: endOfWeek(lastWeek, weekOptions) + }; + }) + }, + { + label: t('common.THIS_MONTH'), + ...createRange(() => { + const today = new Date(); + return { + from: startOfMonth(today), + to: endOfMonth(today) + }; + }) + }, + { + label: t('common.LAST_MONTH'), + ...createRange(() => { + const lastMonth = subMonths(new Date(), 1); + return { + from: startOfMonth(lastMonth), + to: endOfMonth(lastMonth) + }; + }) + } + ], + [createRange, t] + ); + + return ( +
+ {predefinedRanges.map((range) => ( + + ))} +
+ ); +}; diff --git a/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetDetailModal.tsx b/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetDetailModal.tsx index 33b3eeb05..f4f6c7e75 100644 --- a/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetDetailModal.tsx +++ b/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetDetailModal.tsx @@ -38,7 +38,7 @@ function TimesheetDetailModal({ closeModal, isOpen, timesheet, timesheetDetailMo showCloseIcon className="bg-light--theme-light dark:bg-dark--theme-light p-5 rounded w-full md:w-40 md:min-w-[35rem]" titleClass="font-bold flex justify-start w-full text-xl"> -
+
{(() => { switch (timesheetDetailMode) { @@ -89,13 +89,13 @@ const MembersWorkedCard = ({ element, t }: { element: TimesheetLog[], t: Transla
-
- +
+ {timesheet.element[0].employee.fullName}
-
+
-
+
{status === 'DENIED' ? 'REJECTED' : status} @@ -150,7 +150,7 @@ const MembersWorkedCard = ({ element, t }: { element: TimesheetLog[], t: Transla borderBottomColor: statusColor(status).bg }} className={cn( - 'flex items-center border-b border-b-gray-200 dark:border-b-gray-600 space-x-4 p-1 h-[60px]' + 'flex items-center p-1 space-x-4 border-b border-b-gray-200 dark:border-b-gray-600 h-[60px]' )} >
-
+
{items.project?.imageUrl && } {items.project?.name}
@@ -218,11 +218,11 @@ const MenHoursCard = ({ element, t }: MenHoursCardProps) => { style={{ backgroundColor: statusColor(timesheet.element[0].timesheet.status).bgOpacity }} type="button" className={cn( - 'flex flex-row-reverse justify-end items-center w-full h-[50px] rounded-sm gap-x-2 hover:no-underline px-2', + 'flex flex-row-reverse gap-x-2 justify-end items-center px-2 w-full rounded-sm h-[50px] hover:no-underline', )}>
-
+
{timesheet.element[0].timesheet.status === 'DENIED' ? 'REJECTED' : timesheet.element[0].timesheet.status}
@@ -249,10 +249,10 @@ const MenHoursCard = ({ element, t }: MenHoursCardProps) => { 'flex flex-row-reverse justify-end items-center w-full h-[50px] rounded-sm gap-x-2 hover:no-underline px-2', statusColor(status).text )}> -
+
-
+
{status === 'DENIED' ? 'REJECTED' : status} @@ -278,7 +278,7 @@ const MenHoursCard = ({ element, t }: MenHoursCardProps) => { borderBottomColor: statusColor(status).bg }} className={cn( - 'flex items-center border-b border-b-gray-200 dark:border-b-gray-600 space-x-4 p-1 h-[60px]' + 'flex items-center p-1 space-x-4 border-b border-b-gray-200 dark:border-b-gray-600 h-[60px]' )} >
{ taskNumberClassName="text-sm" />
-
+
{items.project?.imageUrl && } {items.project?.name}