diff --git a/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/EnhancedKanbanBoardNativeDnD.tsx b/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/EnhancedKanbanBoardNativeDnD.tsx
index 2c87afe7..01600dfb 100644
--- a/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/EnhancedKanbanBoardNativeDnD.tsx
+++ b/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/EnhancedKanbanBoardNativeDnD.tsx
@@ -1,8 +1,6 @@
-import React, { useState, useEffect, useMemo } from 'react';
+import React, { useState, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { RootState } from '@/app/store';
-import { ITaskListGroup } from '@/types/tasks/taskList.types';
-import { IProjectTask } from '@/types/project/projectTasksViewModel.types';
import '../EnhancedKanbanBoard.css';
import '../EnhancedKanbanGroup.css';
import '../EnhancedKanbanTaskCard.css';
@@ -13,108 +11,9 @@ import Empty from 'antd/es/empty';
import { reorderGroups, reorderEnhancedKanbanGroups, reorderTasks, reorderEnhancedKanbanTasks, fetchEnhancedKanbanLabels, fetchEnhancedKanbanGroups, fetchEnhancedKanbanTaskAssignees } from '@/features/enhanced-kanban/enhanced-kanban.slice';
import { fetchStatusesCategories } from '@/features/taskAttributes/taskStatusSlice';
import { useAppSelector } from '@/hooks/useAppSelector';
+import KanbanGroup from './KanbanGroup';
-// Minimal task card for prototype (reuse your styles)
-const TaskCard: React.FC<{
- task: IProjectTask;
- onTaskDragStart: (e: React.DragEvent, taskId: string, groupId: string) => void;
- onTaskDragOver: (e: React.DragEvent, groupId: string, taskIdx: number) => void;
- onTaskDrop: (e: React.DragEvent, groupId: string, taskIdx: number) => void;
- groupId: string;
- isDropIndicator: boolean;
- idx: number;
-}> = ({ task, onTaskDragStart, onTaskDragOver, onTaskDrop, groupId, isDropIndicator, idx }) => {
- const themeMode = useSelector((state: RootState) => state.themeReducer.mode);
- const background = themeMode === 'dark' ? '#23272f' : '#fff';
- const color = themeMode === 'dark' ? '#fff' : '#23272f';
- return (
- <>
- {isDropIndicator && (
-
- )}
- onTaskDragStart(e, task.id!, groupId)}
- onDragOver={e => onTaskDragOver(e, groupId, idx)}
- onDrop={e => onTaskDrop(e, groupId, idx)}
- style={{ background, color }}
- >
-
-
{task.name}
-
{task.task_key}
-
- {task.assignees?.map(a => a.name).join(', ')}
-
-
-
- >
- );
-};
-// Minimal group column for prototype
-const KanbanGroup: React.FC<{
- group: ITaskListGroup;
- onGroupDragStart: (e: React.DragEvent, groupId: string) => void;
- onGroupDragOver: (e: React.DragEvent) => void;
- onGroupDrop: (e: React.DragEvent, groupId: string) => void;
- onTaskDragStart: (e: React.DragEvent, taskId: string, groupId: string) => void;
- onTaskDragOver: (e: React.DragEvent, groupId: string, taskIdx: number) => void;
- onTaskDrop: (e: React.DragEvent, groupId: string, taskIdx: number) => void;
- hoveredTaskIdx: number | null;
- hoveredGroupId: string | null;
-}> = ({ group, onGroupDragStart, onGroupDragOver, onGroupDrop, onTaskDragStart, onTaskDragOver, onTaskDrop, hoveredTaskIdx, hoveredGroupId }) => {
- const themeMode = useAppSelector(state => state.themeReducer.mode);
- const headerBackgroundColor = useMemo(() => {
- if (themeMode === 'dark') {
- return group.color_code_dark || group.color_code || '#1e1e1e';
- }
- return group.color_code || '#f5f5f5';
- }, [themeMode, group.color_code, group.color_code_dark]);
- return (
-
-
onGroupDragStart(e, group.id)}
- onDragOver={onGroupDragOver}
- onDrop={e => onGroupDrop(e, group.id)}
- >
-
{group.name}
- {group.tasks.length}
-
-
onTaskDragOver(e, group.id, 0)}
- // onDrop={e => onTaskDrop(e, group.id, 0)}
- >
- {/* Drop indicator at the top of the group */}
- {hoveredGroupId === group.id && hoveredTaskIdx === 0 && (
-
- )}
- {group.tasks.map((task, idx) => (
-
-
-
- ))}
- {/* Drop indicator at the end of the group */}
- {hoveredGroupId === group.id && hoveredTaskIdx === group.tasks.length && (
-
- )}
-
-
- )
-};
const EnhancedKanbanBoardNativeDnD: React.FC<{ projectId: string }> = ({ projectId }) => {
const dispatch = useDispatch();
diff --git a/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/KanbanGroup.tsx b/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/KanbanGroup.tsx
new file mode 100644
index 00000000..f69ad544
--- /dev/null
+++ b/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/KanbanGroup.tsx
@@ -0,0 +1,88 @@
+import React, { memo, useMemo } from 'react';
+import { useAppSelector } from '@/hooks/useAppSelector';
+import { ITaskListGroup } from '@/types/tasks/taskList.types';
+import TaskCard from './TaskCard';
+
+interface KanbanGroupProps {
+ group: ITaskListGroup;
+ onGroupDragStart: (e: React.DragEvent, groupId: string) => void;
+ onGroupDragOver: (e: React.DragEvent) => void;
+ onGroupDrop: (e: React.DragEvent, groupId: string) => void;
+ onTaskDragStart: (e: React.DragEvent, taskId: string, groupId: string) => void;
+ onTaskDragOver: (e: React.DragEvent, groupId: string, taskIdx: number) => void;
+ onTaskDrop: (e: React.DragEvent, groupId: string, taskIdx: number) => void;
+ hoveredTaskIdx: number | null;
+ hoveredGroupId: string | null;
+}
+
+const KanbanGroup: React.FC = memo(({
+ group,
+ onGroupDragStart,
+ onGroupDragOver,
+ onGroupDrop,
+ onTaskDragStart,
+ onTaskDragOver,
+ onTaskDrop,
+ hoveredTaskIdx,
+ hoveredGroupId
+}) => {
+ const themeMode = useAppSelector(state => state.themeReducer.mode);
+
+ const headerBackgroundColor = useMemo(() => {
+ if (themeMode === 'dark') {
+ return group.color_code_dark || group.color_code || '#1e1e1e';
+ }
+ return group.color_code || '#f5f5f5';
+ }, [themeMode, group.color_code, group.color_code_dark]);
+
+ return (
+
+
onGroupDragStart(e, group.id)}
+ onDragOver={onGroupDragOver}
+ onDrop={e => onGroupDrop(e, group.id)}
+ >
+
{group.name}
+ {group.tasks.length}
+
+
+ {/* Drop indicator at the top of the group */}
+ {hoveredGroupId === group.id && hoveredTaskIdx === 0 && (
+
+ )}
+
+ {group.tasks.map((task, idx) => (
+
+
+
+ ))}
+
+ {/* Drop indicator at the end of the group */}
+ {hoveredGroupId === group.id && hoveredTaskIdx === group.tasks.length && (
+
+ )}
+
+
+ );
+});
+
+KanbanGroup.displayName = 'KanbanGroup';
+
+export default KanbanGroup;
\ No newline at end of file
diff --git a/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/TaskCard.tsx b/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/TaskCard.tsx
new file mode 100644
index 00000000..f70761c6
--- /dev/null
+++ b/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/TaskCard.tsx
@@ -0,0 +1,64 @@
+import React, { memo } from 'react';
+import { useSelector } from 'react-redux';
+import { RootState } from '@/app/store';
+import { IProjectTask } from '@/types/project/projectTasksViewModel.types';
+
+interface TaskCardProps {
+ task: IProjectTask;
+ onTaskDragStart: (e: React.DragEvent, taskId: string, groupId: string) => void;
+ onTaskDragOver: (e: React.DragEvent, groupId: string, taskIdx: number) => void;
+ onTaskDrop: (e: React.DragEvent, groupId: string, taskIdx: number) => void;
+ groupId: string;
+ isDropIndicator: boolean;
+ idx: number;
+}
+
+const TaskCard: React.FC = memo(({
+ task,
+ onTaskDragStart,
+ onTaskDragOver,
+ onTaskDrop,
+ groupId,
+ isDropIndicator,
+ idx
+}) => {
+ const themeMode = useSelector((state: RootState) => state.themeReducer.mode);
+ const background = themeMode === 'dark' ? '#23272f' : '#fff';
+ const color = themeMode === 'dark' ? '#fff' : '#23272f';
+
+ return (
+ <>
+ {isDropIndicator && (
+
+ )}
+ onTaskDragStart(e, task.id!, groupId)}
+ onDragOver={e => onTaskDragOver(e, groupId, idx)}
+ onDrop={e => onTaskDrop(e, groupId, idx)}
+ style={{ background, color }}
+ >
+
+
{task.name}
+
{task.task_key}
+
+ {task.assignees?.map(a => a.name).join(', ')}
+
+
+
+ >
+ );
+});
+
+TaskCard.displayName = 'TaskCard';
+
+export default TaskCard;
\ No newline at end of file
diff --git a/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/index.ts b/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/index.ts
new file mode 100644
index 00000000..1ddc40f1
--- /dev/null
+++ b/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/index.ts
@@ -0,0 +1,3 @@
+export { default } from './EnhancedKanbanBoardNativeDnD';
+export { default as TaskCard } from './TaskCard';
+export { default as KanbanGroup } from './KanbanGroup';
\ No newline at end of file