Skip to content

Commit

Permalink
Feat: refact timesheet (#2940)
Browse files Browse the repository at this point in the history
* feat: refact timesheet

* fix: cspell

* fix: setCalendarTimeSheet is defined but never used.

* improv: timesheet
Innocent-Akim authored Aug 22, 2024
1 parent 85619f1 commit b3c0138
Showing 11 changed files with 365 additions and 187 deletions.
1 change: 1 addition & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
@@ -33,6 +33,7 @@
"Bowser",
"Btns",
"Konviser",
"Ruslan",
"Bugsnag",
"buildjet",
"cacheable",
103 changes: 57 additions & 46 deletions apps/web/app/[locale]/calendar/component.tsx
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@ import { CalendarDays } from "lucide-react";
import React from "react";
import { DateRange } from "react-day-picker";
import { LuCalendarDays } from "react-icons/lu";
import { Input } from "@components/ui/input";

export function HeadCalendar({
openModal,
@@ -65,54 +66,65 @@ export function HeadTimeSheet({ timesheet }: { timesheet?: timesheetCalendar })
from: new Date(2022, 0, 20),
to: addDays(new Date(2022, 0, 20), 20)
});
console.log(timesheet);
return (
<div>
<div className='flex items-center justify-between w-full dark:!bg-dark--theme h-28'>
{timesheet === 'TimeSheet' && (
<div className='flex items-center space-x-5 dark:!bg-dark--theme '>
<div>
<CustomSelect />
</div>
<DatePicker
buttonVariant={'link'}
className="dark:bg-dark--theme-light rounded-lg"
buttonClassName={'decoration-transparent flex items-center w-full border-gray-300 justify-start text-left font-normal text-black h-10 border dark:border-slate-600 rounded-md"'}
customInput={
<>
<CalendarDays className="h-5 w-5 dark:text-gray-500" />
<Button
variant={"outline"}
className={cn(
"w-[230px] justify-start text-left font-normal text-black h-10 border border-transparent dark:border-transparent",
!date && "text-muted-foreground"
)}>
{date?.from ? (
date.to ? (
<>
{format(date.from, "LLL dd, y")} -{" "}
{format(date.to, "LLL dd, y")}
</>
) : (
format(date.from, "LLL dd, y")
)
) : (
<span>Pick a date</span>
)}
</Button>
</>
}
mode={'range'}
numberOfMonths={2}
initialFocus
defaultMonth={date?.from}
selected={date}
onSelect={(value) => {
value && setDate(value);
}}
<div className="flex justify-between items-center w-full p-2 gap-x-3">
<Input
className="border w-1/4 dark:border-gray-700"
placeholder="Filter time logs"
required
value=""
name="filter"
/>
<div>
<TimeSheetFilter />

<div className='flex items-center justify-end space-x-5 dark:!bg-dark--theme w-full p-2 '>
<div>
<CustomSelect />
</div>
<div className="">
<DatePicker
buttonVariant={'link'}
className="dark:bg-dark--theme-light rounded-lg"
buttonClassName={'decoration-transparent flex items-center w-full bg-white dark:bg-dark--theme-light border-gray-300 justify-start text-left font-normal text-black h-10 border dark:border-slate-600 rounded-md"'}
customInput={
<>
<CalendarDays className="h-5 w-5 dark:text-gray-500" />
<Button
variant={"outline"}
className={cn(
"w-[260px] justify-start text-left font-normal text-black h-10 border border-transparent dark:border-transparent ",
!date && "text-muted-foreground"
)}>
{date?.from ? (
date.to ? (
<>
{format(date.from, "LLL dd, y")} -{" "}
{format(date.to, "LLL dd, y")}
</>
) : (
format(date.from, "LLL dd, y")
)
) : (
<span>Pick a date</span>
)}
</Button>
</>
}
mode={'range'}
numberOfMonths={2}
initialFocus
defaultMonth={date?.from}
selected={date}
onSelect={(value) => {
value && setDate(value);
}}
/>
</div>
<div>
<TimeSheetFilter />
</div>
</div>
</div>
)}
@@ -133,9 +145,8 @@ export function CustomSelect() {
return (
<Select
value={selectedValue}
onValueChange={handleSelectChange}
>
<SelectTrigger className="w-[180px] border border-gray-200 dark:border-gray-700 bg-transparent">
onValueChange={handleSelectChange}>
<SelectTrigger className="w-[180px] border border-gray-200 dark:border-gray-700 bg-white dark:bg-dark--theme-light">
<SelectValue placeholder="Select a daily" />
</SelectTrigger>
<SelectContent>
17 changes: 7 additions & 10 deletions apps/web/app/[locale]/calendar/page.tsx
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ import { useTranslations } from 'next-intl';
import { useParams } from 'next/navigation';
import React, { useMemo } from 'react';
import { useRecoilValue } from 'recoil';
import { HeadCalendar, HeadTimeSheet } from './component';
import { HeadCalendar } from './component';
import { AddManualTimeModal } from 'lib/features/manual-time/add-manual-time-modal';
import { SetupTimeSheet, timesheetCalendar } from 'lib/features/integrations/calendar';

@@ -44,7 +44,7 @@ const CalendarPage = () => {
case 'Calendar':
return <SetupFullCalendar />;
case 'TimeSheet':
return <SetupTimeSheet />;
return <SetupTimeSheet timesheet={calendarTimeSheet} />
default:
return null;
}
@@ -55,15 +55,13 @@ const CalendarPage = () => {
<MainLayout
showTimer={isTrackingEnabled}
footerClassName="hidden"
className="h-[calc(100vh-22px)] shadow-xl"
className="h-full shadow-xl"
>
<AddManualTimeModal
closeModal={closeManualTimeModal}
isOpen={isManualTimeModalOpen}
params='AddManuelTime'
/>


<div
className='fixed top-20 flex flex-col border-b-[1px] dark:border-[#26272C] z-10 mx-0 w-full bg-white dark:bg-dark-high shadow-lg shadow-gray-100 dark:shadow-gray-700 '
>
@@ -81,15 +79,14 @@ const CalendarPage = () => {
<HeadCalendar
openModal={openManualTimeModal}
timesheet={calendarTimeSheet}
setCalendarTimeSheet={setCalendarTimeSheet} />
<div className='border border-gray-100 dark:border-gray-700 w-full'></div>
<HeadTimeSheet timesheet={calendarTimeSheet} />
setCalendarTimeSheet={setCalendarTimeSheet}

/>
<div className='border border-gray-100 dark:border-gray-700 w-full'></div>
</div>
</Container>
</div>

<div className='mt-[325px] mb-40'>
<div className='mt-[15vh] mb-32'>
<Container fullWidth={fullWidth}>
{renderComponent()}
</Container>
36 changes: 36 additions & 0 deletions apps/web/components/ui/badge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"

import { cn } from "lib/utils"

const badgeVariants = cva(
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
{
variants: {
variant: {
default:
"border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
secondary:
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
destructive:
"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
outline: "text-foreground",
},
},
defaultVariants: {
variant: "default",
},
}
)

export interface BadgeProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof badgeVariants> {}

function Badge({ className, variant, ...props }: BadgeProps) {
return (
<div className={cn(badgeVariants({ variant }), className)} {...props} />
)
}

export { Badge, badgeVariants }
Original file line number Diff line number Diff line change
@@ -62,7 +62,22 @@ const CalendarComponent: React.FC<CalendarComponentProps> = ({
dateClick={handleDateClick}
eventDrop={handleEventDrop}
eventContent={renderEventContent}
editable
editable={true}
dragScroll={true}
locale={"pt-br"}
timeZone={"UTF"}
allDaySlot={false}
nowIndicator={true}
themeSystem='bootstrap'
contentHeight='auto'
select={(selected) => {
console.log(selected.start)
}}
eventResize={(resize) => {
console.log(resize.el.COMMENT_NODE)
}}

// dayPopoverFormat={}
/>
<style jsx global>{`
.fc .fc-daygrid-day.fc-day-today {
91 changes: 91 additions & 0 deletions apps/web/lib/features/integrations/calendar/helper-calendar.ts
Original file line number Diff line number Diff line change
@@ -1 +1,92 @@
export type timesheetCalendar = 'TimeSheet' | 'Calendar';

export const statusOptions = [
{ value: "Approved", label: "Approved" },
{ value: "Pending", label: "Pending" },
{ value: "Rejected", label: "Rejected" },
];

export type TimeSheet = {
id: number,
task: string,
name: string,
description: string,
employee: string,
status: "Approved" | "Pending" | "Rejected",
time: string
}

export const dataSourceTimeSheet: TimeSheet[] = [
{
id: 1,
task: "chore(deps-dev): bump karma from 5.2.3 to 6.3.16chore",
name: "Gauzy Platform SaaS",
description: "Members count 11",
employee: "Ruslan Konviser",
status: "Approved",
time: '08:00h'
},
{
id: 2,
task: "chore(deps-dev): bump karma from 5.2.3 to 6.3.16chore",
name: "Gauzy Platform SaaS",
description: "Members count 11",
employee: "Ruslan Konviser",
status: "Pending",
time: '08:00h'
},
{
id: 3,
task: "chore(deps-dev): bump karma from 5.2.3 to 6.3.16chore",
name: "Gauzy Platform SaaS",
description: "Members count 11",
employee: "Ruslan Konviser",
status: "Approved",
time: '08:00h'
},
{
id: 4,
task: "chore(deps-dev): bump karma from 5.2.3 to 6.3.16chore",
name: "Gauzy Platform SaaS",
description: "Members count 11",
employee: "Ruslan Konviser",
status: "Pending",
time: '08:00h'
},
{
id: 5,
task: "chore(deps-dev): bump karma from 5.2.3 to 6.3.16chore",
name: "Gauzy Platform SaaS",
description: "Members count 11",
employee: "Ruslan Konviser",
status: "Rejected",
time: '06:00h'
},
{
id: 6,
task: "chore(deps-dev): bump karma from 5.2.3 to 6.3.16chore",
name: "Gauzy Platform SaaS",
description: "Members count 11",
employee: "Ruslan Konviser",
status: "Pending",
time: '06:00h'
},
{
id: 7,
task: "chore(deps-dev): bump karma from 5.2.3 to 6.3.16chore",
name: "Gauzy Platform SaaS",
description: "Members count 11",
employee: "Ruslan Konviser",
status: "Approved",
time: '06:00h'
},
{
id: 8,
task: "chore(deps-dev): bump karma from 5.2.3 to 6.3.16chore",
name: "Gauzy Platform SaaS",
description: "Members count 11",
employee: "Ruslan Konviser",
status: "Approved",
time: '06:00h'
},
]
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@ import { YearDateFilter } from './year-picker-filter';
import CalendarComponent from './calendar-component';
import { PiTimerBold } from "react-icons/pi";
import { formatWithSuffix } from 'lib/utils';
import { useLocalStorageState } from '@app/hooks';

// import { IOrganizationTeamList } from '@app/interfaces';

@@ -29,8 +30,10 @@ interface Event {

}

type openDetails = 'open' | 'close';

export function SetupFullCalendar() {
const [isDialogOpen, setIsDialogOpen] = useState(false);
const [isDialogOpen, setIsDialogOpen] = useLocalStorageState<openDetails>('calendar_details_persistance', 'close');
// const [newEventTitle, setNewEventTitle] = useState('');
const calendarRef = useRef<FullCalendar | null>(null);
const [selectedDate, setSelectedDate] = useState('');
@@ -82,7 +85,7 @@ export function SetupFullCalendar() {

const handleDateClick = (info: { dateStr: string }) => {
setSelectedDate(info?.dateStr);
setIsDialogOpen((prev) => !prev);
setIsDialogOpen('open');
};

const renderEventContent = (eventInfo: any) => {
@@ -133,7 +136,7 @@ export function SetupFullCalendar() {
</div>
<div>
<Button
className='flex items-center justify-center h-10 rounded-lg'
className='flex items-center justify-center h-10 rounded-lg dark:bg-primary-light'
variant='primary'>
<SettingFilterIcon className="dark:text-white w-3.5" strokeWidth="1.8" />
<span>Filter</span>
@@ -149,7 +152,7 @@ export function SetupFullCalendar() {
handleEventDrop={handleEventDrop}
renderEventContent={renderEventContent}
/>
{isDialogOpen && (
{isDialogOpen === 'open' && (
<div className={`py-10 w-1/5 m-5 h-full`}>
<CardItems selectedDate={selectedDate as any} />
</div>
@@ -167,8 +170,8 @@ export function SetupFullCalendar() {

export const CardItems = ({ selectedDate }: { selectedDate: Date }) => {
return (
<div className='flex flex-col w-full h-[90vh] sticky'>
<div className='h-full w-full border border-gray-200 dark:border-gray-700 rounded-xl py-4 bg-white flex-grow'>
<div className='flex flex-col w-full bg-red-400 md:h-[50vh] lg:h-[90vh] xl:h-[95vh] sticky top-0'>
<div className='h-full w-full border border-gray-200 dark:border-gray-700 rounded-xl py-4 bg-white dark:!bg-dark--theme-light flex-grow'>
<span className='p-2 text-[16px] text-gray-500 font-bold'>
{formatWithSuffix(new Date(selectedDate))}
</span>
@@ -186,8 +189,8 @@ export const CardItems = ({ selectedDate }: { selectedDate: Date }) => {

export const CardItemsMember = ({ imageUrl, name, time }: { imageUrl?: string, name?: string, time?: string }) => {
return (
<div className='w-full flex items-center'>
<div className='w-full flex items-center space-x-2 p-1 cursor-pointer hover:bg-gray-100 rounded'>
<div className='w-full flex items-center'>
<div className='w-full flex items-center space-x-2 p-1 cursor-pointer hover:bg-gray-100 rounded dark:hover:bg-gray-700'>
<Image className='text-white p-1 rounded-full flex items-center justify-center h-8 w-8' src={imageUrl!} alt='' width={90} height={90} />
<div className='flex items-center space-x-1 w-full'>
<span className='text-[14px] font-normal'>{name}</span>
@@ -207,7 +210,7 @@ export const CardItemsProjects = ({ logo, title, totalHours }: { logo?: string,
<div className='flex items-center w-full'>
<Image src={logo!} alt='logos' width={100} height={100} className='h-8 w-8 bg-cover rounded-lg flex items-center justify-center' />
<div className='flex items-start flex-col justify-center p-1'>
<span className='font-bold text-[16px] overflow-hidden leading-4'>{title}</span>
<span className='font-bold text-[14px] sm:text-[16px] overflow-hidden leading-4'>{title}</span>
<span className='text-gray-400 text-[12px] leading-4'>{totalHours}</span>
</div>
</div>
13 changes: 11 additions & 2 deletions apps/web/lib/features/integrations/calendar/setup-time-sheet.tsx
Original file line number Diff line number Diff line change
@@ -2,13 +2,22 @@

import React from 'react'
import { DataTableTimeSheet } from './table-time-sheet'
import { HeadTimeSheet } from '@app/[locale]/calendar/component'
import { timesheetCalendar } from './helper-calendar'

export function SetupTimeSheet() {
interface ISetupTimeSheetProps {
timesheet?: timesheetCalendar
}

export function SetupTimeSheet({ timesheet }: ISetupTimeSheetProps) {

return (
<div className='flex flex-col overflow-hidden py-[32px]'>
<div className='flex h-[750px] border border-gray-200 dark:border-gray-700 rounded-lg bg-white dark:bg-dark--theme-light p-4 shadow-lg shadow-gray-100 dark:shadow-gray-700'>
<div className='flex flex-col w-full'>
<div className='border border-gray-100 dark:border-gray-700 w-full'></div>
<HeadTimeSheet timesheet={timesheet} />
</div>
<div className='flex h-[780px] border border-gray-200 dark:border-gray-700 rounded-lg bg-white dark:bg-dark--theme-light p-4 shadow-lg shadow-gray-100 dark:shadow-gray-700'>
<DataTableTimeSheet />
</div>
</div>
214 changes: 112 additions & 102 deletions apps/web/lib/features/integrations/calendar/table-time-sheet.tsx
Original file line number Diff line number Diff line change
@@ -13,14 +13,17 @@ import {
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table"
import { ArrowUpDownIcon, MoreHorizontal } from "lucide-react"
import { ArrowUpDownIcon, MoreHorizontal, } from "lucide-react"
import { Button } from "@components/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuPortal,
DropdownMenuSeparator,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
} from "@components/ui/dropdown-menu"
import {
@@ -46,74 +49,17 @@ import {
MdKeyboardArrowLeft,
MdKeyboardArrowRight
} from "react-icons/md";
import { ConfirmStatusChange } from "."
import { ConfirmStatusChange, TimeSheet, dataSourceTimeSheet, statusOptions } from "."
import { useModal } from "@app/hooks"
import { Checkbox } from "@components/ui/checkbox";
import { Badge } from "@components/ui/badge"






const data: TimeSheet[] = [
{
id: 1,
task: "chore(deps-dev): bump karma from 5.2.3 to 6.3.16chore",
name: "Gauzy Platform SaaS",
description: "Members count 11",
employee: "Ruslan Konviser",
status: "Approved",
time: '08:00h'
},
{
id: 2,
task: "chore(deps-dev): bump karma from 5.2.3 to 6.3.16chore",
name: "Gauzy Platform SaaS",
description: "Members count 11",
employee: "Ruslan Konviser",
status: "Pending",
time: '08:00h'
},
{
id: 3,
task: "chore(deps-dev): bump karma from 5.2.3 to 6.3.16chore",
name: "Gauzy Platform SaaS",
description: "Members count 11",
employee: "Ruslan Konviser",
status: "Approved",
time: '08:00h'
},
{
id: 4,
task: "chore(deps-dev): bump karma from 5.2.3 to 6.3.16chore",
name: "Gauzy Platform SaaS",
description: "Members count 11",
employee: "Ruslan Konviser",
status: "Pending",
time: '08:00h'
},
{
id: 5,
task: "chore(deps-dev): bump karma from 5.2.3 to 6.3.16chore",
name: "Gauzy Platform SaaS",
description: "Members count 11",
employee: "Ruslan Konviser",
status: "Rejected",
time: '06:00h'
},
]

export type TimeSheet = {
id: number,
task: string,
name: string,
description: string,
employee: string,
status: "Approved" | "Pending" | "Rejected",
time: string
}

const statusOptions = [
{ value: "Approved", label: "Approved" },
{ value: "Pending", label: "Pending" },
{ value: "Rejected", label: "Rejected" },
];

function getStatusColor(status: string) {
switch (status) {
@@ -131,10 +77,32 @@ function getStatusColor(status: string) {

export const columns: ColumnDef<TimeSheet>[] = [
{
accessorKey: "task",
header: "Task",
enableHiding: false,
id: "select",
size: 50,
header: ({ table }) => (
<div className="gap-x-4 flex items-center" >
<Checkbox
checked={
table.getIsAllPageRowsSelected() ||
(table.getIsSomePageRowsSelected() && "indeterminate")
}
onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
aria-label="Select all"
/>
<span>Task</span>
</div>
),
cell: ({ row }) => (
<div className="capitalize break-words whitespace-break-spaces text-sm sm:text-base">{row.getValue("task")}</div>

<div className="flex items-center gap-x-4" >
<Checkbox
checked={row.getIsSelected()}
onCheckedChange={(value) => row.toggleSelected(!!value)}
aria-label="Select row"
/>
<span className="capitalize !text-sm break-words whitespace-break-spaces sm:text-base">{row.original.task}</span>
</div>
),
},
{
@@ -162,15 +130,14 @@ export const columns: ColumnDef<TimeSheet>[] = [
<Button
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
className="text-center w-full sm:w-auto text-sm sm:text-base"
>
Employee
className="text-center flex items-center justify-center font-medium w-full sm:w-96 text-sm sm:text-base">
<span>Employee</span>
<ArrowUpDownIcon className="ml-2 h-4 w-4" />
</Button>
),
cell: ({ row }) => (
<div className="text-center font-medium w-full sm:w-96 text-sm sm:text-base">
{row.original.employee}
<span> {row.original.employee}</span>
</div>
),
},
@@ -180,16 +147,15 @@ export const columns: ColumnDef<TimeSheet>[] = [
<Button
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
className="text-center w-full sm:w-auto text-sm sm:text-base"
className=" flex items-center justify-center text-center w-full sm:w-auto text-sm sm:text-base"
>
Status
<span>Status</span>
<ArrowUpDownIcon className="ml-2 h-4 w-4" />
</Button>

),
cell: ({ row }) => {

return <SelectFilter
return <StatusBadge
selectedStatus={row.original.status} />
}
},
@@ -220,15 +186,12 @@ export const columns: ColumnDef<TimeSheet>[] = [

export function DataTableTimeSheet() {
const [sorting, setSorting] = React.useState<SortingState>([])
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
)
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({})
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])
const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({})
const [rowSelection, setRowSelection] = React.useState({})

const table = useReactTable({
data,
data: dataSourceTimeSheet,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
@@ -251,7 +214,7 @@ export function DataTableTimeSheet() {


<div className="w-full">
<div className="rounded-md w-full ">
<div className="rounded-md">
<Table className=" border dark:border-gray-700">
<TableHeader className="w-full border dark:border-gray-700">
{table.getHeaderGroups().map((headerGroup) => (
@@ -275,13 +238,14 @@ export function DataTableTimeSheet() {
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
className=" cursor-pointer border dark:border-gray-700"
className="cursor-pointer border dark:border-gray-700 font-normal"
key={row.id}
data-state={row.getIsSelected() && "selected"}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
<TableCell aria-checked key={cell.id}>
{flexRender(

cell.column.columnDef.cell,
cell.getContext()
)}
@@ -307,7 +271,8 @@ export function DataTableTimeSheet() {
{table.getFilteredSelectedRowModel().rows.length} of{" "}
{table.getFilteredRowModel().rows.length} row(s) selected.
</div>
<div className="space-x-2 flex items-center">
<div className="gap-x-3 flex items-center">
<span className="text-sm font-medium">Page 1 of 10</span>
<Button
className="border dark:border-gray-700 text-xl flex items-center justify-center cursor-pointer"
variant="outline"
@@ -351,7 +316,36 @@ export function DataTableTimeSheet() {
)
}

function SelectFilter({ selectedStatus }: { selectedStatus?: string }) {


function StatusBadge({ selectedStatus }: { selectedStatus?: string }) {

const [selected] = React.useState(selectedStatus);

const getColorClass = () => {
switch (selected) {
case "Rejected":
return "text-red-500 border-red-500 ";
case "Approved":
return "text-green-500 border-green-500";
case "Pending":
return "text-orange-500 border-orange-500";
default:
return "text-gray-500 border-gray-200";
}


};


return (
<Badge className={`${getColorClass()} bg-transparent rounded-md py-1 px-2 text-center hover:bg-transparent`}
>{selected}</Badge>
);
}


export function SelectFilter({ selectedStatus }: { selectedStatus?: string }) {

const { isOpen, closeModal, openModal } = useModal();
const [selected] = React.useState(selectedStatus);
@@ -424,38 +418,54 @@ const TaskActionMenu = ({ idTasks }: { idTasks: any }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="h-8 w-8 p-0 border text-sm sm:text-base">
<Button variant="ghost" className="h-8 w-8 p-0 text-sm sm:text-base">
<span className="sr-only">Open menu</span>
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuItem onClick={handleCopyPaymentId}>
Copy payment ID
<DropdownMenuItem className="cursor-pointer" onClick={handleCopyPaymentId}>
Edit
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem>View customer</DropdownMenuItem>
<DropdownMenuItem>View payment details</DropdownMenuItem>
<StatusTask />
<DropdownMenuItem className="text-red-600 hover:!text-red-600 cursor-pointer">Delete</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
};

const TaskDetails = ({ description, name }: { description: string; name: string }) => {
return (
<div className="flex items-start w-full">
<div className="flex items-center gap-x-2 w-full">
<div className="flex items-center justify-center h-10 w-10 rounded-lg bg-primary dark:bg-primary-light text-white shadow p-2">
<span className="lowercase font-medium">ever</span>
</div>
<div className="flex flex-col items-start w-full sm:w-1/2 ml-4">
<span className="capitalize font-bold text-sm sm:text-base text-gray-800 dark:text-white leading-4 whitespace-nowrap">
{name}
</span>
<span className="capitalize font-normal text-sm sm:text-base text-gray-400 leading-4 whitespace-nowrap">
{description}
</span>
</div>
<span className="capitalize font-bold !text-sm sm:text-base text-gray-800 dark:text-white leading-4 whitespace-nowrap">
{name}
</span>
</div>
);
};

export const StatusTask = () => {
return (
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<span>Status</span>
</DropdownMenuSubTrigger>
<DropdownMenuPortal>
<DropdownMenuSubContent>
{statusOptions?.map((status, index) => (
<DropdownMenuItem key={index} textValue={status.value} className="cursor-pointer">
<div className="flex items-center gap-3">
<div className="h-1 w-1 rounded-full bg-black dark:bg-white"></div>
<span>{status.label}</span>
</div>
</DropdownMenuItem>
))}
</DropdownMenuSubContent>
</DropdownMenuPortal>
</DropdownMenuSub>
)
}
Original file line number Diff line number Diff line change
@@ -13,9 +13,7 @@ import { statusOptions } from "@app/constants";

export function TimeSheetFilter() {


const { teams, activeTeam } = useOrganizationTeams();

const { activeTeamTask, tasks } = useTeamTasks();
const [status, setStatus] = useState('');
const [taskId, setTaskId] = useState<string>('');
@@ -27,9 +25,14 @@ export function TimeSheetFilter() {
<Popover>
<PopoverTrigger asChild>
<Button
className='flex items-center justify-center h-10 rounded-lg bg-primary dark:bg-primary-light gap-x-3' >
<SettingFilterIcon className="dark:text-white w-3.5" strokeWidth="1.8" />
<span className="dark:text-white">Filter</span>
className='flex items-center justify-center h-10 rounded-lg bg-white dark:bg-dark--theme-light gap-x-3 border dark:border-gray-700 hover:bg-white' >
<SettingFilterIcon className="text-gray-700 dark:text-white w-3.5" strokeWidth="1.8" />
<div className="gap-x-2 flex items-center w-full">
<span className="text-gray-700 dark:text-white">Filter</span>
<div className="bg-gray-700 dark:bg-white h-6 w-6 rounded-full flex items-center justify-center text-whiten dark:text-gray-700">
<span>6</span>
</div>
</div>
</Button>
</PopoverTrigger>
<PopoverContent className="w-[430px] shadow">
26 changes: 14 additions & 12 deletions apps/web/lib/features/task/task-filters.tsx
Original file line number Diff line number Diff line change
@@ -7,7 +7,8 @@ import {
useDailyPlan,
useOrganizationTeams,
useOutsideClick,
useModal
useModal,
useLocalStorageState
} from '@app/hooks';
import { IClassName, ITeamTask } from '@app/interfaces';
import { clsxm } from '@app/utils';
@@ -51,10 +52,10 @@ type StatusFilter = { [x in IStatusType]: string[] };
*/
export function useTaskFilter(profile: I_UserProfilePage) {
const t = useTranslations();
const defaultValue = useMemo(
() => (typeof window !== 'undefined' ? (window.localStorage.getItem('task-tab') as ITab) || null : 'worked'),
[]
);
// const defaultValue = useMemo(
// () => (typeof window !== 'undefined' ? (window.localStorage.getItem('task-tab') as ITab) || null : 'worked'),
// []
// );
const { activeTeamManagers, activeTeam } = useOrganizationTeams();
const { user } = useAuthenticateUser();
const { profileDailyPlans, outstandingPlans, todayPlan } = useDailyPlan();
@@ -68,7 +69,8 @@ export function useTaskFilter(profile: I_UserProfilePage) {
[isManagerConnectedUser, profile.userProfile?.id, user?.id]
);

const [tab, setTab] = useState<ITab>(defaultValue || 'worked');
// const [tab, setTab] = useState<ITab>(defaultValue || 'worked');
const [tab, setTab] = useLocalStorageState<ITab>('task-tab', 'worked')
const [filterType, setFilterType] = useState<FilterType>(undefined);

const [statusFilter, setStatusFilter] = useState<StatusFilter>({} as StatusFilter);
@@ -139,9 +141,9 @@ export function useTaskFilter(profile: I_UserProfilePage) {
});
}

useEffect(() => {
window.localStorage.setItem('task-tab', tab);
}, [tab]);
// useEffect(() => {
// window.localStorage.setItem('task-tab', tab);
// }, [tab]);

useEffect(() => {
setTaskName('');
@@ -220,9 +222,9 @@ export function useTaskFilter(profile: I_UserProfilePage) {
.every((k) => {
return k === 'label'
? intersection(
statusFilters[k],
task['tags'].map((item) => item.name)
).length === statusFilters[k].length
statusFilters[k],
task['tags'].map((item) => item.name)
).length === statusFilters[k].length
: statusFilters[k].includes(task[k]);
});
});

0 comments on commit b3c0138

Please sign in to comment.