Enhance task status handling and progress visualization in Kanban board
- Introduced a mechanism to emit a socket event when a task's status changes during drag-and-drop operations. - Updated TaskCard to consistently display the progress circle regardless of task completion state. - Improved TaskProgressCircle to handle complete_ratio and progress more robustly, ensuring accurate visual representation.
This commit is contained in:
@@ -147,11 +147,11 @@ const EnhancedKanbanBoardNativeDnD: React.FC<{ projectId: string }> = ({ project
|
|||||||
const targetGroup = taskGroups.find(g => g.id === targetGroupId);
|
const targetGroup = taskGroups.find(g => g.id === targetGroupId);
|
||||||
if (!sourceGroup || !targetGroup) return;
|
if (!sourceGroup || !targetGroup) return;
|
||||||
|
|
||||||
|
|
||||||
const taskIdx = sourceGroup.tasks.findIndex(t => t.id === draggedTaskId);
|
const taskIdx = sourceGroup.tasks.findIndex(t => t.id === draggedTaskId);
|
||||||
if (taskIdx === -1) return;
|
if (taskIdx === -1) return;
|
||||||
|
|
||||||
const movedTask = sourceGroup.tasks[taskIdx];
|
const movedTask = sourceGroup.tasks[taskIdx];
|
||||||
|
let didStatusChange = false;
|
||||||
if (groupBy === 'status' && movedTask.id) {
|
if (groupBy === 'status' && movedTask.id) {
|
||||||
if (sourceGroup.id !== targetGroup.id) {
|
if (sourceGroup.id !== targetGroup.id) {
|
||||||
const canContinue = await checkTaskDependencyStatus(movedTask.id, targetGroupId);
|
const canContinue = await checkTaskDependencyStatus(movedTask.id, targetGroupId);
|
||||||
@@ -162,6 +162,7 @@ const EnhancedKanbanBoardNativeDnD: React.FC<{ projectId: string }> = ({ project
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
didStatusChange = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let insertIdx = hoveredTaskIdx;
|
let insertIdx = hoveredTaskIdx;
|
||||||
@@ -258,6 +259,18 @@ const EnhancedKanbanBoardNativeDnD: React.FC<{ projectId: string }> = ({ project
|
|||||||
team_id: teamId,
|
team_id: teamId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Emit progress update if status changed
|
||||||
|
if (didStatusChange) {
|
||||||
|
socket.emit(
|
||||||
|
SocketEvents.TASK_STATUS_CHANGE.toString(),
|
||||||
|
JSON.stringify({
|
||||||
|
task_id: movedTask.id,
|
||||||
|
status_id: targetGroupId,
|
||||||
|
parent_task: movedTask.parent_task_id || null,
|
||||||
|
team_id: teamId,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setDraggedTaskId(null);
|
setDraggedTaskId(null);
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ const TaskCard: React.FC<TaskCardProps> = memo(({
|
|||||||
const d = selectedDate || new Date();
|
const d = selectedDate || new Date();
|
||||||
return new Date(d.getFullYear(), d.getMonth(), 1);
|
return new Date(d.getFullYear(), d.getMonth(), 1);
|
||||||
});
|
});
|
||||||
const [showSubtasks, setShowSubtasks] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSelectedDate(task.end_date ? new Date(task.end_date) : null);
|
setSelectedDate(task.end_date ? new Date(task.end_date) : null);
|
||||||
@@ -205,11 +204,9 @@ const TaskCard: React.FC<TaskCardProps> = memo(({
|
|||||||
<>
|
<>
|
||||||
<div className="enhanced-kanban-task-card" style={{ background, color, display: 'block', position: 'relative' }} >
|
<div className="enhanced-kanban-task-card" style={{ background, color, display: 'block', position: 'relative' }} >
|
||||||
{/* Progress circle at top right */}
|
{/* Progress circle at top right */}
|
||||||
{task.progress > 0 && (
|
<div style={{ position: 'absolute', top: 6, right: 6, zIndex: 2 }}>
|
||||||
<div style={{ position: 'absolute', top: 6, right: 6, zIndex: 2 }}>
|
<TaskProgressCircle task={task} size={20} />
|
||||||
<TaskProgressCircle task={task} size={20} />
|
</div>
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div
|
<div
|
||||||
draggable
|
draggable
|
||||||
onDragStart={e => onTaskDragStart(e, task.id!, groupId)}
|
onDragStart={e => onTaskDragStart(e, task.id!, groupId)}
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ import { IProjectTask } from "@/types/project/projectTasksViewModel.types";
|
|||||||
|
|
||||||
// Add a simple circular progress component
|
// Add a simple circular progress component
|
||||||
const TaskProgressCircle: React.FC<{ task: IProjectTask; size?: number }> = ({ task, size = 28 }) => {
|
const TaskProgressCircle: React.FC<{ task: IProjectTask; size?: number }> = ({ task, size = 28 }) => {
|
||||||
const progress = task.progress ?? 0;
|
const progress = typeof task.complete_ratio === 'number'
|
||||||
|
? task.complete_ratio
|
||||||
|
: (typeof task.progress === 'number' ? task.progress : 0);
|
||||||
const strokeWidth = 1.5;
|
const strokeWidth = 1.5;
|
||||||
const radius = (size - strokeWidth) / 2;
|
const radius = (size - strokeWidth) / 2;
|
||||||
const circumference = 2 * Math.PI * radius;
|
const circumference = 2 * Math.PI * radius;
|
||||||
@@ -22,7 +24,7 @@ const TaskProgressCircle: React.FC<{ task: IProjectTask; size?: number }> = ({ t
|
|||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
style={{ transition: 'stroke-dashoffset 0.3s' }}
|
style={{ transition: 'stroke-dashoffset 0.3s' }}
|
||||||
/>
|
/>
|
||||||
<text
|
{task.complete_ratio && <text
|
||||||
x="50%"
|
x="50%"
|
||||||
y="50%"
|
y="50%"
|
||||||
textAnchor="middle"
|
textAnchor="middle"
|
||||||
@@ -32,7 +34,7 @@ const TaskProgressCircle: React.FC<{ task: IProjectTask; size?: number }> = ({ t
|
|||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
>
|
>
|
||||||
{Math.round(progress)}
|
{Math.round(progress)}
|
||||||
</text>
|
</text>}
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user