import React from 'react' import { Button } from './Button' // ─── Pagination ─────────────────────────────────────────────────────────────── export interface PaginationProps { currentPage: number totalPages: number totalCount?: number pageSize?: number onPageChange: (page: number) => void className?: string } function buildPages(current: number, total: number): (number | '...')[] { if (total <= 7) return Array.from({ length: total }, (_, i) => i + 1) const pages: (number | '...')[] = [1] if (current > 3) pages.push('...') for (let i = Math.max(2, current - 1); i <= Math.min(total - 1, current + 1); i++) { pages.push(i) } if (current < total - 2) pages.push('...') pages.push(total) return pages } export const Pagination: React.FC = ({ currentPage, totalPages, totalCount, pageSize = 10, onPageChange, className = '', }) => { const start = (currentPage - 1) * pageSize + 1 const end = Math.min(currentPage * pageSize, totalCount ?? currentPage * pageSize) const pages = buildPages(currentPage, totalPages) return (
{totalCount != null && ( {start}-{end} / {totalCount}건 )}
{pages.map((p, i) => p === '...' ? ( ... ) : ( ) )}
) } // ─── Table ──────────────────────────────────────────────────────────────────── export interface TableColumn> { key: string label: string width?: string render?: (value: unknown, row: T, index: number) => React.ReactNode } export interface TableProps> { columns: TableColumn[] data: T[] title?: string totalCount?: number onSearch?: (query: string) => void onFilter?: () => void searchPlaceholder?: string currentPage?: number totalPages?: number pageSize?: number onPageChange?: (page: number) => void className?: string emptyMessage?: string } export function Table>({ columns, data, title, totalCount, onSearch, onFilter, searchPlaceholder = '검색...', currentPage, totalPages, pageSize, onPageChange, className = '', emptyMessage = '데이터가 없습니다.', }: TableProps) { const gridCols = columns.map((c) => c.width ?? '1fr').join(' ') return (
{/* Toolbar */} {(title || onSearch || onFilter) && (
{title &&

{title}

} {totalCount != null && ( {totalCount} )}
{onSearch && (
search onSearch(e.target.value)} />
)} {onFilter && ( )}
)} {/* Header */}
{columns.map((col) => ( {col.label} ))}
{/* Rows */}
{data.length === 0 ? (
{emptyMessage}
) : ( data.map((row, rowIndex) => (
{columns.map((col) => (
{col.render ? col.render((row as Record)[col.key], row, rowIndex) : String((row as Record)[col.key] ?? '')}
))}
)) )}
{/* Pagination */} {currentPage != null && totalPages != null && onPageChange && (
)}
) }