"use client"; import * as React from "react"; import { ColumnDef, flexRender, getCoreRowModel, getSortedRowModel, getFilteredRowModel, getPaginationRowModel, SortingState, ColumnFiltersState, useReactTable, } from "@tanstack/react-table"; import { ChevronDown, ChevronUp, Search, Download, Filter } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { cn } from "@/lib/utils"; interface DataTableProps { columns: ColumnDef[]; data: TData[]; searchable?: boolean; searchPlaceholder?: string; showExport?: boolean; showFilter?: boolean; onExport?: () => void; onRowClick?: (row: TData) => void; className?: string; } export function DataTable({ columns, data, searchable = true, searchPlaceholder = "검색...", showExport = false, showFilter = false, onExport, onRowClick, className, }: DataTableProps) { const [sorting, setSorting] = React.useState([]); const [columnFilters, setColumnFilters] = React.useState([]); const [globalFilter, setGlobalFilter] = React.useState(""); const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel(), getPaginationRowModel: getPaginationRowModel(), getSortedRowModel: getSortedRowModel(), getFilteredRowModel: getFilteredRowModel(), onSortingChange: setSorting, onColumnFiltersChange: setColumnFilters, onGlobalFilterChange: setGlobalFilter, state: { sorting, columnFilters, globalFilter, }, }); return (
{/* 테이블 상단 툴바 */}
{searchable && (
setGlobalFilter(event.target.value)} className="w-64 pl-8" />
)} {showFilter && ( )}
{showExport && ( )}
{/* 테이블 */}
{table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => { return ( {header.isPlaceholder ? null : (
{flexRender(header.column.columnDef.header, header.getContext())} {header.column.getCanSort() && (
{header.column.getIsSorted() === "desc" ? ( ) : header.column.getIsSorted() === "asc" ? ( ) : (
)}
)}
)}
); })}
))}
{table.getRowModel().rows?.length ? ( table.getRowModel().rows.map((row) => ( onRowClick?.(row.original)} > {row.getVisibleCells().map((cell) => ( {flexRender(cell.column.columnDef.cell, cell.getContext())} ))} )) ) : ( 데이터가 없습니다. )}
{/* 페이지네이션 */}
{table.getFilteredSelectedRowModel().rows.length}개 중 {table.getFilteredRowModel().rows.length}개 표시

페이지당 행 수

페이지 {table.getState().pagination.pageIndex + 1} / {table.getPageCount()}
); } // 컬럼 정의 헬퍼 함수들 export const createTextColumn = (accessorKey: string, header: string) => ({ accessorKey, header, cell: ({ row }: any) =>
{row.getValue(accessorKey)}
, }); export const createDateColumn = (accessorKey: string, header: string) => ({ accessorKey, header, cell: ({ row }: any) => { const date = row.getValue(accessorKey); return
{date ? new Date(date).toLocaleDateString("ko-KR") : "-"}
; }, }); export const createStatusColumn = (accessorKey: string, header: string) => ({ accessorKey, header, cell: ({ row }: any) => { const status = row.getValue(accessorKey); return (
{status || "-"}
); }, }); export const createActionColumn = (actions: React.ReactNode) => ({ id: "actions", header: "작업", cell: () => actions, });