"use client" import * as React from "react" import { type DataTableRowAction } from "@/types/table" import { type ColumnDef } from "@tanstack/react-table" import { Download, Ellipsis, Paperclip, CheckCircle, XCircle, Eye, Copy, GitBranch } from "lucide-react" import { toast } from "sonner" import { getErrorMessage } from "@/lib/handle-error" import { formatDate, formatDateTime } from "@/lib/utils" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Checkbox } from "@/components/ui/checkbox" import { users } from "@/db/schema" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip" import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header" import { GeneralContractTemplate } from "@/db/schema" import { quickDownload } from "@/lib/file-download" import { useRouter } from "next/navigation" interface GetColumnsProps { setRowAction: React.Dispatch | null>> router: ReturnType } /** * 파일 다운로드 함수 (공용 유틸리티 사용) */ const handleFileDownload = async (filePath: string, fileName: string) => { try { await quickDownload(filePath, fileName); } catch (error) { console.error("파일 다운로드 오류:", error); toast.error("파일 다운로드 중 오류가 발생했습니다."); } }; /** * tanstack table 컬럼 정의 (중첩 헤더 버전) */ export function getColumns({ setRowAction, router }: GetColumnsProps): ColumnDef[] { // ---------------------------------------------------------------- // 1) select 컬럼 (체크박스) // ---------------------------------------------------------------- const selectColumn: ColumnDef = { id: "select", header: ({ table }) => ( table.toggleAllPageRowsSelected(!!value)} aria-label="Select all" className="translate-y-0.5" /> ), cell: ({ row }) => ( row.toggleSelected(!!value)} aria-label="Select row" className="translate-y-0.5" /> ), size: 30, minSize: 30, maxSize: 30, enableSorting: false, enableHiding: false, } // ---------------------------------------------------------------- // 2) 파일 다운로드 컬럼 (아이콘) // ---------------------------------------------------------------- const downloadColumn: ColumnDef = { id: "download", header: "", cell: ({ row }) => { const template = row.original; return ( ); }, size: 30, minSize: 30, maxSize: 30, enableSorting: false, } // ---------------------------------------------------------------- // 3) actions 컬럼 (Dropdown 메뉴) // ---------------------------------------------------------------- const actionsColumn: ColumnDef = { id: "actions", header: "", enableHiding: false, cell: function Cell({ row }) { const [isUpdatePending, startUpdateTransition] = React.useTransition() const template = row.original; const handleViewDetails = () => { router.push(`/evcp/general-contract-template/${template.id}`); }; return ( router.push(`/evcp/general-contract-template/${template.id}`)} > {/* */} 상세보기 setRowAction({ row, type: "create-revision" })} > {/* */} 리비전 생성하기 setRowAction({ row, type: "update" })} > 수정하기 {template.status === 'ACTIVE' && ( setRowAction({ row, type: "dispose" })} > 폐기하기 )} {template.status === 'DISPOSED' && template.disposedAt && ( setRowAction({ row, type: "restore" })} > 복구하기 )} setRowAction({ row, type: "delete" })} > 삭제하기 {/* ⌘⌫ */} ) }, size: 30, minSize: 30, maxSize: 30, } // ---------------------------------------------------------------- // 4) 컬럼 정의 // ---------------------------------------------------------------- const basicInfoColumns: ColumnDef[] = [ { accessorKey: "id", header: ({ column }) => , cell: ({ row }) => { // Sequential number based on table order return (
{row.index + 1}
); }, size: 60, minSize: 50, maxSize: 80, enableSorting: false, }, { accessorKey: "status", header: ({ column }) => , cell: ({ row }) => { const status = row.getValue("status") as string; const getStatusDisplay = (status: string) => { switch (status) { case "ACTIVE": return "A"; case "DISPOSED": return "D"; case "INACTIVE": return ""; // 빈 문자열로 "Null" 표현 default: return ""; } }; return (
{getStatusDisplay(status)}
); }, size: 80, minSize: 60, maxSize: 120, enableResizing: true, filterFn: (row, id, value) => { return value.includes(row.getValue(id)); }, }, { accessorKey: "contractTemplateType", header: ({ column }) => , cell: ({ row }) => { const contractType = row.getValue("contractTemplateType") as string; return (
{contractType}
); }, size: 100, minSize: 80, maxSize: 150, enableResizing: true, filterFn: (row, id, value) => { return value.includes(row.getValue(id)); }, }, { accessorKey: "contractTemplateName", header: ({ column }) => , cell: ({ row }) => { const template = row.original; const handleClick = () => { router.push(`/evcp/general-contract-template/${template.id}`); }; return (
); }, size: 250, minSize: 200, maxSize: 400, enableResizing: true, }, { accessorKey: "revision", header: ({ column }) => , cell: ({ row }) => { const revision = row.getValue("revision") as number; return (
{revision}
); }, size: 80, minSize: 60, maxSize: 120, enableResizing: true, }, ]; // const scopeColumns: ColumnDef[] = [ // { // accessorKey: "shipBuildingApplicable", // header: ({ column }) => , // cell: ({ row }) => { // const applicable = row.getValue("shipBuildingApplicable") as boolean; // return ( //
// {applicable ? ( // // ) : ( // // )} //
// ); // }, // size: 80, // enableResizing: true, // }, // { // accessorKey: "windApplicable", // header: ({ column }) => , // cell: ({ row }) => { // const applicable = row.getValue("windApplicable") as boolean; // return ( //
// {applicable ? ( // // ) : ( // // )} //
// ); // }, // size: 60, // enableResizing: true, // }, // { // accessorKey: "pcApplicable", // header: ({ column }) => , // cell: ({ row }) => { // const applicable = row.getValue("pcApplicable") as boolean; // return ( //
// {applicable ? ( // // ) : ( // // )} //
// ); // }, // size: 50, // enableResizing: true, // }, // { // accessorKey: "nbApplicable", // header: ({ column }) => , // cell: ({ row }) => { // const applicable = row.getValue("nbApplicable") as boolean; // return ( //
// {applicable ? ( // // ) : ( // // )} //
// ); // }, // size: 50, // enableResizing: true, // }, // { // accessorKey: "rcApplicable", // header: ({ column }) => , // cell: ({ row }) => { // const applicable = row.getValue("rcApplicable") as boolean; // return ( //
// {applicable ? ( // // ) : ( // // )} //
// ); // }, // size: 50, // enableResizing: true, // }, // { // accessorKey: "gyApplicable", // header: ({ column }) => , // cell: ({ row }) => { // const applicable = row.getValue("gyApplicable") as boolean; // return ( //
// {applicable ? ( // // ) : ( // // )} //
// ); // }, // size: 50, // enableResizing: true, // }, // { // accessorKey: "sysApplicable", // header: ({ column }) => , // cell: ({ row }) => { // const applicable = row.getValue("sysApplicable") as boolean; // return ( //
// {applicable ? ( // // ) : ( // // )} //
// ); // }, // size: 60, // enableResizing: true, // }, // { // accessorKey: "infraApplicable", // header: ({ column }) => , // cell: ({ row }) => { // const applicable = row.getValue("infraApplicable") as boolean; // return ( //
// {applicable ? ( // // ) : ( // // )} //
// ); // }, // size: 60, // enableResizing: true, // }, // ]; const fileInfoColumns: ColumnDef[] = [ { accessorKey: "fileName", header: ({ column }) => , cell: ({ row }) => { const fileName = row.getValue("fileName") as string; return (
{fileName}
); }, size: 200, minSize: 150, maxSize: 300, enableResizing: true, }, ]; const auditColumns: ColumnDef[] = [ { accessorKey: "createdAt", header: ({ column }) => , cell: ({ row }) => { const date = row.getValue("createdAt") as Date; return date ? formatDateTime(date, "ko-KR") : "-"; }, size: 120, minSize: 100, maxSize: 180, enableResizing: true, }, { accessorKey: "updatedAt", header: ({ column }) => , cell: ({ row }) => { const date = row.getValue("updatedAt") as Date; return date ? formatDateTime(date, "ko-KR") : "-"; }, size: 120, minSize: 100, maxSize: 180, enableResizing: true, }, { accessorKey: "disposedAt", header: ({ column }) => , cell: ({ row }) => { const date = row.getValue("disposedAt") as Date; return date ? formatDateTime(date, "ko-KR") : "-"; }, size: 120, minSize: 100, maxSize: 180, enableResizing: true, }, { accessorKey: "restoredAt", header: ({ column }) => , cell: ({ row }) => { const date = row.getValue("restoredAt") as Date; return date ? formatDateTime(date, "ko-KR") : "-"; }, size: 120, minSize: 100, maxSize: 180, enableResizing: true, }, ]; // ---------------------------------------------------------------- // 5) 최종 컬럼 배열: 사용자 요구사항 순서에 맞게 재배치 // ---------------------------------------------------------------- return [ selectColumn, // ㅁ* (체크박스) { // No. accessorKey: "id", header: ({ column }) => , cell: ({ row }) => { return (
{row.index + 1}
); }, size: 40, minSize: 40, maxSize: 70, enableSorting: false, }, { // 상태 accessorKey: "status", header: ({ column }) => , cell: ({ row }) => { const status = row.getValue("status") as string; let displayStatus = ""; if (status === "ACTIVE") displayStatus = "A"; else if (status === "DISPOSED") displayStatus = "D"; // INACTIVE는 빈 문자열로 "Null" 표현 return (
{displayStatus}
); }, size: 50, minSize: 40, maxSize: 70, enableResizing: true, }, { // 계약종류 accessorKey: "contractTemplateType", header: ({ column }) => , cell: ({ row }) => { const contractType = row.getValue("contractTemplateType") as string; return (
{contractType}
); }, size: 80, minSize: 60, maxSize: 120, enableResizing: true, }, { // 계약문서명 accessorKey: "contractTemplateName", header: ({ column }) => , cell: ({ row }) => { const contractName = row.getValue("contractTemplateName") as string; return (
{contractName}
); }, size: 200, minSize: 150, maxSize: 1000, enableResizing: true, }, { // Rev. accessorKey: "revision", header: ({ column }) => , cell: ({ row }) => { const revision = row.getValue("revision") as number; return (
{revision}
); }, size: 60, minSize: 50, maxSize: 80, enableResizing: true, }, { // 법무검토 accessorKey: "legalReviewRequired", header: ({ column }) => , cell: ({ row }) => { const required = row.getValue("legalReviewRequired") as boolean; return ( {required ? "필요" : "불필요"} ); }, size: 100, minSize: 80, maxSize: 150, enableResizing: true, }, { // 최종 Update일 accessorKey: "updatedAt", header: ({ column }) => , cell: ({ row }) => { const date = row.getValue("updatedAt") as Date; return date ? formatDate(date) : ""; }, size: 120, minSize: 100, maxSize: 180, enableResizing: true, }, { // 최종 Update자 accessorKey: "updatedByName", header: ({ column }) => , cell: ({ row }) => { const updatedByName = row.getValue("updatedByName") as string | null; return updatedByName || ""; }, size: 120, minSize: 100, maxSize: 180, enableResizing: true, }, { // 폐기일자 accessorKey: "disposedAt", header: ({ column }) => , cell: ({ row }) => { const date = row.getValue("disposedAt") as Date | null; return date ? formatDate(date) : ""; }, size: 120, minSize: 100, maxSize: 180, enableResizing: true, }, { // 첨부 accessorKey: "fileName", header: ({ column }) => , cell: ({ row }) => { const template = row.original; return ( ); }, maxSize: 50, enableSorting: false, }, actionsColumn, // 빈 컬럼 (···) ] }