From b6c056dd1adb199d3ce216b5e98727679ffd024a Mon Sep 17 00:00:00 2001 From: chamikaJ Date: Wed, 30 Jul 2025 15:26:27 +0530 Subject: [PATCH] feat(task-status-dropdown): enhance task status update and group movement handling - Added logic to optimistically update task status in Redux for immediate feedback. - Implemented group movement handling when tasks are updated based on their status, ensuring tasks are moved between groups as needed. - Improved socket event emissions for real-time updates, including parent task handling. - Refactored group selection logic to streamline target group identification based on status ID and group value. --- .../task-management/task-status-dropdown.tsx | 43 ++++++++++++++-- .../src/hooks/useTaskSocketHandlers.ts | 51 ++++--------------- 2 files changed, 50 insertions(+), 44 deletions(-) diff --git a/worklenz-frontend/src/components/task-management/task-status-dropdown.tsx b/worklenz-frontend/src/components/task-management/task-status-dropdown.tsx index 302367c0..bf298154 100644 --- a/worklenz-frontend/src/components/task-management/task-status-dropdown.tsx +++ b/worklenz-frontend/src/components/task-management/task-status-dropdown.tsx @@ -8,6 +8,8 @@ import { Task } from '@/types/task-management.types'; import { updateTask, selectCurrentGroupingV3, + selectGroups, + moveTaskBetweenGroups, } from '@/features/task-management/task-management.slice'; interface TaskStatusDropdownProps { @@ -30,6 +32,7 @@ const TaskStatusDropdown: React.FC = ({ const statusList = useAppSelector(state => state.taskStatusReducer.status); const currentGroupingV3 = useAppSelector(selectCurrentGroupingV3); + const groups = useAppSelector(selectGroups); // Find current status details const currentStatus = useMemo(() => { @@ -44,21 +47,53 @@ const TaskStatusDropdown: React.FC = ({ (statusId: string, statusName: string) => { if (!task.id || !statusId || !connected) return; - console.log('🎯 Status change initiated:', { taskId: task.id, statusId, statusName }); + // Optimistic update: immediately update the task status in Redux for instant feedback + const updatedTask = { + ...task, + status: statusId, + updatedAt: new Date().toISOString(), + }; + dispatch(updateTask(updatedTask)); + // Handle group movement if grouping by status + if (currentGroupingV3 === 'status' && groups && groups.length > 0) { + // Find current group containing the task + const currentGroup = groups.find(group => group.taskIds.includes(task.id)); + + // Find target group based on the new status ID + let targetGroup = groups.find(group => group.id === statusId); + + // If not found by status ID, try matching with group value + if (!targetGroup) { + targetGroup = groups.find(group => group.groupValue === statusId); + } + + if (currentGroup && targetGroup && currentGroup.id !== targetGroup.id) { + // Move task between groups immediately for instant feedback + dispatch( + moveTaskBetweenGroups({ + taskId: task.id, + sourceGroupId: currentGroup.id, + targetGroupId: targetGroup.id, + }) + ); + } + } + + // Emit socket event for server-side update and real-time sync socket?.emit( SocketEvents.TASK_STATUS_CHANGE.toString(), JSON.stringify({ task_id: task.id, status_id: statusId, - parent_task: null, // Assuming top-level tasks for now - team_id: projectId, // Using projectId as teamId + parent_task: task.parent_task_id || null, + team_id: projectId, }) ); socket?.emit(SocketEvents.GET_TASK_PROGRESS.toString(), task.id); setIsOpen(false); }, - [task.id, connected, socket, projectId] + [task, connected, socket, projectId, dispatch, currentGroupingV3, groups] ); // Calculate dropdown position and handle outside clicks diff --git a/worklenz-frontend/src/hooks/useTaskSocketHandlers.ts b/worklenz-frontend/src/hooks/useTaskSocketHandlers.ts index 42001f8a..72a1f71a 100644 --- a/worklenz-frontend/src/hooks/useTaskSocketHandlers.ts +++ b/worklenz-frontend/src/hooks/useTaskSocketHandlers.ts @@ -244,44 +244,18 @@ export const useTaskSocketHandlers = () => { // Find current group containing the task const currentGroup = groups.find(group => group.taskIds.includes(response.id)); - // Find target group based on new status value with multiple matching strategies - let targetGroup = groups.find(group => group.groupValue === newStatusValue); + // Find target group based on the actual status ID from response + let targetGroup = groups.find(group => group.id === response.status_id); - // If not found, try case-insensitive matching + // If not found by status ID, try matching with group value if (!targetGroup) { - targetGroup = groups.find(group => - group.groupValue?.toLowerCase() === newStatusValue.toLowerCase() - ); + targetGroup = groups.find(group => group.groupValue === response.status_id); } - // If still not found, try matching with title - if (!targetGroup) { + // If still not found, try matching by status name (fallback) + if (!targetGroup && response.status) { targetGroup = groups.find(group => - group.title?.toLowerCase() === newStatusValue.toLowerCase() - ); - } - - // If still not found, try matching common status patterns - if (!targetGroup && newStatusValue === 'todo') { - targetGroup = groups.find(group => - group.title?.toLowerCase().includes('todo') || - group.title?.toLowerCase().includes('to do') || - group.title?.toLowerCase().includes('pending') || - group.groupValue?.toLowerCase().includes('todo') - ); - } else if (!targetGroup && newStatusValue === 'doing') { - targetGroup = groups.find(group => - group.title?.toLowerCase().includes('doing') || - group.title?.toLowerCase().includes('progress') || - group.title?.toLowerCase().includes('active') || - group.groupValue?.toLowerCase().includes('doing') - ); - } else if (!targetGroup && newStatusValue === 'done') { - targetGroup = groups.find(group => - group.title?.toLowerCase().includes('done') || - group.title?.toLowerCase().includes('complete') || - group.title?.toLowerCase().includes('finish') || - group.groupValue?.toLowerCase().includes('done') + group.title?.toLowerCase() === response.status.toLowerCase() ); } @@ -295,14 +269,11 @@ export const useTaskSocketHandlers = () => { }) ); } else if (!targetGroup) { - console.log('❌ Target group not found for status:', newStatusValue); - } else if (!currentGroup) { - console.log('❌ Current group not found for task:', response.id); - } else { - console.log('🔧 No group movement needed - task already in correct group'); + // Fallback: refetch tasks to ensure consistency + if (projectId) { + dispatch(fetchTasksV3(projectId)); + } } - } else { - console.log('🔧 Not grouped by status, skipping group movement'); } } },