"use client"; import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { cn } from "@/lib/utils"; export interface PaginationInfo { currentPage: number; totalPages: number; totalItems: number; itemsPerPage: number; startItem: number; endItem: number; } export interface PaginationProps { paginationInfo: PaginationInfo; onPageChange: (page: number) => void; onPageSizeChange?: (pageSize: number) => void; showPageSizeSelector?: boolean; pageSizeOptions?: number[]; className?: string; } /** * 재사용 가능한 페이지네이션 컴포넌트 * * @example * console.log('Page changed:', page)} * onPageSizeChange={(size) => console.log('Page size changed:', size)} * showPageSizeSelector={true} * pageSizeOptions={[10, 20, 50, 100]} * /> */ export function Pagination({ paginationInfo, onPageChange, onPageSizeChange, showPageSizeSelector = false, pageSizeOptions = [10, 20, 50, 100], className, }: PaginationProps) { const { currentPage, totalPages, totalItems, itemsPerPage, startItem, endItem } = paginationInfo; // 페이지 버튼 범위 계산 (현재 페이지 기준으로 앞뒤 2개씩) const getPageNumbers = () => { const delta = 2; const range = []; const rangeWithDots = []; // 시작과 끝 계산 let start = Math.max(1, currentPage - delta); let end = Math.min(totalPages, currentPage + delta); // 범위 조정 if (end - start < delta * 2) { if (start === 1) { end = Math.min(totalPages, start + delta * 2); } else if (end === totalPages) { start = Math.max(1, end - delta * 2); } } // 페이지 번호 배열 생성 for (let i = start; i <= end; i++) { range.push(i); } // 첫 페이지와 점 추가 if (start > 1) { rangeWithDots.push(1); if (start > 2) { rangeWithDots.push("..."); } } // 중간 범위 추가 rangeWithDots.push(...range); // 마지막 페이지와 점 추가 if (end < totalPages) { if (end < totalPages - 1) { rangeWithDots.push("..."); } rangeWithDots.push(totalPages); } return rangeWithDots; }; const pageNumbers = getPageNumbers(); // 페이지 변경 핸들러 const handlePageChange = (page: number) => { if (page >= 1 && page <= totalPages && page !== currentPage) { onPageChange(page); } }; // 페이지 크기 변경 핸들러 const handlePageSizeChange = (newPageSize: string) => { const size = parseInt(newPageSize, 10); if (onPageSizeChange && size !== itemsPerPage) { onPageSizeChange(size); } }; // 항상 페이지네이션을 표시 (1페이지일 때도 표시) return (
{/* 페이지 정보 */}
{startItem.toLocaleString()} {" - "} {endItem.toLocaleString()} {" / "} {totalItems.toLocaleString()}개 항목
{/* 페이지네이션 컨트롤 */}
{/* 페이지 크기 선택 */} {showPageSizeSelector && onPageSizeChange && (
페이지당
)} {/* 페이지 버튼들 */}
{/* 첫 페이지로 */} {/* 이전 페이지 */} {/* 페이지 번호들 */} {pageNumbers.map((page, index) => (
{page === "..." ? ( ... ) : ( )}
))} {/* 다음 페이지 */} {/* 마지막 페이지로 */}
); }