diff --git a/worklenz-frontend/src/components/taskListCommon/task-list-bulk-actions-bar/task-list-bulk-actions-bar.tsx b/worklenz-frontend/src/components/taskListCommon/task-list-bulk-actions-bar/task-list-bulk-actions-bar.tsx index ce38df32..0099ae11 100644 --- a/worklenz-frontend/src/components/taskListCommon/task-list-bulk-actions-bar/task-list-bulk-actions-bar.tsx +++ b/worklenz-frontend/src/components/taskListCommon/task-list-bulk-actions-bar/task-list-bulk-actions-bar.tsx @@ -58,7 +58,7 @@ import alertService from '@/services/alerts/alertService'; interface ITaskAssignee { id: string; - name?: string; + name: string; email?: string; avatar_url?: string; team_member_id: string; @@ -437,7 +437,7 @@ const TaskListBulkActionsBar = () => { placement="top" arrow trigger={['click']} - destroyPopupOnHide + destroyOnHidden onOpenChange={value => { if (!value) { setSelectedLabels([]); diff --git a/worklenz-frontend/src/features/navbar/timers/timer-button.tsx b/worklenz-frontend/src/features/navbar/timers/timer-button.tsx index c4a229e8..b9e050f0 100644 --- a/worklenz-frontend/src/features/navbar/timers/timer-button.tsx +++ b/worklenz-frontend/src/features/navbar/timers/timer-button.tsx @@ -241,7 +241,7 @@ const TimerButton = () => { return ( dropdownContent} + popupRender={() => dropdownContent} trigger={['click']} placement="bottomRight" open={dropdownOpen} diff --git a/worklenz-frontend/src/hooks/useTaskDragAndDrop.ts b/worklenz-frontend/src/hooks/useTaskDragAndDrop.ts index cab0a361..cfadee8a 100644 --- a/worklenz-frontend/src/hooks/useTaskDragAndDrop.ts +++ b/worklenz-frontend/src/hooks/useTaskDragAndDrop.ts @@ -19,10 +19,10 @@ import { IProjectTask } from '@/types/project/projectTasksViewModel.types'; export const useTaskDragAndDrop = () => { const dispatch = useAppDispatch(); - const { taskGroups, groupBy } = useAppSelector(state => ({ - taskGroups: state.taskReducer.taskGroups, - groupBy: state.taskReducer.groupBy, - })); + + // Memoize the selector to prevent unnecessary rerenders + const taskGroups = useAppSelector(state => state.taskReducer.taskGroups); + const groupBy = useAppSelector(state => state.taskReducer.groupBy); // Memoize sensors configuration for better performance const sensors = useSensors( diff --git a/worklenz-frontend/src/pages/projects/projectView/project-view.tsx b/worklenz-frontend/src/pages/projects/projectView/project-view.tsx index d1ff8b9d..d3391109 100644 --- a/worklenz-frontend/src/pages/projects/projectView/project-view.tsx +++ b/worklenz-frontend/src/pages/projects/projectView/project-view.tsx @@ -177,7 +177,7 @@ const ProjectView = () => { onChange={handleTabChange} items={tabMenuItems} tabBarStyle={{ paddingInline: 0 }} - destroyInactiveTabPane={true} + destroyOnHidden={true} /> {portalElements} diff --git a/worklenz-frontend/src/pages/projects/projectView/taskList/project-view-task-list.tsx b/worklenz-frontend/src/pages/projects/projectView/taskList/project-view-task-list.tsx index 29914771..9b0524f5 100644 --- a/worklenz-frontend/src/pages/projects/projectView/taskList/project-view-task-list.tsx +++ b/worklenz-frontend/src/pages/projects/projectView/taskList/project-view-task-list.tsx @@ -19,36 +19,19 @@ const ProjectViewTaskList = () => { const [searchParams, setSearchParams] = useSearchParams(); const [initialLoadComplete, setInitialLoadComplete] = useState(false); - // Combine related selectors to reduce subscriptions - const { - projectId, - taskGroups, - loadingGroups, - groupBy, - archived, - fields, - search, - } = useAppSelector(state => ({ - projectId: state.projectReducer.projectId, - taskGroups: state.taskReducer.taskGroups, - loadingGroups: state.taskReducer.loadingGroups, - groupBy: state.taskReducer.groupBy, - archived: state.taskReducer.archived, - fields: state.taskReducer.fields, - search: state.taskReducer.search, - })); + // Split selectors to prevent unnecessary rerenders + const projectId = useAppSelector(state => state.projectReducer.projectId); + const taskGroups = useAppSelector(state => state.taskReducer.taskGroups); + const loadingGroups = useAppSelector(state => state.taskReducer.loadingGroups); + const groupBy = useAppSelector(state => state.taskReducer.groupBy); + const archived = useAppSelector(state => state.taskReducer.archived); + const fields = useAppSelector(state => state.taskReducer.fields); + const search = useAppSelector(state => state.taskReducer.search); - const { - statusCategories, - loading: loadingStatusCategories, - } = useAppSelector(state => ({ - statusCategories: state.taskStatusReducer.statusCategories, - loading: state.taskStatusReducer.loading, - })); + const statusCategories = useAppSelector(state => state.taskStatusReducer.statusCategories); + const loadingStatusCategories = useAppSelector(state => state.taskStatusReducer.loading); - const { loadingPhases } = useAppSelector(state => ({ - loadingPhases: state.phaseReducer.loadingPhases, - })); + const loadingPhases = useAppSelector(state => state.phaseReducer.loadingPhases); // Single source of truth for loading state - EXCLUDE labels loading from skeleton // Labels loading should not block the main task list display