'use client'; import React from 'react'; import { cn } from '../../../lib'; import { useIsMobile } from '../../../hooks'; import { useLocation, useQueryParams } from '../../../hooks/router'; import { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious } from './pagination'; interface SSRPaginationProps { currentPage: number; totalPages: number; totalItems: number; itemsPerPage: number; hasNextPage: boolean; hasPreviousPage: boolean; className?: string; showInfo?: boolean; maxVisiblePages?: number; baseUrl?: string; pathname?: string; preserveQuery?: boolean; } function buildSearch(params: Record, page: number, preserveQuery: boolean): string { const next = new URLSearchParams(); if (preserveQuery) { for (const [key, value] of Object.entries(params)) { if (key === 'page') continue; if (Array.isArray(value)) { for (const v of value) next.append(key, v); } else { next.set(key, value); } } } if (page !== 1) next.set('page', page.toString()); return next.toString(); } export const SSRPagination: React.FC = ({ currentPage, totalPages, totalItems, itemsPerPage, hasNextPage, hasPreviousPage: _hasPreviousPage, className, showInfo = true, maxVisiblePages = 7, baseUrl, pathname: propPathname, preserveQuery = true, }) => { const queryParams = useQueryParams(); const { pathname } = useLocation(); const isMobile = useIsMobile(); const getCurrentPageFromUrl = (): number => { const pageParam = queryParams.get('page'); if (pageParam) { const pageNum = parseInt(pageParam, 10); return isNaN(pageNum) ? 1 : pageNum; } return 1; }; const actualCurrentPage = getCurrentPageFromUrl() || currentPage; const actualHasPreviousPage = actualCurrentPage > 1; const getPageUrl = (page: number): string => { if (baseUrl) { return `${baseUrl}?page=${page}`; } const queryString = buildSearch(queryParams.params, page, preserveQuery); const basePath = propPathname || pathname || ''; return queryString ? `${basePath}?${queryString}` : basePath; }; const getVisiblePages = (): (number | 'ellipsis')[] => { const mobileMaxVisible = 3; const effectiveMaxVisible = isMobile ? mobileMaxVisible : maxVisiblePages; if (totalPages <= effectiveMaxVisible) { return Array.from({ length: totalPages }, (_, i) => i + 1); } const pages: (number | 'ellipsis')[] = []; const halfVisible = Math.floor(effectiveMaxVisible / 2); if (isMobile) { if (actualCurrentPage > 1) pages.push(actualCurrentPage - 1); pages.push(actualCurrentPage); if (actualCurrentPage < totalPages) pages.push(actualCurrentPage + 1); } else { pages.push(1); let start = Math.max(2, actualCurrentPage - halfVisible); let end = Math.min(totalPages - 1, actualCurrentPage + halfVisible); if (actualCurrentPage <= halfVisible + 1) { end = Math.min(totalPages - 1, effectiveMaxVisible - 1); } else if (actualCurrentPage >= totalPages - halfVisible) { start = Math.max(2, totalPages - effectiveMaxVisible + 2); } if (start > 2) pages.push('ellipsis'); for (let i = start; i <= end; i++) pages.push(i); if (end < totalPages - 1) pages.push('ellipsis'); if (totalPages > 1) pages.push(totalPages); } return pages; }; const visiblePages = getVisiblePages(); const startItem = (actualCurrentPage - 1) * itemsPerPage + 1; const endItem = Math.min(actualCurrentPage * itemsPerPage, totalItems); if (totalItems === 0) { return null; } return (
{showInfo && (
{isMobile ? ( `Page ${actualCurrentPage} of ${totalPages}` ) : ( `Showing ${startItem.toLocaleString()} to ${endItem.toLocaleString()} of ${totalItems.toLocaleString()} results` )}
)} {visiblePages.map((page, index) => ( {page === 'ellipsis' ? ( ) : ( {page} )} ))}
); }; SSRPagination.displayName = 'SSRPagination';