Skip to content

Commit

Permalink
[Feat]: DataTableTimeSheet and SelectFilter components for improved a…
Browse files Browse the repository at this point in the history
…nd status management (#3223)

* feat: Refactor DataTableTimeSheet and SelectFilter components for improved readability and status management

* fix: resolve

* fix: resolve

* feat: enhance timesheet component
  • Loading branch information
Innocent-Akim authored Nov 2, 2024
1 parent df0452e commit 4f30b12
Show file tree
Hide file tree
Showing 21 changed files with 658 additions and 357 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ export function FilterWithStatus({
key={index}
className={clsxm(
'group flex items-center justify-start h-[2.2rem] rounded-xl border w-full',
'dark:bg-dark--theme-light dark:border-gray-700 bg-[#e2e8f0aa] text[#71717A] w-[80px]',
'dark:bg-dark--theme-light dark:border-gray-700 bg-transparent text[#71717A] w-[80px]',
activeStatus === label && 'text-primary bg-white shadow-lg font-bold'
)}
onClick={() => onToggle(label)}>
<span className={clsxm('font-medium ml-1 text-[#71717A]', `${activeStatus === label ? "text-primary" : ""}`)}>{label}</span>
<span className={clsxm('font-medium ml-1 text-[#7E7991]', `${activeStatus === label ? "text-primary" : ""}`)}>{label}</span>
<span className='font-medium ml-1 text-[#71717A]'>{count}</span>
</Button>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export function FrequencySelect() {
<Select
value={selectedValue}
onValueChange={handleSelectChange}>
<SelectTrigger className="w-[170px] border border-gray-200 dark:border-gray-700 bg-white dark:bg-dark--theme-light focus:ring-2 focus:ring-transparent">
<SelectTrigger className="w-[170px] overflow-hidden text-clip border border-gray-200 dark:border-gray-700 bg-white dark:bg-dark--theme-light focus:ring-2 focus:ring-transparent">
<SelectValue placeholder="Select a daily" />
</SelectTrigger>
<SelectContent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ export function TimeSheetFilterPopover() {
</PopoverTrigger>
<PopoverContent className="w-96">
<div className="w-full flex flex-col">
<div className="flex mb-3 text-xl font-bold gap-2">
<SettingFilterIcon className="text-gray-700 dark:text-white w-4" strokeWidth="1.8" />
<span className="text-gray-700 dark:text-white">Filters</span>
</div>
<div className="grid gap-5">
<div className="">
<label className="flex justify-between text-gray-600 mb-1 text-sm">
Expand Down Expand Up @@ -83,14 +87,14 @@ export function TimeSheetFilterPopover() {
triggerClassName="dark:border-gray-700"
/>
</div>
<div className="flex items-center justify-between gap-x-4 w-full">
<div className="flex items-center justify-end gap-x-4 w-full">
<Button
variant={'outline'}
className='flex items-center text-sm justify-center h-10 w-full rounded-lg dark:text-gray-300' >
className='flex items-center text-sm justify-center h-10 rounded-lg dark:text-gray-300' >
<span className="text-sm">Clear Filter</span>
</Button>
<Button
className='flex items-center text-sm justify-center h-10 w-full rounded-lg bg-primary dark:bg-primary-light dark:text-gray-300' >
className='flex items-center text-sm justify-center h-10 rounded-lg bg-primary dark:bg-primary-light dark:text-gray-300' >
<span className="text-sm">Apply Filter</span>
</Button>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { clsxm } from "@/app/utils";
import { ReactNode } from "react";
import { FaClipboardCheck } from "react-icons/fa6";
import { IoClose } from "react-icons/io5";
import { RiDeleteBin6Fill } from "react-icons/ri";
type ITimesheetButton = {
title?: string,
onClick?: () => void,
className?: string,
icon?: ReactNode

}
export const TimesheetButton = ({ className, icon, onClick, title }: ITimesheetButton) => {
return (
<button onClick={onClick} className={clsxm("flex items-center gap-1 text-gray-400 font-normal leading-3", className)}>
<div className="w-[16px] h-[16px] text-[#293241]">
{icon}
</div>
<span>{title}</span>
</button>
)
}


export type StatusType = "Pending" | "Approved" | "Rejected";

// eslint-disable-next-line @typescript-eslint/no-empty-function
export const getTimesheetButtons = (status: StatusType) => {
const buttonsConfig: Record<StatusType, { icon: JSX.Element; title: string }[]> = {
Pending: [
{ icon: <FaClipboardCheck className="!text-[#2932417c] rounded" />, title: "Approve Selected" },
{ icon: <IoClose className="!bg-[#2932417c] rounded" />, title: "Reject Selected" },
{ icon: <RiDeleteBin6Fill className="!text-[#2932417c] rounded" />, title: "Delete Selected" }
],
Approved: [
{ icon: <IoClose className="!bg-[#2932417c] rounded" />, title: "Reject Selected" },
{ icon: <RiDeleteBin6Fill className="!text-[#2932417c] rounded" />, title: "Delete Selected" }
],
Rejected: [
{ icon: <FaClipboardCheck className="!text-[#2932417c] rounded" />, title: "Approve Selected" },
{ icon: <RiDeleteBin6Fill className="!text-[#2932417c] rounded" />, title: "Delete Selected" }
]
};

return (buttonsConfig[status] || buttonsConfig.Rejected).map((button, index) => (
<TimesheetButton
key={index}
icon={button.icon}
onClick={() => {
// TODO: Implement the onClick functionality
}}
title={button.title}
/>
));
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { FilterWithStatus } from './FilterWithStatus';
import { FrequencySelect, TimesheetFilterDate } from '.';
import { FrequencySelect, TimeSheetFilterPopover, TimesheetFilterDate } from '.';
import { Button } from 'lib/components';
import { SettingFilterIcon } from '@/assets/svg';

export function TimesheetFilter() {
return (
Expand All @@ -18,17 +17,12 @@ export function TimesheetFilter() {
<div className="col-span-1">
<div className='flex gap-2'>
<FrequencySelect />
<button
onClick={() => null}
className='flex items-center justify-center h-10 rounded-lg bg-white dark:bg-dark--theme-light border dark:border-gray-700 hover:bg-white p-3 gap-2' >
<SettingFilterIcon className="text-gray-700 dark:text-white w-3.5" strokeWidth="1.8" />
<span className="text-gray-700 dark:text-white">Filter</span>
</button>
<TimesheetFilterDate />
<TimeSheetFilterPopover />
<Button
onClick={() => null}
variant='outline'
className='bg-primary/5 dark:bg-primary-light h-10 w-[2.5rem] font-medium'>
className='bg-primary/5 dark:bg-primary-light h-10 font-medium'>
Add Time
</Button>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
} from "@components/ui/popover"
import { CalendarIcon } from "@radix-ui/react-icons"
import { format } from "date-fns"
import React from "react"
import React, { useState } from "react"
import { MdKeyboardArrowRight } from "react-icons/md"
import { PiCalendarDotsThin } from "react-icons/pi"

Expand All @@ -34,7 +34,7 @@ export function TimesheetFilterDate({
from: initialRange?.from ?? new Date(),
to: initialRange?.to ?? new Date(),
});

const [isVisible, setIsVisible] = useState(false)
const handleFromChange = (fromDate: Date | null) => {
if (maxDate && fromDate && fromDate > maxDate) {
return;
Expand Down Expand Up @@ -92,34 +92,57 @@ export function TimesheetFilterDate({
aria-label="Select date range"
aria-expanded="false"
className={cn(
"w-[240px] justify-start text-left font-normal",
"w-[240px] justify-start text-left font-normal overflow-hidden text-clip",
!dateRange.from && "text-muted-foreground"
)}>
<CalendarIcon />
{dateRange.from ? format(dateRange.from, "PPP") : <span>Pick a date</span>}
{dateRange.from ? (
dateRange.to ? (
<>
{format(dateRange.from, "LLL d")}-{format(dateRange.to, "d, yyyy")}
</>
) : (
format(dateRange.from, "LLL d, yyyy")
)
) : (
<span>Pick a date</span>
)}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0 flex">
<div className="flex flex-col p-2 gap-2">
<DatePickerFilter
label="From"
date={dateRange.from}
setDate={handleFromChange}
/>
<DatePickerFilter
label="To"
date={dateRange.to}
setDate={handleToChange}
minDate={dateRange.from}
/>
</div>
{isVisible && (
<div className="flex flex-col p-2 gap-2 translate-x-0 justify-between">
<div className="flex flex-col gap-2">
<DatePickerFilter
label="From"
date={dateRange.from}
setDate={handleFromChange}
/>
<DatePickerFilter
label="To"
date={dateRange.to}
setDate={handleToChange}
minDate={dateRange.from}
/>
</div>
<div className="flex w-full justify-end items-end">
<Button variant={'outline'} className="h-4 border-none text-primary hover:bg-transparent hover:text-primary hover:underline">Cancel</Button>
<Button variant={'outline'} className="h-4 border-none text-primary hover:bg-transparent hover:text-primary hover:underline">Apply</Button>
</div>
</div>
)
}
<div className="border border-slate-100 my-1"></div>
<div className="flex flex-col p-2">
{["Today", "Last 7 days", "Last 30 days", `This year (${new Date().getFullYear()})`, "Custom Date Range"].map((label, index) => (
<Button
key={index}
variant="outline"
className="h-7 flex items-center justify-between border-none text-[12px] text-gray-700"
onClick={() => handlePresetClick(label)}>
onClick={() => {
label === 'Custom Date Range' && setIsVisible((prev) => !prev)
handlePresetClick(label)
}}>
<span> {label}</span>
{label === 'Custom Date Range' && <MdKeyboardArrowRight />}
</Button>
Expand Down Expand Up @@ -185,7 +208,9 @@ export function DatePickerFilter({
}
}}
modifiersClassNames={{
disabled: 'text-gray-300 cursor-not-allowed',
disabled: 'text-[#6989AA] cursor-not-allowed',
selected: '!rounded-full bg-primary text-white',
today: '!rounded-full bg-[#BCCAD9] text-white'
}}
disabled={[
...(minDate ? [{ before: minDate }] : []),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { IDailyPlan } from '@/app/interfaces'
import { DataTableTimeSheet } from 'lib/features/integrations/calendar'

export function TimesheetView() {
export function TimesheetView({ data }: { data?: IDailyPlan[] }) {
return (
<div className='grow h-full w-full bg-[#FFFFFF]'>
<DataTableTimeSheet />
<DataTableTimeSheet data={data} />
</div>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ export * from './TimesheetFilter';
export * from './FrequencySelect';
export * from './FilterWithStatus';
export * from './TimesheetFilterDate';
export * from './TimeSheetFilterPopover'
export * from './TimesheetAction'
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useTranslations } from 'next-intl';
import { withAuthentication } from 'lib/app/authenticator';
import { Breadcrumb, Container, Divider } from 'lib/components';
import { Footer, MainLayout } from 'lib/layout';
import { useLocalStorageState, useOrganizationTeams } from '@app/hooks';
import { useAuthenticateUser, useDailyPlan, useLocalStorageState, useOrganizationTeams } from '@app/hooks';
import { clsxm } from '@app/utils';
import { fullWidthState } from '@app/stores/fullWidth';
import { useAtomValue } from 'jotai';
Expand All @@ -14,6 +14,7 @@ import { CalendarView, TimesheetCard, TimesheetFilter, TimesheetView } from './c
import { CalendarDaysIcon, Clock, User2 } from 'lucide-react';
import { GrTask } from "react-icons/gr";
import { GoSearch } from "react-icons/go";
import { getGreeting } from '@/app/helpers';

type TimesheetViewMode = "ListView" | "CalendarView";

Expand All @@ -28,21 +29,26 @@ interface FooterTimeSheetProps {
fullWidth: boolean;
}

function TimeSheetPage() {
const TimeSheet = React.memo(function TimeSheetPage({ params }: { params: { memberId: string } }) {
const t = useTranslations();
const { user } = useAuthenticateUser();

const { sortedPlans } = useDailyPlan();

const username = user?.name || user?.firstName || user?.lastName || user?.username;

const [timesheetNavigator, setTimesheetNavigator] = useLocalStorageState<TimesheetViewMode>('timesheet-viewMode', 'ListView');

const fullWidth = useAtomValue(fullWidthState);
const { isTrackingEnabled, activeTeam } = useOrganizationTeams();

const params = useParams<{ locale: string }>();
const currentLocale = params ? params.locale : null;
const paramsUrl = useParams<{ locale: string }>();
const currentLocale = paramsUrl ? paramsUrl.locale : null;
const breadcrumbPath = useMemo(
() => [
{ title: JSON.parse(t('pages.home.BREADCRUMB')), href: '/' },
{ title: activeTeam?.name || '', href: '/' },
{ title: 'Timesheet', href: `/${currentLocale}/timesheet` }
{ title: 'Timesheet', href: `/${currentLocale}/timesheet/${params.memberId}` }
],
[activeTeam?.name, currentLocale, t]
);
Expand All @@ -66,7 +72,7 @@ function TimeSheetPage() {
<Container fullWidth={fullWidth} className='h-full pt-14'>
<div className='py-5'>
<div className='flex flex-col justify-start items-start gap-y-2'>
<h1 className='!text-[23px] font-bold text-[#282048]'>Good morning, Ruslan !</h1>
<h1 className='!text-[23px] font-bold text-[#282048]'>{getGreeting()}, {username} !</h1>
<span className='text-[16px] text-[#3D5A80]'>This is your personal timesheet dashboard, showing you what needs your attention now.</span>
</div>
<div className='flex items-center w-full justify-between gap-6 pt-4'>
Expand Down Expand Up @@ -113,6 +119,9 @@ function TimeSheetPage() {
<input
role="searchbox"
aria-label="Search timesheet"
type="search"
name="timesheet-search"
id="timesheet-search"
className="h-10 w-full bg-transparent focus:border-transparent focus:ring-2 focus:ring-transparent placeholder-gray-500 placeholder:font-medium shadow-sm outline-none"
placeholder="Search.." />
</div>
Expand All @@ -122,7 +131,7 @@ function TimeSheetPage() {
<TimesheetFilter />
<div className='pt-4'>
{timesheetNavigator === 'ListView' ?
<TimesheetView />
<TimesheetView data={sortedPlans} />
: <CalendarView />
}
</div>
Expand All @@ -133,9 +142,9 @@ function TimeSheetPage() {
<FooterTimeSheet fullWidth={fullWidth} />
</>
)
}
})

export default withAuthentication(TimeSheetPage, { displayName: 'TimeSheet' });
export default withAuthentication(TimeSheet, { displayName: 'TimeSheet' });

const FooterTimeSheet: React.FC<FooterTimeSheetProps> = ({ fullWidth }) => {
return (
Expand Down
17 changes: 17 additions & 0 deletions apps/web/app/helpers/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,20 @@ export function formatTimeString(timeString: string): string {

return result.length ? result : '0h 00m';
}

export const getGreeting = () => {
const GREETING_TIMES = {
MORNING_START: 5,
AFTERNOON_START: 12,
EVENING_START: 18
} as const
const currentHour = new Date().getHours();

if (currentHour >= GREETING_TIMES.MORNING_START && currentHour < GREETING_TIMES.AFTERNOON_START) {
return "Good morning";
} else if (currentHour >= GREETING_TIMES.AFTERNOON_START && currentHour < GREETING_TIMES.EVENING_START) {
return "Good afternoon";
} else {
return "Good evening";
}
}
Loading

0 comments on commit 4f30b12

Please sign in to comment.