feat(enhanced-kanban): implement synchronous reordering for tasks and groups

- Added synchronous state updates for task and group reordering in the EnhancedKanbanBoard component, improving UI responsiveness during drag-and-drop operations.
- Introduced new actions `reorderTasks` and `reorderGroups` in the enhanced-kanban slice for better state management.
- Updated EnhancedKanbanGroup and EnhancedKanbanTaskCard components to utilize the new layout change animations, enhancing the user experience during reordering.
This commit is contained in:
shancds
2025-06-23 14:08:32 +05:30
parent 6508dc6c64
commit b436db183f
4 changed files with 62 additions and 10 deletions

View File

@@ -27,7 +27,9 @@ import {
fetchEnhancedKanbanGroups,
reorderEnhancedKanbanTasks,
reorderEnhancedKanbanGroups,
setDragState
setDragState,
reorderTasks,
reorderGroups,
} from '@/features/enhanced-kanban/enhanced-kanban.slice';
import EnhancedKanbanGroup from './EnhancedKanbanGroup';
import EnhancedKanbanTaskCard from './EnhancedKanbanTaskCard';
@@ -210,12 +212,10 @@ const EnhancedKanbanBoard: React.FC<EnhancedKanbanBoardProps> = ({ projectId, cl
const [movedGroup] = reorderedGroups.splice(fromIndex, 1);
reorderedGroups.splice(toIndex, 0, movedGroup);
// Dispatch group reorder action
dispatch(reorderEnhancedKanbanGroups({
fromIndex,
toIndex,
reorderedGroups,
}) as any);
// Synchronous UI update
dispatch(reorderGroups({ fromIndex, toIndex, reorderedGroups }));
// Async backend sync (optional)
dispatch(reorderEnhancedKanbanGroups({ fromIndex, toIndex, reorderedGroups }) as any);
}
return;
}
@@ -274,7 +274,17 @@ const EnhancedKanbanBoard: React.FC<EnhancedKanbanBoardProps> = ({ projectId, cl
updatedTargetTasks.splice(targetIndex, 0, movedTask);
}
// Dispatch the reorder action
// Synchronous UI update
dispatch(reorderTasks({
activeGroupId: sourceGroup.id,
overGroupId: targetGroup.id,
fromIndex: sourceIndex,
toIndex: targetIndex,
task: movedTask,
updatedSourceTasks,
updatedTargetTasks,
}));
// Async backend sync (optional)
dispatch(reorderEnhancedKanbanTasks({
activeGroupId: sourceGroup.id,
overGroupId: targetGroup.id,

View File

@@ -1,6 +1,6 @@
import React, { useMemo, useRef, useEffect, useState } from 'react';
import { useDroppable } from '@dnd-kit/core';
import { SortableContext, verticalListSortingStrategy, useSortable } from '@dnd-kit/sortable';
import { SortableContext, verticalListSortingStrategy, useSortable, defaultAnimateLayoutChanges } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { ITaskListGroup } from '@/types/tasks/taskList.types';
import EnhancedKanbanTaskCard from './EnhancedKanbanTaskCard';
@@ -46,6 +46,7 @@ const EnhancedKanbanGroup: React.FC<EnhancedKanbanGroupProps> = React.memo(({
type: 'group',
group,
},
animateLayoutChanges: defaultAnimateLayoutChanges,
});
const groupRef = useRef<HTMLDivElement>(null);

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { useSortable } from '@dnd-kit/sortable';
import { useSortable, defaultAnimateLayoutChanges } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { IProjectTask } from '@/types/project/projectTasksViewModel.types';
import { useAppSelector } from '@/hooks/useAppSelector';
@@ -34,6 +34,7 @@ const EnhancedKanbanTaskCard: React.FC<EnhancedKanbanTaskCardProps> = React.memo
task,
},
disabled: isDragOverlay,
animateLayoutChanges: defaultAnimateLayoutChanges,
});
const style = {

View File

@@ -402,6 +402,44 @@ const enhancedKanbanSlice = createSlice({
resetState: (state) => {
return { ...initialState, groupBy: state.groupBy };
},
// Synchronous reorder for tasks
reorderTasks: (state, action: PayloadAction<{
activeGroupId: string;
overGroupId: string;
fromIndex: number;
toIndex: number;
task: IProjectTask;
updatedSourceTasks: IProjectTask[];
updatedTargetTasks: IProjectTask[];
}>) => {
const { activeGroupId, overGroupId, updatedSourceTasks, updatedTargetTasks } = action.payload;
const sourceGroupIndex = state.taskGroups.findIndex(group => group.id === activeGroupId);
const targetGroupIndex = state.taskGroups.findIndex(group => group.id === overGroupId);
if (sourceGroupIndex !== -1) {
state.taskGroups[sourceGroupIndex].tasks = updatedSourceTasks;
state.groupCache[activeGroupId] = state.taskGroups[sourceGroupIndex];
}
if (targetGroupIndex !== -1 && activeGroupId !== overGroupId) {
state.taskGroups[targetGroupIndex].tasks = updatedTargetTasks;
state.groupCache[overGroupId] = state.taskGroups[targetGroupIndex];
}
},
// Synchronous reorder for groups
reorderGroups: (state, action: PayloadAction<{
fromIndex: number;
toIndex: number;
reorderedGroups: ITaskListGroup[];
}>) => {
const { reorderedGroups } = action.payload;
state.taskGroups = reorderedGroups;
state.groupCache = reorderedGroups.reduce((cache, group) => {
cache[group.id] = group;
return cache;
}, {} as Record<string, ITaskListGroup>);
state.columnOrder = reorderedGroups.map(group => group.id);
},
},
extraReducers: (builder) => {
builder
@@ -488,6 +526,8 @@ export const {
updateTaskPriority,
deleteTask,
resetState,
reorderTasks,
reorderGroups,
} = enhancedKanbanSlice.actions;
export default enhancedKanbanSlice.reducer;