You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
3.7 KiB
TypeScript

// 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,
}: {
tasks: Task[];
people: Record<string, Person>;
projects: Record<string, Project>;
onOpen: (id: string) => void;
onMove: (id: string, status: Status) => void;
onAdd: (status: Status, title: string) => void;
}) {
const [dragId, setDragId] = useState<string | null>(null);
const [overCol, setOverCol] = useState<string | null>(null);
const [addCol, setAddCol] = useState<string | null>(null);
const [text, setText] = useState("");
const submit = (status: Status) => {
if (text.trim()) onAdd(status, text.trim());
setText("");
setAddCol(null);
};
return (
<div className="kboard">
{COLUMNS.map((col) => {
const items = tasks.filter((t) => t.status === col.id);
return (
<div
key={col.id}
className={cx("kcol", overCol === col.id && "over")}
onDragOver={(e) => {
e.preventDefault();
if (overCol !== col.id) setOverCol(col.id);
}}
onDragLeave={(e) => {
if (e.currentTarget === e.target) setOverCol(null);
}}
onDrop={(e) => {
e.preventDefault();
if (dragId) onMove(dragId, col.id as Status);
setDragId(null);
setOverCol(null);
}}
>
<div className="kcol-head">
<span className="kcol-dot" style={{ background: col.accent }} />
<span className="kcol-label">{col.label}</span>
<span className="kcol-count">{items.length}</span>
<button
className="kcol-add"
onClick={() => {
setAddCol(col.id);
setText("");
}}
aria-label="작업 추가"
>
<Icon name="plus" />
</button>
</div>
<div className="kcol-body">
{addCol === col.id && (
<div className="quickadd">
<input
autoFocus
value={text}
placeholder="작업 입력 후 Enter…"
onChange={(e) => 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)}
/>
</div>
)}
{items.map((t) => (
<KanbanCard
key={t.id}
task={t}
people={people}
projects={projects}
onOpen={onOpen}
dragging={dragId === t.id}
onDragStart={(e) => {
setDragId(t.id);
e.dataTransfer.effectAllowed = "move";
}}
onDragEnd={() => {
setDragId(null);
setOverCol(null);
}}
/>
))}
{items.length === 0 && addCol !== col.id && (
<div className="kcol-empty"> </div>
)}
</div>
</div>
);
})}
</div>
);
}