// frontend/components/tasks/KanbanView.tsx "use client"; import { useState } from "react"; import { Icon } from "@/components/Icon"; import { cx } from "@/lib/cx"; import { COLUMNS } from "@/lib/tasks/tree"; import type { Person, Project, Status, Task } from "@/lib/types"; import { KanbanCard } from "./KanbanCard"; export function KanbanView({ tasks, people, projects, onOpen, onMove, onAdd, onReorder, }: { tasks: Task[]; people: Record; projects: Record; onOpen: (id: string) => void; onMove: (id: string, status: Status) => void; onAdd: (status: Status, title: string) => void; onReorder?: (ids: string[]) => void; }) { const [dragId, setDragId] = useState(null); const [overCol, setOverCol] = useState(null); const [overId, setOverId] = useState(null); const [overAfter, setOverAfter] = useState(false); const [addCol, setAddCol] = useState(null); const [text, setText] = useState(""); const submit = (status: Status) => { if (text.trim()) onAdd(status, text.trim()); setText(""); setAddCol(null); }; const clearDrag = () => { setDragId(null); setOverCol(null); setOverId(null); }; const handleDrop = async (colId: string) => { const id = dragId; const oid = overId; const oaft = overAfter; clearDrag(); if (!id) return; const dragged = tasks.find((t) => t.id === id); const sameCol = dragged?.status === colId; const colIds = tasks.filter((t) => t.status === colId && t.id !== id).map((t) => t.id); let idx = colIds.length; if (oid && oid !== id) { const at = colIds.indexOf(oid); if (at >= 0) idx = at + (oaft ? 1 : 0); } const newIds = [...colIds.slice(0, idx), id, ...colIds.slice(idx)]; if (!sameCol) await onMove(id, colId as Status); if (onReorder) await onReorder(newIds); }; return (
{COLUMNS.map((col) => { const items = tasks.filter((t) => t.status === col.id); return (
{ e.preventDefault(); if (overCol !== col.id) setOverCol(col.id); }} onDragLeave={(e) => { if (e.currentTarget === e.target) setOverCol(null); }} onDrop={(e) => { e.preventDefault(); void handleDrop(col.id); }} >
{col.label} {items.length}
{addCol === col.id && (
setText(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") submit(col.id as Status); if (e.key === "Escape") setAddCol(null); }} onBlur={() => submit(col.id as Status)} />
)} {items.map((t) => ( { setDragId(t.id); e.dataTransfer.effectAllowed = "move"; }} onDragEnd={clearDrag} onDragOver={(e) => { if (!dragId || dragId === t.id) return; const r = e.currentTarget.getBoundingClientRect(); setOverId(t.id); setOverAfter(e.clientY > r.top + r.height / 2); }} /> ))} {items.length === 0 && addCol !== col.id && (
여기로 작업을 옮겨보세요
)}
); })}
); }