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}