diff --git a/apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx b/apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx index 3893337aa..31c241932 100644 --- a/apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx +++ b/apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx @@ -12,6 +12,7 @@ import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@c import { DatePickerFilter } from './TimesheetFilterDate'; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@components/ui/select'; import { useTimesheet } from '@/app/hooks/features/useTimesheet'; +import { toUTC } from '@/app/helpers'; export interface IAddTaskModalProps { isOpen: boolean; closeModal: () => void; @@ -22,6 +23,18 @@ interface Shift { totalHours: string; dateFrom: Date | string, } +interface FormState { + isBillable: boolean; + notes: string; + projectId: string; + taskId: string; + employeeId: string; + shifts: { + dateFrom: Date; + startTime: string; + endTime: string; + }[]; +} export function AddTaskModal({ closeModal, isOpen }: IAddTaskModalProps) { const { tasks } = useTeamTasks(); @@ -32,6 +45,7 @@ export function AddTaskModal({ closeModal, isOpen }: IAddTaskModalProps) { const timeOptions = generateTimeOptions(5); const t = useTranslations(); + const [formState, setFormState] = React.useState({ notes: '', isBillable: true, @@ -77,37 +91,53 @@ export function AddTaskModal({ closeModal, isOpen }: IAddTaskModalProps) { }, ]; - const handleAddTimesheet = async () => { + const createUtcDate = (baseDate: Date, time: string): Date => { + const [hours, minutes] = time.split(':').map(Number); + return new Date(Date.UTC(baseDate.getFullYear(), baseDate.getMonth(), baseDate.getDate(), hours, minutes)); + }; + + const handleAddTimesheet = async (formState: FormState) => { const payload = { isBillable: formState.isBillable, description: formState.notes, projectId: formState.projectId, - logType: TimeLogType.MANUAL as any, - source: TimerSource.BROWSER as any, + logType: TimeLogType.MANUAL, + source: TimerSource.BROWSER, taskId: formState.taskId, - employeeId: formState.employeeId - } - const createUtcDate = (baseDate: Date, time: string): Date => { - const [hours, minutes] = time.split(':').map(Number); - return new Date(Date.UTC(baseDate.getFullYear(), baseDate.getMonth(), baseDate.getDate(), hours, minutes)); + employeeId: formState.employeeId, + organizationContactId: null || "", + organizationTeamId: null, }; - try { - await Promise.all(formState.shifts.map(async (shift) => { - const baseDate = shift.dateFrom instanceof Date ? shift.dateFrom : new Date(shift.dateFrom ?? new Date()); - const startedAt = createUtcDate(baseDate, shift.startTime.toString().slice(0, 5)); - const stoppedAt = createUtcDate(baseDate, shift.endTime.toString().slice(0, 5)); - await createTimesheet({ - ...payload, - startedAt, - stoppedAt, - }); - })); - closeModal(); + if (!formState.shifts || formState.shifts.length === 0) { + throw new Error('No shifts provided.'); + } + await Promise.all( + formState.shifts.map(async (shift) => { + if (!shift.dateFrom || !shift.startTime || !shift.endTime) { + throw new Error('Incomplete shift data.'); + } + + const baseDate = shift.dateFrom instanceof Date ? shift.dateFrom : new Date(shift.dateFrom); + const start = createUtcDate(baseDate, shift.startTime); + const end = createUtcDate(baseDate, shift.endTime); + const startedAt = toUTC(start).toISOString(); + const stoppedAt = toUTC(end).toISOString(); + if (stoppedAt <= startedAt) { + throw new Error('End time must be after start time.'); + } + await createTimesheet({ + ...payload, + startedAt, + stoppedAt, + }); + }) + ); + console.log('Timesheets successfully created.'); } catch (error) { console.error('Failed to create timesheet:', error); } - } + }; return ( *: updateFormState('employeeId', value.id)} renderOption={(option: any) => ( @@ -235,7 +265,7 @@ export function AddTaskModal({ closeModal, isOpen }: IAddTaskModalProps) { - ), - cell: ({ row }) => - }, - { - accessorKey: 'employee', - header: ({ column }) => ( - - ), - cell: ({ row }) => ( -
- {row.original.employee} -
- ) - }, - { - accessorKey: 'status', - header: ({ column }) => ( - - ), - cell: ({ row }) => { - return ; - } - }, - { - accessorKey: 'time', - header: () =>
Time
, - cell: ({ row }) => ( -
- {row.original.time} -
- ) - } -]; export function DataTableTimeSheet({ data, user }: { data?: GroupedTimesheet[], user?: IUser | undefined }) { const modal = useModal(); @@ -183,28 +80,7 @@ export function DataTableTimeSheet({ data, user }: { data?: GroupedTimesheet[], }; const t = useTranslations(); - const [sorting, setSorting] = React.useState([]); - const [columnFilters, setColumnFilters] = React.useState([]); - const [columnVisibility, setColumnVisibility] = React.useState({}); - const [rowSelection, setRowSelection] = React.useState({}); - const table = useReactTable({ - data: dataSourceTimeSheet, - columns, - onSortingChange: setSorting, - onColumnFiltersChange: setColumnFilters, - getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), - getSortedRowModel: getSortedRowModel(), - getFilteredRowModel: getFilteredRowModel(), - onColumnVisibilityChange: setColumnVisibility, - onRowSelectionChange: setRowSelection, - state: { - sorting, - columnFilters, - columnVisibility, - rowSelection - } - }); + const handleSort = (key: string, order: SortOrder) => { console.log(`Sorting ${key} in ${order} order`); }; @@ -277,6 +153,7 @@ export function DataTableTimeSheet({ data, user }: { data?: GroupedTimesheet[], className={clsxm("p-1 rounded")} > -
-
- {table.getFilteredSelectedRowModel().rows.length} of {table.getFilteredRowModel().rows.length}{' '} - row(s) selected. -
-
- - Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount()} - - - - - -
-
); } @@ -544,19 +386,7 @@ const TaskActionMenu = ({ dataTimesheet, isManage, user }: { dataTimesheet: Time }; -const TaskDetails = ({ description, name }: { description: string; name: string }) => { - return ( -
-
- ever -
- - {name} - -
{description}
-
- ); -}; + export const StatusTask = ({ timesheet }: { timesheet: TimesheetLog }) => { const t = useTranslations(); diff --git a/apps/web/lib/features/multiple-select/index.tsx b/apps/web/lib/features/multiple-select/index.tsx index 94149c225..5ec9af5da 100644 --- a/apps/web/lib/features/multiple-select/index.tsx +++ b/apps/web/lib/features/multiple-select/index.tsx @@ -158,8 +158,8 @@ export function CustomSelect({ - {options.map((value) => ( - + {options.map((value, index) => ( + {renderOption ? renderOption(value) : value.charAt(0).toUpperCase() + value.slice(1)} ))}