"use client" import * as React from "react" import { type DataTableRowAction } from "@/types/table" import { type ColumnDef } from "@tanstack/react-table" import { Download, Ellipsis, Paperclip } 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 { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header" import { basicContractTemplateColumnsConfig } from "@/config/basicContractColumnsConfig" import { BasicContractTemplate } from "@/db/schema" interface GetColumnsProps { setRowAction: React.Dispatch | null>> } /** * 파일 다운로드 함수 */ const handleFileDownload = (filePath: string, fileName: string) => { try { // 전체 URL 생성 const fullUrl = `${window.location.origin}${filePath}`; // a 태그를 생성하여 다운로드 실행 const link = document.createElement('a'); link.href = fullUrl; link.download = fileName; // 다운로드될 파일명 설정 document.body.appendChild(link); link.click(); document.body.removeChild(link); toast.success("파일 다운로드를 시작합니다."); } catch (error) { console.error("파일 다운로드 오류:", error); toast.error("파일 다운로드 중 오류가 발생했습니다."); } }; /** * tanstack table 컬럼 정의 (중첩 헤더 버전) */ export function getColumns({ setRowAction }: 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" /> ), maxSize: 30, enableSorting: false, enableHiding: false, } // ---------------------------------------------------------------- // 2) 파일 다운로드 컬럼 (아이콘) // ---------------------------------------------------------------- const downloadColumn: ColumnDef = { id: "download", header: "", cell: ({ row }) => { const template = row.original; return ( ); }, maxSize: 30, enableSorting: false, } // ---------------------------------------------------------------- // 3) actions 컬럼 (Dropdown 메뉴) // ---------------------------------------------------------------- const actionsColumn: ColumnDef = { id: "actions", enableHiding: false, cell: function Cell({ row }) { const [isUpdatePending, startUpdateTransition] = React.useTransition() return ( setRowAction({ row, type: "update" })} > Edit setRowAction({ row, type: "delete" })} > Delete ⌘⌫ ) }, maxSize: 30, } // ---------------------------------------------------------------- // 4) 일반 컬럼들을 "그룹"별로 묶어 중첩 columns 생성 // ---------------------------------------------------------------- // 4-1) groupMap: { [groupName]: ColumnDef[] } const groupMap: Record[]> = {} basicContractTemplateColumnsConfig.forEach((cfg) => { // 만약 group가 없으면 "_noGroup" 처리 const groupName = cfg.group || "_noGroup" if (!groupMap[groupName]) { groupMap[groupName] = [] } // child column 정의 const childCol: ColumnDef = { accessorKey: cfg.id, enableResizing: true, header: ({ column }) => ( ), meta: { excelHeader: cfg.excelHeader, group: cfg.group, type: cfg.type, }, cell: ({ row, cell }) => { // 날짜 형식 처리 if (cfg.id === "createdAt" || cfg.id === "updatedAt") { const dateVal = cell.getValue() as Date return formatDateTime(dateVal, "KR") } // Status 컬럼에 Badge 적용 if (cfg.id === "status") { const status = row.getValue(cfg.id) as string const isActive = status === "ACTIVE" return ( {isActive ? "활성" : "비활성"} ) } // 나머지 컬럼은 그대로 값 표시 return row.getValue(cfg.id) ?? "" }, minSize:80 } groupMap[groupName].push(childCol) }) // ---------------------------------------------------------------- // 4-2) groupMap에서 실제 상위 컬럼(그룹)을 만들기 // ---------------------------------------------------------------- const nestedColumns: ColumnDef[] = [] // 순서를 고정하고 싶다면 group 순서를 미리 정의하거나 sort해야 함 // 여기서는 그냥 Object.entries 순서 Object.entries(groupMap).forEach(([groupName, colDefs]) => { if (groupName === "_noGroup") { // 그룹 없음 → 그냥 최상위 레벨 컬럼 nestedColumns.push(...colDefs) } else { // 상위 컬럼 nestedColumns.push({ id: groupName, header: groupName, // "Basic Info", "Metadata" 등 columns: colDefs, }) } }) // ---------------------------------------------------------------- // 5) 최종 컬럼 배열: select, download, nestedColumns, actions // ---------------------------------------------------------------- return [ selectColumn, downloadColumn, // 다운로드 컬럼 추가 ...nestedColumns, actionsColumn, ] }