"use client"; import { type ReactNode, useMemo } from "react"; import { type ColumnDef, getCoreRowModel, type PaginationState, useReactTable, } from "@tanstack/react-table"; import { getStandardRowNumber, type ScrollMode, StandardDataTable, type UiHeadProps, } from "@common/business_components"; import type { UiTableSort } from "@common/business_components/ui/table"; type MapPopupDataTableProps> = { rows: T[]; headlist: UiHeadProps[]; title: ReactNode; total: number; page: number; pageSize: number; onPageChange: (page: number) => void; actions?: ReactNode; loading?: boolean; scrollMode?: ScrollMode; minTableWidth?: string; emptyMessage?: string; viewPagination?: boolean; fillAvailableHeight?: boolean; rowId?: (row: T, index: number) => string; selectedRowId?: string; onRowClick?: (row: T, index: number) => void; onCellClick?: (row: T, rowIndex: number, columnId: string) => void; clickableHeadIds?: string[]; renderCell?: ( row: T, headId: string, rowIndex: number, ) => ReactNode | undefined; sort?: UiTableSort; onSortChange?: (sort: UiTableSort | undefined) => void; }; const ROW_NUMBER_IDS = new Set(["no", "rowNo", "rowNumber"]); const formatCellValue = (value: unknown) => { if (value === null || value === undefined || value === "") return "-"; if (typeof value === "number") return value.toLocaleString("ko-KR"); return String(value); }; /** 지도 WindowPopup 목록을 CS 공통 표·순번·페이징 규칙으로 연결한다. */ export default function MapPopupDataTable>({ rows, headlist, title, total, page, pageSize, onPageChange, actions, loading = false, scrollMode = "none", minTableWidth = "100%", emptyMessage, viewPagination = true, fillAvailableHeight = false, rowId, selectedRowId, onRowClick, onCellClick, clickableHeadIds, renderCell, sort, onSortChange, }: MapPopupDataTableProps) { const visibleHeads = useMemo( () => headlist.filter( (head) => head.visible !== false && head.id && head.id.length > 1, ), [headlist], ); const columns = useMemo[]>( () => visibleHeads.map((head) => ({ id: head.id, accessorFn: (row) => row[head.id], header: () => { const title = ROW_NUMBER_IDS.has(head.id) ? "순번" : head.title; if (!head.sortable || !onSortChange) return title; const key = head.sortKey ?? head.id; const direction = sort?.key === key ? sort.direction : undefined; return ( ); }, cell: ({ row, getValue }) => { const rowIndex = row.index; const rendered = renderCell?.(row.original, head.id, rowIndex); const value = ROW_NUMBER_IDS.has(head.id) ? getStandardRowNumber({ total, rowIndex, pageIndex: page - 1, pageSize, }) : rendered === undefined ? formatCellValue(getValue()) : rendered; const isClickable = Boolean(onCellClick) && (!clickableHeadIds || clickableHeadIds.includes(head.id)); return isClickable ? ( ) : ( value ); }, meta: { align: head.align === "left" || head.align === "right" ? head.align : "center", width: head.widthPercent, }, })), [ clickableHeadIds, onCellClick, page, pageSize, renderCell, sort, total, visibleHeads, onSortChange, ], ); const pagination: PaginationState = { pageIndex: Math.max(page - 1, 0), pageSize, }; const table = useReactTable({ data: rows, columns, state: { pagination, rowSelection: selectedRowId ? { [selectedRowId]: true } : {}, }, rowCount: total, manualPagination: true, getCoreRowModel: getCoreRowModel(), getRowId: (row, index) => rowId?.(row, index) ?? String(index), onPaginationChange: (updater) => { const next = typeof updater === "function" ? updater(pagination) : updater; if (next.pageIndex === pagination.pageIndex) return; onPageChange(next.pageIndex + 1); }, }); return ( onRowClick(row, rows.indexOf(row)) : undefined } /> ); } export type { MapPopupDataTableProps };