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:
chamikaJ
2025-07-30 15:26:27 +05:30
parent 81e1872c1f
commit b6c056dd1a
2 changed files with 50 additions and 44 deletions

View File

@@ -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

View File

@@ -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');
} }
} }
}, },