import { useCallback, useState } from "react"; import { Link, Clock } from "lucide-react"; import type { Task, TaskDetail, Column } from "@hai/core"; import { fetchTaskDetail } from "../api"; import type { ToastType } from "../hooks/useToast"; const COLUMN_COLOR_MAP: Record = { triage: "rgba(210,153,34,0.15)", todo: "rgba(88,166,255,0.15)", "in-progress": "rgba(188,140,255,0.15)", "in-review": "rgba(63,185,80,0.15)", done: "rgba(139,148,158,0.15)", }; const COLUMN_TEXT_COLOR_MAP: Record = { triage: "var(--triage)", todo: "var(--todo)", "in-progress": "var(--in-progress)", "in-review": "var(--in-review)", done: "var(--done)", }; const ACTIVE_STATUSES = new Set(["planning", "researching", "executing", "finalizing", "merging", "specifying"]); interface TaskCardProps { task: Task; queued?: boolean; onOpenDetail: (task: TaskDetail) => void; addToast: (message: string, type?: ToastType) => void; } export function TaskCard({ task, queued, onOpenDetail, addToast }: TaskCardProps) { const [dragging, setDragging] = useState(false); const handleDragStart = useCallback((e: React.DragEvent) => { e.dataTransfer.setData("text/plain", task.id); e.dataTransfer.effectAllowed = "move"; setDragging(true); }, [task.id]); const handleDragEnd = useCallback(() => { setDragging(false); }, []); const handleClick = useCallback(async () => { try { const detail = await fetchTaskDetail(task.id); onOpenDetail(detail); } catch (err: any) { addToast("Failed to load task details", "error"); } }, [task.id, onOpenDetail, addToast]); const isAgentActive = !queued && (task.column === "in-progress" || ACTIVE_STATUSES.has(task.status as string)); const cardClass = `card${dragging ? " dragging" : ""}${queued ? " queued" : ""}${isAgentActive ? " agent-active" : ""}`; return (
{task.id} {task.status && task.status !== "queued" && ( {task.status} )}
{task.title || (task.description ? task.description.slice(0, 60) + (task.description.length > 60 ? "…" : "") : task.id)}
{task.steps.length > 0 && (() => { const completedSteps = task.steps.filter(s => s.status === "done").length; const totalSteps = task.steps.length; return (
{completedSteps}/{totalSteps}
); })()} {((task.dependencies && task.dependencies.length > 0) || queued || task.status === "queued") && (
{task.dependencies && task.dependencies.length > 0 && ( {task.dependencies.length} dep{task.dependencies.length > 1 ? "s" : ""} )} {(queued || task.status === "queued") && Queued}
)}
); }