"use client"; import React, { useState, useMemo } from "react"; import { useReactTable, getCoreRowModel, flexRender, } from "@tanstack/react-table"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Badge } from "@/components/ui/badge"; import { ColumnDef } from "@tanstack/react-table"; import { SwpInboxDocumentDetailDialog } from "./swp-inbox-document-detail-dialog"; import type { SwpFileApiResponse } from "@/lib/swp/api-client"; interface SwpInboxTableProps { files: SwpFileApiResponse[]; projNo: string; vendorCode: string; userId: string; } // 문서별로 그룹핑된 데이터 타입 export interface InboxDocumentItem { ownDocNo: string; latestRevFileCount: number; // 최신 REV의 파일 개수 latestStage: string; latestRevNo: string; latestStatus: string | null; latestStatusNm: string | null; files: SwpFileApiResponse[]; } // 테이블 컬럼 정의 const inboxDocumentColumns: ColumnDef[] = [ { accessorKey: "latestStatusNm", header: "상태", cell: ({ row }) => { const statNm = row.original.latestStatusNm; const stat = row.original.latestStatus; const displayStatus = statNm || stat || "-"; if (!stat) return displayStatus; // STAT 코드 기반 색상 결정 const color = stat === "SCW03" || stat === "SCW08" ? "bg-green-100 text-green-800" : // Complete, Checked stat === "SCW02" ? "bg-blue-100 text-blue-800" : // Processing stat === "SCW01" ? "bg-yellow-100 text-yellow-800" : // Standby stat === "SCW04" || stat === "SCW05" || stat === "SCW06" ? "bg-red-100 text-red-800" : // Reject, Error Zip, Error Meta stat === "SCW07" ? "bg-purple-100 text-purple-800" : // Send for Eng Verification stat === "SCW09" ? "bg-gray-100 text-gray-800" : // Cancelled stat === "SCW00" ? "bg-orange-100 text-orange-800" : // Upload "bg-gray-100 text-gray-800"; // 기타 return ( {displayStatus} ); }, size: 120, }, { accessorKey: "ownDocNo", header: "OWN_DOC_NO", cell: ({ row }) => (
{row.original.ownDocNo}
), size: 300, }, { accessorKey: "latestStage", header: "최신 스테이지", cell: ({ row }) => { const stage = row.original.latestStage; if (!stage) return "-"; const color = stage === "IFC" ? "bg-green-100 text-green-800" : stage === "IFA" ? "bg-blue-100 text-blue-800" : "bg-gray-100 text-gray-800"; return ( {stage} ); }, size: 120, }, { accessorKey: "latestRevNo", header: "최신 REV", cell: ({ row }) => row.original.latestRevNo || "-", size: 100, }, { accessorKey: "latestRevFileCount", header: "최신 REV 파일 수", cell: ({ row }) => (
{row.original.latestRevFileCount}개
), size: 100, }, ]; export function SwpInboxTable({ files, projNo, vendorCode, userId, }: SwpInboxTableProps) { const [dialogOpen, setDialogOpen] = useState(false); const [selectedDocument, setSelectedDocument] = useState(null); // 파일들을 문서별로 그룹핑 const documents = useMemo(() => { const docMap = new Map(); files.forEach((file) => { const docNo = file.OWN_DOC_NO; if (!docMap.has(docNo)) { docMap.set(docNo, []); } docMap.get(docNo)!.push(file); }); const result: InboxDocumentItem[] = []; docMap.forEach((docFiles, ownDocNo) => { // 최신 REV 찾기 (REV_NO 기준으로 정렬) const sortedByRev = [...docFiles].sort((a, b) => (b.REV_NO || "").localeCompare(a.REV_NO || "") ); const latestRevNo = sortedByRev[0].REV_NO || ""; // 최신 REV의 파일들만 필터링 const latestRevFiles = docFiles.filter(file => file.REV_NO === latestRevNo); // 최신 REV 내에서 가장 최근 생성된 파일 찾기 (상태 표시용) const sortedLatestRevFiles = [...latestRevFiles].sort((a, b) => (b.CRTE_DTM || "").localeCompare(a.CRTE_DTM || "") ); const latestFile = sortedLatestRevFiles[0]; result.push({ ownDocNo, latestRevFileCount: latestRevFiles.length, // 최신 REV의 파일 개수 latestStage: latestFile.STAGE || "", latestRevNo: latestRevNo, latestStatus: latestFile.STAT, latestStatusNm: latestFile.STAT_NM, files: docFiles, // 전체 파일 목록 (상세보기용) }); }); return result.sort((a, b) => a.ownDocNo.localeCompare(b.ownDocNo)); }, [files]); const table = useReactTable({ data: documents, columns: inboxDocumentColumns, getCoreRowModel: getCoreRowModel(), }); // 문서 클릭 핸들러 const handleDocumentClick = (document: InboxDocumentItem) => { setSelectedDocument(document); setDialogOpen(true); }; return (
{/* 테이블 */}
{table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( {header.isPlaceholder ? null : flexRender( header.column.columnDef.header, header.getContext() )} ))} ))} {table.getRowModel().rows?.length ? ( table.getRowModel().rows.map((row) => ( handleDocumentClick(row.original)} > {row.getVisibleCells().map((cell) => ( {flexRender(cell.column.columnDef.cell, cell.getContext())} ))} )) ) : ( 업로드한 파일이 없습니다. )}
{/* 문서 상세 Dialog */}
); }