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.
This commit is contained in:
@@ -8,6 +8,8 @@ import { Task } from '@/types/task-management.types';
|
|||||||
import {
|
import {
|
||||||
updateTask,
|
updateTask,
|
||||||
selectCurrentGroupingV3,
|
selectCurrentGroupingV3,
|
||||||
|
selectGroups,
|
||||||
|
moveTaskBetweenGroups,
|
||||||
} from '@/features/task-management/task-management.slice';
|
} from '@/features/task-management/task-management.slice';
|
||||||
|
|
||||||
interface TaskStatusDropdownProps {
|
interface TaskStatusDropdownProps {
|
||||||
@@ -30,6 +32,7 @@ const TaskStatusDropdown: React.FC<TaskStatusDropdownProps> = ({
|
|||||||
|
|
||||||
const statusList = useAppSelector(state => state.taskStatusReducer.status);
|
const statusList = useAppSelector(state => state.taskStatusReducer.status);
|
||||||
const currentGroupingV3 = useAppSelector(selectCurrentGroupingV3);
|
const currentGroupingV3 = useAppSelector(selectCurrentGroupingV3);
|
||||||
|
const groups = useAppSelector(selectGroups);
|
||||||
|
|
||||||
// Find current status details
|
// Find current status details
|
||||||
const currentStatus = useMemo(() => {
|
const currentStatus = useMemo(() => {
|
||||||
@@ -44,21 +47,53 @@ const TaskStatusDropdown: React.FC<TaskStatusDropdownProps> = ({
|
|||||||
(statusId: string, statusName: string) => {
|
(statusId: string, statusName: string) => {
|
||||||
if (!task.id || !statusId || !connected) return;
|
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(
|
socket?.emit(
|
||||||
SocketEvents.TASK_STATUS_CHANGE.toString(),
|
SocketEvents.TASK_STATUS_CHANGE.toString(),
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
task_id: task.id,
|
task_id: task.id,
|
||||||
status_id: statusId,
|
status_id: statusId,
|
||||||
parent_task: null, // Assuming top-level tasks for now
|
parent_task: task.parent_task_id || null,
|
||||||
team_id: projectId, // Using projectId as teamId
|
team_id: projectId,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
socket?.emit(SocketEvents.GET_TASK_PROGRESS.toString(), task.id);
|
socket?.emit(SocketEvents.GET_TASK_PROGRESS.toString(), task.id);
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
},
|
},
|
||||||
[task.id, connected, socket, projectId]
|
[task, connected, socket, projectId, dispatch, currentGroupingV3, groups]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Calculate dropdown position and handle outside clicks
|
// Calculate dropdown position and handle outside clicks
|
||||||
|
|||||||
@@ -244,44 +244,18 @@ export const useTaskSocketHandlers = () => {
|
|||||||
// Find current group containing the task
|
// Find current group containing the task
|
||||||
const currentGroup = groups.find(group => group.taskIds.includes(response.id));
|
const currentGroup = groups.find(group => group.taskIds.includes(response.id));
|
||||||
|
|
||||||
// Find target group based on new status value with multiple matching strategies
|
// Find target group based on the actual status ID from response
|
||||||
let targetGroup = groups.find(group => group.groupValue === newStatusValue);
|
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) {
|
if (!targetGroup) {
|
||||||
targetGroup = groups.find(group =>
|
targetGroup = groups.find(group => group.groupValue === response.status_id);
|
||||||
group.groupValue?.toLowerCase() === newStatusValue.toLowerCase()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If still not found, try matching with title
|
// If still not found, try matching by status name (fallback)
|
||||||
if (!targetGroup) {
|
if (!targetGroup && response.status) {
|
||||||
targetGroup = groups.find(group =>
|
targetGroup = groups.find(group =>
|
||||||
group.title?.toLowerCase() === newStatusValue.toLowerCase()
|
group.title?.toLowerCase() === response.status.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')
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,14 +269,11 @@ export const useTaskSocketHandlers = () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
} else if (!targetGroup) {
|
} else if (!targetGroup) {
|
||||||
console.log('❌ Target group not found for status:', newStatusValue);
|
// Fallback: refetch tasks to ensure consistency
|
||||||
} else if (!currentGroup) {
|
if (projectId) {
|
||||||
console.log('❌ Current group not found for task:', response.id);
|
dispatch(fetchTasksV3(projectId));
|
||||||
} else {
|
}
|
||||||
console.log('🔧 No group movement needed - task already in correct group');
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
console.log('🔧 Not grouped by status, skipping group movement');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user