Skip to content

Commit

Permalink
Merge pull request #3397 from ever-co/feat/integrate-translations-wit…
Browse files Browse the repository at this point in the history
…h-buttons

[Feat]: handle February (28/29 days) in calendar and integrate task label translations, update button logic
  • Loading branch information
evereq authored Dec 8, 2024
2 parents 3b7409d + f2f6f3b commit b8bbf86
Show file tree
Hide file tree
Showing 19 changed files with 147 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import MonthlyTimesheetCalendar from "./MonthlyTimesheetCalendar";
import { useTimelogFilterOptions } from "@/app/hooks";
import WeeklyTimesheetCalendar from "./WeeklyTimesheetCalendar";
interface BaseCalendarDataViewProps {
t: TranslationHooks
data: GroupedTimesheet[];
daysLabels?: string[];
CalendarComponent: typeof MonthlyTimesheetCalendar | typeof WeeklyTimesheetCalendar;
Expand All @@ -35,9 +36,9 @@ export function CalendarView({ data, loading }: { data?: GroupedTimesheet[], loa
data.length > 0 ? (
<>
{timesheetGroupByDays === 'Monthly' ? (
<MonthlyCalendarDataView data={data} daysLabels={defaultDaysLabels} />
<MonthlyCalendarDataView data={data} daysLabels={defaultDaysLabels} t={t} />
) : timesheetGroupByDays === 'Weekly' ? (
<WeeklyCalendarDataView data={data} daysLabels={defaultDaysLabels} />
<WeeklyCalendarDataView data={data} daysLabels={defaultDaysLabels} t={t} />
) : (
<CalendarDataView data={data} t={t} />
)}
Expand Down Expand Up @@ -99,7 +100,7 @@ const CalendarDataView = ({ data, t }: { data?: GroupedTimesheet[], t: Translati
<div className="flex items-center w-full gap-2">
<div className={cn('p-2 rounded', statusColor(status).bg)}></div>
<div className="flex items-center gap-x-1">
<span className="text-base font-normal text-gray-400 uppercase text-[12px]">
<span className="text-base font-normal text-gray-400 uppercase !text-[12px]">
{status === 'DENIED' ? 'REJECTED' : status}
</span>
<span className="text-gray-400 text-[14px]">({rows.length})</span>
Expand Down Expand Up @@ -166,10 +167,11 @@ const CalendarDataView = ({ data, t }: { data?: GroupedTimesheet[], t: Translati
)
}

const BaseCalendarDataView = ({ data, daysLabels, CalendarComponent }: BaseCalendarDataViewProps) => {
const BaseCalendarDataView = ({ data, daysLabels, t, CalendarComponent }: BaseCalendarDataViewProps) => {
const { getStatusTimesheet } = useTimesheet({});
return (
<CalendarComponent
t={t}
data={data}
// locale={ }
daysLabels={daysLabels}
Expand All @@ -185,17 +187,17 @@ const BaseCalendarDataView = ({ data, daysLabels, CalendarComponent }: BaseCalen
<AccordionTrigger
type="button"
className={cn(
'flex flex-row-reverse justify-end items-center w-full !h-[20px] rounded-sm gap-x-2 hover:no-underline',
'flex flex-row-reverse justify-end items-center w-full !h-[16px] rounded-sm gap-x-2 hover:no-underline',
statusColor(status).text
)}>
<div className="flex items-center justify-between space-x-1 w-full">
<div className="flex items-center w-full gap-2">
<div className={cn('p-2 rounded', statusColor(status).bg)}></div>
<div className="flex items-center gap-x-1">
<span className="text-base font-normal text-gray-400 uppercase text-[12px]">
<span className="text-base font-normal text-gray-400 uppercase !text-[13px]">
{status === 'DENIED' ? 'REJECTED' : status}
</span>
<span className="text-gray-400 text-[12px]">({rows.length})</span>
<span className="text-gray-400 text-[13px]">({rows.length})</span>
</div>
</div>
<div className="flex items-center space-x-2">
Expand Down Expand Up @@ -262,10 +264,10 @@ const BaseCalendarDataView = ({ data, daysLabels, CalendarComponent }: BaseCalen
);
};

const MonthlyCalendarDataView = (props: { data: GroupedTimesheet[], daysLabels?: string[] }) => (
const MonthlyCalendarDataView = (props: { data: GroupedTimesheet[], t: TranslationHooks, daysLabels?: string[] }) => (
<BaseCalendarDataView {...props} CalendarComponent={MonthlyTimesheetCalendar} />
);

const WeeklyCalendarDataView = (props: { data: GroupedTimesheet[], daysLabels?: string[] }) => (
const WeeklyCalendarDataView = (props: { data: GroupedTimesheet[], t: TranslationHooks, daysLabels?: string[] }) => (
<BaseCalendarDataView {...props} CalendarComponent={WeeklyTimesheetCalendar} />
);
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React, { HTMLAttributes } from 'react';
import { Button } from 'lib/components';
import { clsxm } from '@app/utils';
import { TimesheetLog, TimesheetStatus } from '@/app/interfaces';
import { useTranslations } from 'next-intl';

export type FilterStatus = 'All Tasks' | 'Pending' | 'Approved' | 'In review' | 'Draft' | 'Rejected';
export function FilterWithStatus({
Expand All @@ -17,6 +18,7 @@ export function FilterWithStatus({
onToggle: (status: FilterStatus) => void;
className?: HTMLAttributes<HTMLDivElement>;
}>) {
const t = useTranslations();

const statusIcons: Record<FilterStatus, string> = {
'All Tasks': 'icon-all',
Expand All @@ -29,12 +31,12 @@ export function FilterWithStatus({

const buttonData = React.useMemo(() => {
const counts = {
'All Tasks': Object.values(data ?? {}).reduce((total, tasks) => total + (tasks?.length ?? 0), 0),
Pending: data?.PENDING?.length ?? 0,
Approved: data?.APPROVED?.length ?? 0,
'In review': data?.['IN REVIEW']?.length ?? 0,
Draft: data?.DRAFT?.length ?? 0,
Rejected: data?.DENIED?.length ?? 0,
[t('pages.timesheet.ALL_TASKS')]: Object.values(data ?? {}).reduce((total, tasks) => total + (tasks?.length ?? 0), 0),
[t('pages.timesheet.PENDING')]: data?.PENDING?.length ?? 0,
[t('pages.timesheet.APPROVED')]: data?.APPROVED?.length ?? 0,
[t('pages.timesheet.IN_REVIEW')]: data?.['IN REVIEW']?.length ?? 0,
[t('pages.timesheet.DRAFT')]: data?.DRAFT?.length ?? 0,
[t('pages.timesheet.REJECTED')]: data?.DENIED?.length ?? 0,
};
return Object.entries(counts).map(([label, count]) => ({
label: label as FilterStatus,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import React, { useMemo, useState, useCallback } from "react";
import { format, addMonths, eachDayOfInterval, startOfMonth, endOfMonth, addDays, Locale } from "date-fns";
import { format, addMonths, eachDayOfInterval, startOfMonth, endOfMonth, addDays, Locale, isLeapYear } from "date-fns";
import { GroupedTimesheet } from "@/app/hooks/features/useTimesheet";
import { enGB } from 'date-fns/locale';
import { cn } from "@/lib/utils";
import { TotalDurationByDate } from "@/lib/features";
import { formatDate } from "@/app/helpers";
import { TranslationHooks } from "next-intl";

type MonthlyCalendarDataViewProps = {
t: TranslationHooks
data?: GroupedTimesheet[];
onDateClick?: (date: Date) => void;
renderDayContent?: (date: Date, plan?: GroupedTimesheet) => React.ReactNode;
Expand All @@ -26,7 +28,14 @@ const defaultDaysLabels = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];

const generateFullCalendar = (currentMonth: Date) => {
const monthStart = startOfMonth(currentMonth);
const monthEnd = endOfMonth(currentMonth);
const monthEnd = (() => {
const month = monthStart.getMonth();
if (month === 1) {
const year = monthStart.getFullYear();
return new Date(year, 1, isLeapYear(monthStart) ? 29 : 28);
}
return endOfMonth(monthStart);
})();
const startDate = addDays(monthStart, -monthStart.getDay());
const endDate = addDays(monthEnd, 6 - monthEnd.getDay());
return eachDayOfInterval({ start: startDate, end: endDate });
Expand All @@ -40,7 +49,8 @@ const MonthlyTimesheetCalendar: React.FC<MonthlyCalendarDataViewProps> = ({
locale = enGB,
daysLabels = defaultDaysLabels,
noDataText = "No Data",
classNames = {}
classNames = {},
t
}) => {
const [currentMonth, setCurrentMonth] = useState(new Date());
const calendarDates = useMemo(() => generateFullCalendar(currentMonth), [currentMonth]);
Expand All @@ -60,7 +70,7 @@ const MonthlyTimesheetCalendar: React.FC<MonthlyCalendarDataViewProps> = ({
onClick={handlePreviousMonth}
className="px-4 py-2 bg-gray-200 rounded hover:bg-gray-300 dark:bg-primary-light hover:dark:bg-primary-light"
>
Previous
{t('common.PREV')}
</button>
<h2 className="text-xl font-bold">
{format(currentMonth, "MMMM yyyy", { locale: locale })}
Expand All @@ -69,7 +79,7 @@ const MonthlyTimesheetCalendar: React.FC<MonthlyCalendarDataViewProps> = ({
onClick={handleNextMonth}
className="px-4 py-2 bg-gray-200 dark:bg-primary-light rounded hover:bg-gray-300 hover:dark:bg-primary-light"
>
Next
{t('common.NEXT')}
</button>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { MultiSelect } from 'lib/components/custom-select';
import { Popover, PopoverContent, PopoverTrigger } from '@components/ui/popover';
import { SettingFilterIcon } from '@/assets/svg';
import { useTranslations } from 'next-intl';
import { clsxm } from '@/app/utils';
import { useTimelogFilterOptions } from '@/app/hooks';
import { useTimesheet } from '@/app/hooks/features/useTimesheet';
import { cn } from '@/lib/utils';

export const TimeSheetFilterPopover = React.memo(function TimeSheetFilterPopover() {
const [shouldRemoveItems, setShouldRemoveItems] = React.useState(false);
Expand Down Expand Up @@ -61,7 +61,7 @@ export const TimeSheetFilterPopover = React.memo(function TimeSheetFilterPopover
<label className="flex justify-between mb-1 text-sm text-gray-600">
<span className="text-[12px]">{t('manualTime.EMPLOYEE')}</span>
<span
className={clsxm(
className={cn(
'text-primary/10',
employee?.length > 0 && 'text-primary dark:text-primary-light'
)}
Expand All @@ -84,7 +84,7 @@ export const TimeSheetFilterPopover = React.memo(function TimeSheetFilterPopover
<label className="flex justify-between mb-1 text-sm text-gray-600">
<span className="text-[12px]">{t('sidebar.PROJECTS')}</span>
<span
className={clsxm(
className={cn(
'text-primary/10',
project?.length > 0 && 'text-primary dark:text-primary-light'
)}
Expand All @@ -109,7 +109,7 @@ export const TimeSheetFilterPopover = React.memo(function TimeSheetFilterPopover
<label className="flex justify-between mb-1 text-sm text-gray-600">
<span className="text-[12px]">{t('hotkeys.TASK')}</span>
<span
className={clsxm(
className={cn(
'text-primary/10',
task?.length > 0 && 'text-primary dark:text-primary-light'
)}
Expand All @@ -132,7 +132,7 @@ export const TimeSheetFilterPopover = React.memo(function TimeSheetFilterPopover
<label className="flex justify-between mb-1 text-sm text-gray-600">
<span className="text-[12px]">{t('common.STATUS')}</span>
<span
className={clsxm(
className={cn(
'text-primary/10',
statusState && 'text-primary dark:text-primary-light'
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@

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';
Expand All @@ -12,6 +11,7 @@ import { EmployeeAvatar } from './CompactTimesheetComponent';
import { useTimesheet } from '@/app/hooks/features/useTimesheet';
import { useTimelogFilterOptions } from '@/app/hooks';
import { TimesheetLog, TimesheetStatus } from '@/app/interfaces';
import { cn } from '@/lib/utils';

interface ITimesheetCard {
title?: string;
Expand Down Expand Up @@ -42,7 +42,7 @@ export function TimesheetCard({ ...props }: ITimesheetCard) {
</div>
<Button
variant='outline'
className={clsxm(
className={cn(
'h-9 px-3 py-2',
'border border-gray-200 ',
'text-[#282048] text-sm',
Expand All @@ -52,14 +52,14 @@ export function TimesheetCard({ ...props }: ITimesheetCard) {
aria-label="View timesheet details"
onClick={onClick}>
<span>{t('pages.timesheet.TIMESHEET_VIEW_DETAILS')}</span>
<ArrowRightIcon className={clsxm(
<ArrowRightIcon className={cn(
'h-6 w-6',
'text-[#282048] dark:text-[#6b7280]'
)} />
</Button>
</div>
<div
className={clsxm(
className={cn(
'h-16 w-16 rounded-lg p-5',
'flex items-center justify-center',
'text-white font-bold text-sm',
Expand All @@ -86,7 +86,7 @@ export const TimesheetCardDetail = ({ data }: { data?: Record<TimesheetStatus, T
{timesheetGroupByDate.map((plan, index) => {
return <div key={index}>
<div
className={clsxm(
className={cn(
'h-[48px] flex justify-between items-center w-full',
'bg-[#ffffffcc] dark:bg-dark--theme rounded-md border-1',
'border-gray-400 px-5 text-[#71717A] font-medium'
Expand All @@ -107,19 +107,19 @@ export const TimesheetCardDetail = ({ data }: { data?: Record<TimesheetStatus, T
return rows.length > 0 && status && <AccordionItem
key={status}
value={status === 'DENIED' ? 'REJECTED' : status}
className={clsxm("p-1 rounded")}
className={cn("p-1 rounded")}
>
<AccordionTrigger
style={{ backgroundColor: statusColor(status).bgOpacity }}
type="button"
className={clsxm(
className={cn(
'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
)}
>
<div className="flex items-center justify-between w-full space-x-1">
<div className="flex items-center space-x-1">
<div className={clsxm('p-2 rounded', statusColor(status).bg)}></div>
<div className={cn('p-2 rounded', statusColor(status).bg)}></div>
<div className="flex items-center gap-x-1">
<span className="text-base font-normal text-gray-400 uppercase">
{status === 'DENIED' ? 'REJECTED' : status}
Expand All @@ -144,17 +144,17 @@ export const TimesheetCardDetail = ({ data }: { data?: Record<TimesheetStatus, T
backgroundColor: statusColor(status).bgOpacity,
borderBottomColor: statusColor(status).bg
}}
className={clsxm(
className={cn(
'flex items-center border-b border-b-gray-200 dark:border-b-gray-600 space-x-4 p-1 h-[60px]'
)}>
<div className="flex-[2]">
<TaskNameInfoDisplay
task={task.task}
className={clsxm(
className={cn(
'shadow-[0px_0px_15px_0px_#e2e8f0] dark:shadow-transparent'
)}
taskTitleClassName={clsxm(
'text-sm text-ellipsis overflow-hidden text-sm'
taskTitleClassName={cn(
'text-sm !text-ellipsis !overflow-hidden text-sm'
)}
showSize={false}
dash
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import { cn } from "@/lib/utils";
import { GroupedTimesheet } from "@/app/hooks/features/useTimesheet";
import { TotalDurationByDate } from "@/lib/features";
import { formatDate } from "@/app/helpers";
import { TranslationHooks } from "next-intl";

type WeeklyCalendarProps = {
t: TranslationHooks
data?: GroupedTimesheet[];
onDateClick?: (date: Date) => void;
renderDayContent?: (date: Date, plan?: GroupedTimesheet) => React.ReactNode;
Expand Down Expand Up @@ -38,6 +40,7 @@ const WeeklyTimesheetCalendar: React.FC<WeeklyCalendarProps> = ({
daysLabels = defaultDaysLabels,
noDataText = "No Data",
classNames = {},
t
}) => {
const [currentDate, setCurrentDate] = useState(new Date());

Expand All @@ -61,7 +64,7 @@ const WeeklyTimesheetCalendar: React.FC<WeeklyCalendarProps> = ({
onClick={handlePreviousWeek}
className="px-4 py-2 bg-gray-200 rounded hover:bg-gray-300 dark:bg-primary-light hover:dark:bg-primary-light"
>
Previous
{t('common.PREV')}
</button>
<h2 className="text-xl font-bold">
{`Week of ${format(weekDates[0], "MMM d", { locale })} - ${format(
Expand All @@ -74,7 +77,7 @@ const WeeklyTimesheetCalendar: React.FC<WeeklyCalendarProps> = ({
onClick={handleNextWeek}
className="px-4 py-2 bg-gray-200 dark:bg-primary-light rounded hover:bg-gray-300 hover:dark:bg-primary-light"
>
Next
{t('common.NEXT')}
</button>
</div>

Expand Down
Loading

0 comments on commit b8bbf86

Please sign in to comment.