"use client"; import { useEffect, useState } from "react"; import { Task, getTasks, updateTask, createTask } from "@/lib/api"; const COLUMNS = [ { key: "draft", label: "Backlog", color: "#737373" }, { key: "ready", label: "TODO", color: "#3b82f6" }, { key: "in_progress", label: "In Progress", color: "#f59e0b" }, { key: "review", label: "Review", color: "#a855f7" }, { key: "completed", label: "Done", color: "#22c55e" }, ]; const PRIORITY_COLORS: Record = { critical: "#ef4444", high: "#f59e0b", medium: "#3b82f6", low: "#737373", }; interface Props { projectId: string; } export default function KanbanBoard({ projectId }: Props) { const [tasks, setTasks] = useState([]); const [loading, setLoading] = useState(true); const [newTaskTitle, setNewTaskTitle] = useState(""); const [addingTo, setAddingTo] = useState(null); const [draggedTask, setDraggedTask] = useState(null); const loadTasks = async () => { try { const data = await getTasks(projectId); setTasks(data); } finally { setLoading(false); } }; useEffect(() => { loadTasks(); }, [projectId]); const handleDrop = async (status: string) => { if (!draggedTask) return; const task = tasks.find((t) => t.id === draggedTask); if (!task || task.status === status) return; // Optimistic update setTasks((prev) => prev.map((t) => (t.id === draggedTask ? { ...t, status } : t))); setDraggedTask(null); try { await updateTask(draggedTask, { status }); } catch { loadTasks(); // revert } }; const handleAddTask = async (status: string) => { if (!newTaskTitle.trim()) return; try { const task = await createTask({ project_id: projectId, title: newTaskTitle.trim(), status, }); setTasks((prev) => [...prev, task]); setNewTaskTitle(""); setAddingTo(null); } catch (e) { console.error(e); } }; if (loading) { return
Загрузка...
; } return (
{COLUMNS.map((col) => { const colTasks = tasks.filter((t) => t.status === col.key); return (
e.preventDefault()} onDrop={() => handleDrop(col.key)} > {/* Column header */}
{col.label} {colTasks.length}
{/* Cards */}
{colTasks.map((task) => (
setDraggedTask(task.id)} className="bg-[var(--card)] border border-[var(--border)] rounded-lg p-3 cursor-grab hover:border-[var(--accent)] transition-colors active:cursor-grabbing" >
{task.title}
{task.description && (

{task.description}

)}
))} {/* Add task */} {addingTo === col.key ? (
setNewTaskTitle(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") handleAddTask(col.key); if (e.key === "Escape") setAddingTo(null); }} onBlur={() => { if (!newTaskTitle.trim()) setAddingTo(null); }} />
) : ( )}
); })}
); }