"use client" import * as React from "react" import { type DataTableRowAction } from "@/types/table" import { type ColumnDef } from "@tanstack/react-table" import { InfoIcon, FileTextIcon, SendIcon, FileSignatureIcon, MoreHorizontalIcon, ExternalLinkIcon } from "lucide-react" import { formatDate } from "@/lib/utils" import { Button } from "@/components/ui/button" import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { Badge } from "@/components/ui/badge" import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header" import { poColumnsConfig } from "@/config/poColumnsConfig" import { ContractDetailParsed } from "@/db/schema/contract" interface GetColumnsProps { setRowAction: React.Dispatch | null>> } /** * tanstack table column definitions with nested headers */ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef[] { // ---------------------------------------------------------------- // 1) select column (checkbox) - if needed // ---------------------------------------------------------------- // ---------------------------------------------------------------- // 2) actions column (buttons for item info and signature request) // ---------------------------------------------------------------- const actionsColumn: ColumnDef = { id: "actions", enableHiding: false, header: () =>
Actions
, cell: function Cell({ row }) { // Check if this contract already has a signature envelope const hasSignature = row.original.hasSignature; const contract = row.original; return (
{/* Items Button - Visually distinct with badge showing count */} View contract items and details {/* Signature related actions */} {hasSignature ? ( View signature status and details ) : ( Send electronic signature requests )} {/* Alternative: Dropdown menu for more actions */} {/* Actions setRowAction({ row, type: "items" })}> View Items {hasSignature ? ( setRowAction({ row, type: "esign-detail" })}> View Signatures ) : ( setRowAction({ row, type: "signature" })}> Request Signatures )} */}
); }, size: 340, // Adjusted for multiple buttons minSize:280 }; // ---------------------------------------------------------------- // 3) Regular columns grouped by group name // ---------------------------------------------------------------- // 3-1) groupMap: { [groupName]: ColumnDef[] } const groupMap: Record[]> = {}; // (1) JSON config를 읽어서 ColumnDef를 생성하는 부분 (일부 발췌) poColumnsConfig.forEach((cfg) => { const groupName = cfg.group || "_noGroup" if (!groupMap[groupName]) { groupMap[groupName] = [] } let childCol: ColumnDef if (cfg.type === "custom") { // ======================================== // (2) 전자서명 전용 커스텀 컬럼 // ======================================== childCol = { id: cfg.id, header: ({ column }) => ( ), // 여기서 row.original.envelopes 등 활용하여 최신 전자서명 상태 표시 cell: ({ row }) => { const data = row.original if (!data.envelopes || data.envelopes.length === 0) { return (
No E-Sign
) } // envelopes가 여러 개 있으면 최신(가장 최근 updatedAt) 가져오기 const sorted = [...data.envelopes].sort((a, b) => { const dateA = new Date(a.updatedAt) const dateB = new Date(b.updatedAt) return dateB.getTime() - dateA.getTime() }) const latest = sorted[0] const status = latest.envelopeStatus; if (!status) { // status가 null이면, 기본 색상이나 별도 표시 return No Status } const colorMap: Record = { completed: "text-green-600", sent: "text-blue-600", voided: "text-red-600", }; const colorClass = colorMap[status] ?? "text-gray-700"; return (
setRowAction({ row, type: "esign-detail" })} className={`${colorClass} cursor-pointer flex items-center`} > {status}
) }, meta: { excelHeader: cfg.excelHeader, group: cfg.group, type: cfg.type, }, } } else { // ======================================== // (3) 일반 컬럼 (type: text/date/number 등) // ======================================== childCol = { accessorKey: cfg.id, enableResizing: true, header: ({ column }) => ( ), meta: { excelHeader: cfg.excelHeader, group: cfg.group, type: cfg.type, }, cell: ({ row, cell }) => { // 날짜 포맷, 숫자 포맷 등 처리 if (cfg.type === "date") { const dateVal = cell.getValue() as Date return formatDate(dateVal) } // ... return row.getValue(cfg.id) ?? "" }, } } groupMap[groupName].push(childCol) }) // ---------------------------------------------------------------- // 3-2) Create actual parent columns (groups) from the groupMap // ---------------------------------------------------------------- const nestedColumns: ColumnDef[] = []; // Order can be fixed by pre-defining group order or sorting // Here we just use Object.entries order Object.entries(groupMap).forEach(([groupName, colDefs]) => { if (groupName === "_noGroup") { // No group → Add as top-level columns nestedColumns.push(...colDefs); } else { // Parent column nestedColumns.push({ id: groupName, header: groupName, // "Basic Info", "Metadata", etc. columns: colDefs, }); } }); // ---------------------------------------------------------------- // 4) Final column array: nestedColumns + actionsColumn // ---------------------------------------------------------------- return [ ...nestedColumns, actionsColumn, ]; }