From ca52c4d02cc559fa0e5cfc6fb2899fb78a8e4926 Mon Sep 17 00:00:00 2001 From: AKILIMAILI CIZUNGU Innocent <51681130+Innocent-Akim@users.noreply.github.com> Date: Sun, 8 Dec 2024 20:00:16 +0200 Subject: [PATCH] [Feat]: Manage Permissions and Improve Time entries view (#3403) * fix: Kanban | Cards are broken when toogle FullWidth Mode * fix: cspell * feat: manage permissions and improve time entries view * fix:coderabbitai * feat(timesheet): calculate and display total duration * improve:Enhanced user permissions management in the Timesheet components * improve: update status style for tasks in timesheet --- apps/web/app/[locale]/kanban/page.tsx | 18 +++-- .../[memberId]/components/AddTaskModal.tsx | 2 +- .../[memberId]/components/CalendarView.tsx | 4 +- .../[memberId]/components/TimesheetFilter.tsx | 27 ++++--- .../components/TimesheetFilterDate.tsx | 13 ++-- .../[memberId]/components/TimesheetView.tsx | 5 +- .../[locale]/timesheet/[memberId]/page.tsx | 37 ++++++---- .../hooks/features/useTimelogFilterOptions.ts | 14 +++- apps/web/app/hooks/features/useTimesheet.ts | 14 ++-- .../calendar/table-time-sheet.tsx | 30 +++++--- apps/web/lib/features/task/task-displays.tsx | 20 ++++-- .../lib/features/team-members-kanban-view.tsx | 72 +++++++++---------- apps/web/lib/settings/member-table.tsx | 2 +- 13 files changed, 160 insertions(+), 98 deletions(-) diff --git a/apps/web/app/[locale]/kanban/page.tsx b/apps/web/app/[locale]/kanban/page.tsx index 018561643..f4cf38ee6 100644 --- a/apps/web/app/[locale]/kanban/page.tsx +++ b/apps/web/app/[locale]/kanban/page.tsx @@ -31,6 +31,7 @@ import { useAtomValue } from 'jotai'; import { fullWidthState } from '@app/stores/fullWidth'; import { CircleIcon } from 'lucide-react'; import { XMarkIcon } from '@heroicons/react/20/solid'; +import { cn } from '@/lib/utils'; const Kanban = () => { const { @@ -161,11 +162,10 @@ const Kanban = () => {
setActiveTab(tab.value)} - className={`cursor-pointer pt-2.5 px-5 pb-[30px] text-base font-semibold ${ - activeTab === tab.value - ? 'border-b-[#3826A6] text-[#3826A6] dark:text-white dark:border-b-white' - : 'border-b-white dark:border-b-[#191A20] dark:text-white text-[#282048]' - }`} + className={`cursor-pointer pt-2.5 px-5 pb-[30px] text-base font-semibold ${activeTab === tab.value + ? 'border-b-[#3826A6] text-[#3826A6] dark:text-white dark:border-b-white' + : 'border-b-white dark:border-b-[#191A20] dark:text-white text-[#282048]' + }`} style={{ borderBottomWidth: '3px', borderBottomStyle: 'solid' @@ -259,10 +259,14 @@ const Kanban = () => { } > {/** TODO:fetch teamtask based on days */} + +
{activeTab && (Object.keys(data).length > 0 ? ( - + + + ) : ( // add filter for today, yesterday and tomorrow
@@ -270,7 +274,7 @@ const Kanban = () => {
))}
- + ); diff --git a/apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx b/apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx index f9ba3321a..ca450efd9 100644 --- a/apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx +++ b/apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx @@ -94,7 +94,7 @@ export function AddTaskModal({ closeModal, isOpen }: IAddTaskModalProps) { {...taskIssues[option as ITaskIssue]} showIssueLabels={false} issueType="issue" - className={clsxm('rounded-md px-2 text-white bg-primary')} + className={clsxm('rounded-sm h-auto !px-[0.3312rem] py-[0.2875rem] text-white bg-primary')} /> {option}
diff --git a/apps/web/app/[locale]/timesheet/[memberId]/components/CalendarView.tsx b/apps/web/app/[locale]/timesheet/[memberId]/components/CalendarView.tsx index e1b649a62..686961708 100644 --- a/apps/web/app/[locale]/timesheet/[memberId]/components/CalendarView.tsx +++ b/apps/web/app/[locale]/timesheet/[memberId]/components/CalendarView.tsx @@ -11,14 +11,16 @@ import { cn } from "@/lib/utils"; import MonthlyTimesheetCalendar from "./MonthlyTimesheetCalendar"; import { useTimelogFilterOptions } from "@/app/hooks"; import WeeklyTimesheetCalendar from "./WeeklyTimesheetCalendar"; +import { IUser } from "@/app/interfaces"; interface BaseCalendarDataViewProps { t: TranslationHooks data: GroupedTimesheet[]; daysLabels?: string[]; CalendarComponent: typeof MonthlyTimesheetCalendar | typeof WeeklyTimesheetCalendar; + user?: IUser | undefined } -export function CalendarView({ data, loading }: { data?: GroupedTimesheet[], loading: boolean }) { +export function CalendarView({ data, loading, user }: { data?: GroupedTimesheet[], loading: boolean, user?: IUser | undefined }) { const t = useTranslations(); const { timesheetGroupByDays } = useTimelogFilterOptions(); const defaultDaysLabels = [ diff --git a/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilter.tsx b/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilter.tsx index 71d9c6fb0..4cff8b6c1 100644 --- a/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilter.tsx +++ b/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilter.tsx @@ -3,7 +3,8 @@ import { FrequencySelect, TimeSheetFilterPopover, TimesheetFilterDate, Timesheet import { Button } from 'lib/components'; import { TranslationHooks } from 'next-intl'; import { AddTaskModal } from './AddTaskModal'; -import { TimesheetLog, TimesheetStatus } from '@/app/interfaces'; +import { IUser, TimesheetLog, TimesheetStatus } from '@/app/interfaces'; +import { useTimelogFilterOptions } from '@/app/hooks'; interface ITimesheetFilter { isOpen: boolean, @@ -14,10 +15,13 @@ interface ITimesheetFilter { onChangeStatus?: (status: FilterStatus) => void; filterStatus?: FilterStatus, data?: Record + user?: IUser | undefined } -export function TimesheetFilter({ closeModal, isOpen, openModal, t, initDate, filterStatus, onChangeStatus, data }: ITimesheetFilter,) { +export function TimesheetFilter({ closeModal, isOpen, openModal, t, initDate, filterStatus, onChangeStatus, data, user }: ITimesheetFilter,) { + const { isUserAllowedToAccess } = useTimelogFilterOptions(); + const isManage = isUserAllowedToAccess(user); return ( <> { @@ -37,13 +41,18 @@ export function TimesheetFilter({ closeModal, isOpen, openModal, t, initDate, fi
- - + {isManage && ( + <> + + + + ) + }
diff --git a/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilterDate.tsx b/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilterDate.tsx index 5c50e0631..83e1f8a91 100644 --- a/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilterDate.tsx +++ b/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilterDate.tsx @@ -11,6 +11,8 @@ import { MdKeyboardArrowRight } from 'react-icons/md'; import { PiCalendarDotsThin } from 'react-icons/pi'; import React, { Dispatch, useEffect, useState, SetStateAction, useCallback, useMemo, memo } from 'react'; import moment from 'moment'; +import { ChevronDown } from 'lucide-react'; + interface DatePickerInputProps { date: Date | null; @@ -138,7 +140,7 @@ export function TimesheetFilterDate({
))} diff --git a/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetView.tsx b/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetView.tsx index 18606f719..be0640fdf 100644 --- a/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetView.tsx +++ b/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetView.tsx @@ -1,9 +1,10 @@ import { GroupedTimesheet } from '@/app/hooks/features/useTimesheet'; +import { IUser } from '@/app/interfaces'; import TimesheetSkeleton from '@components/shared/skeleton/TimesheetSkeleton'; import { DataTableTimeSheet } from 'lib/features/integrations/calendar'; import { useTranslations } from 'next-intl'; -export function TimesheetView({ data, loading }: { data?: GroupedTimesheet[]; loading?: boolean }) { +export function TimesheetView({ data, loading, user }: { data?: GroupedTimesheet[]; loading?: boolean, user?: IUser | undefined }) { const t = useTranslations(); if (loading || !data) { @@ -26,7 +27,7 @@ export function TimesheetView({ data, loading }: { data?: GroupedTimesheet[]; lo return (
- +
); } diff --git a/apps/web/app/[locale]/timesheet/[memberId]/page.tsx b/apps/web/app/[locale]/timesheet/[memberId]/page.tsx index ade889e9b..a31a9cc60 100644 --- a/apps/web/app/[locale]/timesheet/[memberId]/page.tsx +++ b/apps/web/app/[locale]/timesheet/[memberId]/page.tsx @@ -19,9 +19,9 @@ import { CalendarDaysIcon, Clock, User2 } from 'lucide-react'; import { GrTask } from 'react-icons/gr'; import { GoSearch } from 'react-icons/go'; -import { getGreeting } from '@/app/helpers'; +import { getGreeting, secondsToTime } from '@/app/helpers'; import { useTimesheet } from '@/app/hooks/features/useTimesheet'; -import { endOfDay, startOfDay } from 'date-fns'; +import { startOfWeek, endOfWeek } from 'date-fns'; import TimesheetDetailModal from './components/TimesheetDetailModal'; type TimesheetViewMode = 'ListView' | 'CalendarView'; @@ -37,6 +37,7 @@ type ViewToggleButtonProps = { const TimeSheet = React.memo(function TimeSheetPage({ params }: { params: { memberId: string } }) { const t = useTranslations(); const { user } = useAuthenticateUser(); + const { isTrackingEnabled, activeTeam } = useOrganizationTeams(); const [search, setSearch] = useState(''); const [filterStatus, setFilterStatus] = useLocalStorageState('timesheet-filter-status', 'All Tasks'); const [timesheetNavigator, setTimesheetNavigator] = useLocalStorageState( @@ -45,12 +46,12 @@ const TimeSheet = React.memo(function TimeSheetPage({ params }: { params: { memb ); const [dateRange, setDateRange] = React.useState<{ from: Date | null; to: Date | null }>({ - from: startOfDay(new Date()), - to: endOfDay(new Date()) + from: startOfWeek(new Date(), { weekStartsOn: 1 }), + to: endOfWeek(new Date(), { weekStartsOn: 1 }), }); - const { timesheet, statusTimesheet, loadingTimesheet } = useTimesheet({ - startDate: dateRange.from ?? '', - endDate: dateRange.to ?? '', + const { timesheet, statusTimesheet, loadingTimesheet, isManage } = useTimesheet({ + startDate: dateRange.from!, + endDate: dateRange.to!, timesheetViewMode: timesheetNavigator }); @@ -88,10 +89,13 @@ const TimeSheet = React.memo(function TimeSheetPage({ params }: { params: { memb const username = user?.name || user?.firstName || user?.lastName || user?.username; - + const totalDuration = Object.values(statusTimesheet) + .flat() + .map(entry => entry.timesheet.duration) + .reduce((total, current) => total + current, 0); + const { h: hours, m: minute } = secondsToTime(totalDuration || 0); const fullWidth = useAtomValue(fullWidthState); - const { isTrackingEnabled, activeTeam } = useOrganizationTeams(); const paramsUrl = useParams<{ locale: string }>(); const currentLocale = paramsUrl ? paramsUrl.locale : null; @@ -144,19 +148,23 @@ const TimeSheet = React.memo(function TimeSheetPage({ params }: { params: { memb onClick={() => openTimesheetDetail()} /> } classNameIcon="bg-[#3D5A80] shadow-[#3d5a809c] " /> - entry.employee.id) + .filter((id, index, array) => array.indexOf(id) === index) + .length} title="Members Worked" description="People worked since last time" icon={} classNameIcon="bg-[#30B366] shadow-[#30b3678f]" - /> + />)}
@@ -190,6 +198,7 @@ const TimeSheet = React.memo(function TimeSheetPage({ params }: { params: { memb
{timesheetNavigator === 'ListView' ? ( ) : ( diff --git a/apps/web/app/hooks/features/useTimelogFilterOptions.ts b/apps/web/app/hooks/features/useTimelogFilterOptions.ts index bcbe64a23..ba00c9aae 100644 --- a/apps/web/app/hooks/features/useTimelogFilterOptions.ts +++ b/apps/web/app/hooks/features/useTimelogFilterOptions.ts @@ -1,8 +1,10 @@ +import { IUser, RoleNameEnum } from '@/app/interfaces'; import { timesheetDeleteState, timesheetGroupByDayState, timesheetFilterEmployeeState, timesheetFilterProjectState, timesheetFilterStatusState, timesheetFilterTaskState, timesheetUpdateStatus } from '@/app/stores'; import { useAtom } from 'jotai'; import React from 'react'; export function useTimelogFilterOptions() { + const [employeeState, setEmployeeState] = useAtom(timesheetFilterEmployeeState); const [projectState, setProjectState] = useAtom(timesheetFilterProjectState); const [statusState, setStatusState] = useAtom(timesheetFilterStatusState); @@ -17,6 +19,15 @@ export function useTimelogFilterOptions() { const project = projectState; const task = taskState + const isUserAllowedToAccess = (user: IUser | null | undefined): boolean => { + const allowedRoles: RoleNameEnum[] = [ + RoleNameEnum.SUPER_ADMIN, + RoleNameEnum.MANAGER, + RoleNameEnum.ADMIN, + ]; + return user?.role.name ? allowedRoles.includes(user.role.name as RoleNameEnum) : false; + }; + const generateTimeOptions = (interval = 15) => { const totalSlots = (24 * 60) / interval; // Total intervals in a day return Array.from({ length: totalSlots }, (_, i) => { @@ -67,6 +78,7 @@ export function useTimelogFilterOptions() { setTimesheetGroupByDays, generateTimeOptions, setPuTimesheetStatus, - puTimesheetStatus + puTimesheetStatus, + isUserAllowedToAccess }; } diff --git a/apps/web/app/hooks/features/useTimesheet.ts b/apps/web/app/hooks/features/useTimesheet.ts index 2f3c6599b..2594b3734 100644 --- a/apps/web/app/hooks/features/useTimesheet.ts +++ b/apps/web/app/hooks/features/useTimesheet.ts @@ -95,26 +95,29 @@ export function useTimesheet({ }: TimesheetParams) { const { user } = useAuthenticateUser(); const [timesheet, setTimesheet] = useAtom(timesheetRapportState); - const { employee, project, task, statusState, timesheetGroupByDays, puTimesheetStatus } = useTimelogFilterOptions(); + const { employee, project, task, statusState, timesheetGroupByDays, puTimesheetStatus, isUserAllowedToAccess } = useTimelogFilterOptions(); const { loading: loadingTimesheet, queryCall: queryTimesheet } = useQuery(getTaskTimesheetLogsApi); const { loading: loadingDeleteTimesheet, queryCall: queryDeleteTimesheet } = useQuery(deleteTaskTimesheetLogsApi); const { loading: loadingUpdateTimesheetStatus, queryCall: queryUpdateTimesheetStatus } = useQuery(updateStatusTimesheetFromApi) const { loading: loadingCreateTimesheet, queryCall: queryCreateTimesheet } = useQuery(createTimesheetFromApi); const { loading: loadingUpdateTimesheet, queryCall: queryUpdateTimesheet } = useQuery(updateTimesheetFromAPi); - + const isManage = user && isUserAllowedToAccess(user); const getTaskTimesheet = useCallback( ({ startDate, endDate }: TimesheetParams) => { if (!user) return; + const from = moment(startDate).format('YYYY-MM-DD'); - const to = moment(endDate).format('YYYY-MM-DD') + const to = moment(endDate).format('YYYY-MM-DD'); queryTimesheet({ startDate: from, endDate: to, organizationId: user.employee?.organizationId, tenantId: user.tenantId ?? '', timeZone: user.timeZone?.split('(')[0].trim(), - employeeIds: employee?.map((member) => member.employee.id).filter((id) => id !== undefined), + employeeIds: isManage + ? employee?.map(({ employee: { id } }) => id).filter(Boolean) + : [user.employee.id], projectIds: project?.map((project) => project.id).filter((id) => id !== undefined), taskIds: task?.map((task) => task.id).filter((id) => id !== undefined), status: statusState?.map((status) => status.value).filter((value) => value !== undefined) @@ -297,6 +300,7 @@ export function useTimesheet({ loadingCreateTimesheet, updateTimesheet, loadingUpdateTimesheet, - groupByDate + groupByDate, + isManage }; } diff --git a/apps/web/lib/features/integrations/calendar/table-time-sheet.tsx b/apps/web/lib/features/integrations/calendar/table-time-sheet.tsx index db7616a22..8d0efecec 100644 --- a/apps/web/lib/features/integrations/calendar/table-time-sheet.tsx +++ b/apps/web/lib/features/integrations/calendar/table-time-sheet.tsx @@ -63,7 +63,7 @@ import { useTranslations } from 'next-intl'; import { formatDate } from '@/app/helpers'; import { GroupedTimesheet, useTimesheet } from '@/app/hooks/features/useTimesheet'; import { DisplayTimeForTimesheet, TaskNameInfoDisplay, TotalDurationByDate, TotalTimeDisplay } from '../../task/task-displays'; -import { TimesheetLog, TimesheetStatus } from '@/app/interfaces'; +import { IUser, TimesheetLog, TimesheetStatus } from '@/app/interfaces'; import { toast } from '@components/ui/use-toast'; import { ToastAction } from '@components/ui/toast'; @@ -156,15 +156,15 @@ export const columns: ColumnDef[] = [ } ]; -export function DataTableTimeSheet({ data }: { data?: GroupedTimesheet[] }) { +export function DataTableTimeSheet({ data, user }: { data?: GroupedTimesheet[], user?: IUser | undefined }) { const modal = useModal(); const alertConfirmationModal = useModal(); const { isOpen, openModal, closeModal } = modal; const { isOpen: isOpenAlert, openModal: openAlertConfirmation, closeModal: closeAlertConfirmation } = alertConfirmationModal; const { deleteTaskTimesheet, loadingDeleteTimesheet, getStatusTimesheet, updateTimesheetStatus } = useTimesheet({}); - const { timesheetGroupByDays, handleSelectRowByStatusAndDate, handleSelectRowTimesheet, selectTimesheetId, setSelectTimesheetId } = useTimelogFilterOptions(); - + const { timesheetGroupByDays, handleSelectRowByStatusAndDate, handleSelectRowTimesheet, selectTimesheetId, setSelectTimesheetId, isUserAllowedToAccess } = useTimelogFilterOptions(); + const isManage = isUserAllowedToAccess(user); const handleConfirm = () => { @@ -303,7 +303,7 @@ export function DataTableTimeSheet({ data }: { data?: GroupedTimesheet[] }) {
- {getTimesheetButtons(status as StatusType, t, false, handleButtonClick)} + {isManage && getTimesheetButtons(status as StatusType, t, true, handleButtonClick)}
@@ -336,7 +336,7 @@ export function DataTableTimeSheet({ data }: { data?: GroupedTimesheet[] }) { - + ))} @@ -469,10 +473,11 @@ export function SelectFilter({ selectedStatus }: { selectedStatus?: string }) { ); } -const TaskActionMenu = ({ dataTimesheet }: { dataTimesheet: TimesheetLog }) => { +const TaskActionMenu = ({ dataTimesheet, isManage, user }: { dataTimesheet: TimesheetLog, isManage?: boolean, user?: IUser | undefined }) => { const { isOpen: isEditTask, openModal: isOpenModalEditTask, closeModal: isCloseModalEditTask } = useModal(); const { isOpen: isOpenAlert, openModal: openAlertConfirmation, closeModal: closeAlertConfirmation } = useModal(); const { deleteTaskTimesheet, loadingDeleteTimesheet } = useTimesheet({}); + const canEdit = isManage || user?.id === dataTimesheet.employee.user.id; const t = useTranslations(); const handleDeleteTask = () => { @@ -519,9 +524,12 @@ const TaskActionMenu = ({ dataTimesheet }: { dataTimesheet: TimesheetLog }) => { - - {t('common.EDIT')} - + {canEdit && ( + + {t('common.EDIT')} + + ) + } ; @@ -73,23 +74,32 @@ const formatTime = (hours: number, minutes: number) => ( ); -export const DisplayTimeForTimesheet = ({ duration }: { duration: number }) => { +export const DisplayTimeForTimesheet = ({ duration, logType }: { duration: number, logType?: 'TRACKED' | 'MANUAL' | 'IDLE' | undefined }) => { if (duration < 0) { console.warn('Negative duration provided to DisplayTimeForTimesheet'); duration = 0; } const { h: hours, m: minute } = secondsToTime(duration || 0); + + const iconClasses = 'text-[14px] h-4 w-4'; + const icons = { + MANUAL: , + TRACKED: , + IDLE: , + }; + const resolvedLogType: keyof typeof icons = logType ?? 'TRACKED'; return ( -
- -
+
+ {icons[resolvedLogType]} +
{formatTime(hours, minute)}
- ) + ); } + export const TotalTimeDisplay = React.memo(({ timesheetLog }: { timesheetLog: TimesheetLog[] }) => { const totalDuration = Array.isArray(timesheetLog) ? timesheetLog.reduce((acc, curr) => acc + (curr.timesheet?.duration || 0), 0) diff --git a/apps/web/lib/features/team-members-kanban-view.tsx b/apps/web/lib/features/team-members-kanban-view.tsx index b260e0b76..3ab46d943 100644 --- a/apps/web/lib/features/team-members-kanban-view.tsx +++ b/apps/web/lib/features/team-members-kanban-view.tsx @@ -2,7 +2,6 @@ import { useTaskStatus } from '@app/hooks'; import { useKanban } from '@app/hooks/features/useKanban'; import { ITaskStatusItemList, ITeamTask } from '@app/interfaces'; import { IKanban } from '@app/interfaces/IKanban'; -import { fullWidthState } from '@app/stores/fullWidth'; import KanbanDraggable, { EmptyKanbanDroppable } from 'lib/components/Kanban'; import { Fragment, useEffect, useRef, useState } from 'react'; import { @@ -13,7 +12,6 @@ import { DroppableProvided, DroppableStateSnapshot } from 'react-beautiful-dnd'; -import { useAtomValue } from 'jotai'; import { ScrollArea, ScrollBar } from '@components/ui/scroll-area'; import { cn } from '../utils'; @@ -38,7 +36,6 @@ export const KanbanView = ({ kanbanBoardTasks, isLoading }: { kanbanBoardTasks: }; }) ); - const fullWidth = useAtomValue(fullWidthState); const containerRef = useRef(null); const { taskStatus: ts } = useTaskStatus(); const reorderTask = (list: ITeamTask[], startIndex: number, endIndex: number) => { @@ -201,7 +198,7 @@ export const KanbanView = ({ kanbanBoardTasks, isLoading }: { kanbanBoardTasks: return (
@@ -213,46 +210,45 @@ export const KanbanView = ({ kanbanBoardTasks, isLoading }: { kanbanBoardTasks: className={cn( 'flex flex-1 flex-row gap-2 min-h-fit px-8 lg:px-0 w-full h-full', snapshot.isDraggingOver ? 'bg-slate-200 dark:bg-slate-800' : '', - !fullWidth && 'x-container pl-0' )} ref={provided.innerRef} {...provided.droppableProps} > {columns.length > 0 ? columns.map((column: any, index: number) => ( - - {isColumnCollapse(column.name) ? ( - - ) : ( - - )} - - )) + + {isColumnCollapse(column.name) ? ( + + ) : ( + + )} + + )) : null} {provided.placeholder as React.ReactElement}
diff --git a/apps/web/lib/settings/member-table.tsx b/apps/web/lib/settings/member-table.tsx index 497148d72..f186d14c7 100644 --- a/apps/web/lib/settings/member-table.tsx +++ b/apps/web/lib/settings/member-table.tsx @@ -21,7 +21,7 @@ export const MemberTable = ({ members }: { members: OT_Member[] }) => { const t = useTranslations(); const { total, onPageChange, itemsPerPage, itemOffset, endOffset, setItemsPerPage, currentItems } = usePagination(members); - const { activeTeam, updateOrganizationTeam,} = useOrganizationTeams(); + const { activeTeam, updateOrganizationTeam, } = useOrganizationTeams(); const { updateAvatar } = useSettings(); const activeTeamRef = useSyncRef(activeTeam);