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.

106 lines
2.9 KiB
TypeScript

// frontend/components/tasks/SubRow.tsx — 재귀 하위작업 행 (드릴다운)
"use client";
import { Icon } from "@/components/Icon";
import { cx } from "@/lib/cx";
import { dueLabel, stat } from "@/lib/tasks/tree";
import type { Person, Task } from "@/lib/types";
import { Av } from "./bits";
interface Props {
node: Task;
depth: number;
people: Record<string, Person>;
expanded: Record<string, boolean>;
onExpand: (id: string) => void;
onCheck: (id: string) => void;
onFocus: (id: string) => void;
}
export function SubRow({ node, depth, people, expanded, onExpand, onCheck, onFocus }: Props) {
const has = !!(node.children && node.children.length);
const open = !!expanded[node.id];
const s = stat(node);
const done = node.status === "done";
return (
<>
<div
className={cx("subrow", done && "done")}
style={{ paddingLeft: 6 + depth * 22 }}
onClick={() => onFocus(node.id)}
>
{has ? (
<button
className={cx("sub-twist", open && "open")}
onClick={(e) => {
e.stopPropagation();
onExpand(node.id);
}}
aria-label="펼치기"
>
<Icon name="chev" />
</button>
) : (
<span className="sub-twist-sp" />
)}
<div
className={cx("sub-check", done && "done")}
onClick={(e) => {
e.stopPropagation();
onCheck(node.id);
}}
role="checkbox"
aria-checked={done}
aria-label="완료 토글"
>
<Icon name="tick" w={3} />
</div>
<span className="sub-title">{node.title}</span>
<div className="sub-meta">
{has && (
<span className="sub-chip">
<Icon name="branch" /> {s.done}/{s.total}
</span>
)}
{node.est && (
<span className="sub-chip est">
<Icon name="clock" /> {node.est}
</span>
)}
{node.due && (
<span className="sub-chip">
<Icon name="cal" /> {dueLabel(node.due)}
</span>
)}
<Av person={node.assignee_id ? people[node.assignee_id] : null} />
<button
className="sub-drill"
onClick={(e) => {
e.stopPropagation();
onFocus(node.id);
}}
aria-label="작업 열기"
>
<Icon name="chev" />
</button>
</div>
</div>
{has && open && (
<div className="subkids">
{node.children.map((c) => (
<SubRow
key={c.id}
node={c}
depth={depth + 1}
people={people}
expanded={expanded}
onExpand={onExpand}
onCheck={onCheck}
onFocus={onFocus}
/>
))}
</div>
)}
</>
);
}