Files
school_compare/nextjs-app/components/Pagination.tsx

127 lines
3.0 KiB
TypeScript
Raw Normal View History

/**
* Pagination Component
* Navigate through pages of results
*/
'use client';
import { useRouter, useSearchParams, usePathname } from 'next/navigation';
import styles from './Pagination.module.css';
interface PaginationProps {
currentPage: number;
totalPages: number;
total: number;
}
export function Pagination({ currentPage, totalPages, total }: PaginationProps) {
const router = useRouter();
const pathname = usePathname();
const searchParams = useSearchParams();
if (totalPages <= 1) return null;
const goToPage = (page: number) => {
const params = new URLSearchParams(searchParams);
params.set('page', page.toString());
router.push(`${pathname}?${params.toString()}`);
};
const handlePrevious = () => {
if (currentPage > 1) {
goToPage(currentPage - 1);
}
};
const handleNext = () => {
if (currentPage < totalPages) {
goToPage(currentPage + 1);
}
};
// Generate page numbers to show
const getPageNumbers = () => {
const pages: (number | string)[] = [];
const maxVisible = 7;
if (totalPages <= maxVisible) {
// Show all pages
for (let i = 1; i <= totalPages; i++) {
pages.push(i);
}
} else {
// Show first, last, and pages around current
pages.push(1);
if (currentPage > 3) {
pages.push('...');
}
const start = Math.max(2, currentPage - 1);
const end = Math.min(totalPages - 1, currentPage + 1);
for (let i = start; i <= end; i++) {
pages.push(i);
}
if (currentPage < totalPages - 2) {
pages.push('...');
}
pages.push(totalPages);
}
return pages;
};
const pageNumbers = getPageNumbers();
return (
<div className={styles.pagination}>
<div className={styles.info}>
Showing page {currentPage} of {totalPages} ({total.toLocaleString()} total schools)
</div>
<div className={styles.controls}>
<button
onClick={handlePrevious}
disabled={currentPage === 1}
className={styles.navButton}
aria-label="Previous page"
>
Previous
</button>
<div className={styles.pages}>
{pageNumbers.map((page, index) => (
typeof page === 'number' ? (
<button
key={index}
onClick={() => goToPage(page)}
className={page === currentPage ? styles.pageButtonActive : styles.pageButton}
aria-label={`Go to page ${page}`}
aria-current={page === currentPage ? 'page' : undefined}
>
{page}
</button>
) : (
<span key={index} className={styles.ellipsis}>
{page}
</span>
)
))}
</div>
<button
onClick={handleNext}
disabled={currentPage === totalPages}
className={styles.navButton}
aria-label="Next page"
>
Next
</button>
</div>
</div>
);
}