ERP-node/frontend/lib/registry/components/v2-process-work-standard/components/WorkPhaseSection.tsx

124 lines
3.8 KiB
TypeScript

"use client";
import React from "react";
import { Plus, ClipboardList } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { WorkItemCard } from "./WorkItemCard";
import { WorkItemDetailList } from "./WorkItemDetailList";
import {
WorkItem,
WorkItemDetail,
WorkPhaseDefinition,
DetailTypeDefinition,
} from "../types";
interface WorkPhaseSectionProps {
phase: WorkPhaseDefinition;
items: WorkItem[];
selectedWorkItemId: string | null;
selectedWorkItemDetails: WorkItemDetail[];
detailTypes: DetailTypeDefinition[];
readonly?: boolean;
onSelectWorkItem: (workItemId: string) => void;
onAddWorkItem: (phase: string) => void;
onEditWorkItem: (item: WorkItem) => void;
onDeleteWorkItem: (id: string) => void;
onCreateDetail: (workItemId: string, data: Partial<WorkItemDetail>) => void;
onUpdateDetail: (id: string, data: Partial<WorkItemDetail>) => void;
onDeleteDetail: (id: string) => void;
}
export function WorkPhaseSection({
phase,
items,
selectedWorkItemId,
selectedWorkItemDetails,
detailTypes,
readonly,
onSelectWorkItem,
onAddWorkItem,
onEditWorkItem,
onDeleteWorkItem,
onCreateDetail,
onUpdateDetail,
onDeleteDetail,
}: WorkPhaseSectionProps) {
const selectedItem = items.find((i) => i.id === selectedWorkItemId) || null;
const isThisSectionSelected = items.some(
(i) => i.id === selectedWorkItemId
);
return (
<div className="rounded-lg border bg-card">
{/* 섹션 헤더 */}
<div className="flex items-center justify-between border-b px-4 py-2.5">
<div className="flex items-center gap-2">
<h3 className="text-sm font-semibold">{phase.label}</h3>
<Badge
variant="secondary"
className="h-5 rounded-full px-2 text-[10px]"
>
{items.length}
</Badge>
</div>
{!readonly && (
<Button
variant="outline"
size="sm"
className="h-7 gap-1 text-xs"
onClick={() => onAddWorkItem(phase.key)}
>
<Plus className="h-3 w-3" />
</Button>
)}
</div>
{/* 콘텐츠 영역 */}
<div className="flex min-h-[140px]">
{/* 좌측: 작업 항목 카드 목록 */}
<div className="w-[240px] shrink-0 border-r p-2">
{items.length === 0 ? (
<div className="flex flex-col items-center justify-center py-6 text-center">
<ClipboardList className="mb-1 h-6 w-6 text-muted-foreground/40" />
<p className="text-[11px] text-muted-foreground">
</p>
</div>
) : (
<div className="space-y-1.5">
{items.map((item) => (
<WorkItemCard
key={item.id}
item={item}
isSelected={selectedWorkItemId === item.id}
readonly={readonly}
onClick={() => onSelectWorkItem(item.id)}
onEdit={() => onEditWorkItem(item)}
onDelete={() => onDeleteWorkItem(item.id)}
/>
))}
</div>
)}
</div>
{/* 우측: 상세 리스트 */}
<div className="flex-1">
<WorkItemDetailList
workItem={isThisSectionSelected ? selectedItem : null}
details={isThisSectionSelected ? selectedWorkItemDetails : []}
detailTypes={detailTypes}
readonly={readonly}
onCreateDetail={(data) =>
selectedWorkItemId && onCreateDetail(selectedWorkItemId, data)
}
onUpdateDetail={onUpdateDetail}
onDeleteDetail={onDeleteDetail}
/>
</div>
</div>
</div>
);
}