Files
goal-planner/frontend/components/TaskList.tsx
T
2026-11-02 17:15:39 +08:00

80 lines
3.0 KiB
TypeScript

import React from 'react';
import { Task } from '../types';
import TaskItem from './TaskItem';
interface TaskListProps {
tasks: Task[];
onToggleTask: (taskDbId: number) => void;
onEditTask: (task: Task) => void;
onDeleteTask: (taskDbId: number) => void;
onAddChildTask: (parentTask: Task) => void;
onAddSiblingTask: (task: Task) => void;
onStatusChange: (taskDbId: number, status: string) => void;
onDragStart?: (task: Task) => void;
onDragOver?: (e: React.DragEvent, task: Task) => void;
onDrop?: (e: React.DragEvent, task: Task) => void;
onDragEnd?: () => void;
dragOverTask?: Task | null;
onChildTaskCompleted?: (task: Task, level: number) => void;
onParentTaskCompleted?: (task: Task, level: number) => void;
}
const TaskList: React.FC<TaskListProps> = ({ tasks, onToggleTask, onEditTask, onDeleteTask, onAddChildTask, onAddSiblingTask, onStatusChange, onDragStart, onDragOver, onDrop, onDragEnd, dragOverTask, onChildTaskCompleted, onParentTaskCompleted }) => {
const collectAllTaskIds = (taskList: Task[]): Set<string> => {
const ids = new Set<string>();
const walk = (items: Task[]) => {
for (const t of items) {
if (t.status === 'done') ids.add(t.task_id);
if (t.children?.length) walk(t.children);
}
};
walk(taskList);
return ids;
};
const allCompletedIds = collectAllTaskIds(tasks);
const isTaskLocked = (task: Task): boolean => {
// Check own dependencies
if (task.dependencies.length > 0 && !task.dependencies.every(depId => allCompletedIds.has(depId))) {
return true;
}
// If has children, check if ALL children are locked (recursive)
if (task.children && task.children.length > 0) {
const allChildrenLocked = task.children.every(child => isTaskLocked(child));
if (allChildrenLocked) return true;
}
return false;
};
return (
<div className="space-y-4 sm:space-y-5">
{tasks.map((task, index) => (
<TaskItem
key={task.id}
task={task}
taskNumber={`${index + 1}`}
onToggleTask={onToggleTask}
onEditTask={onEditTask}
onDeleteTask={onDeleteTask}
onAddChildTask={onAddChildTask}
onAddSiblingTask={onAddSiblingTask}
onStatusChange={onStatusChange}
onDragStart={onDragStart}
onDragOver={onDragOver}
onDrop={onDrop}
onDragEnd={onDragEnd}
dragOverTask={dragOverTask}
isLocked={isTaskLocked(task)}
level={0}
isLastChild={index === tasks.length - 1}
onChildTaskCompleted={onChildTaskCompleted}
onParentTaskCompleted={onParentTaskCompleted}
/>
))}
</div>
);
};
export default TaskList;