Files
2026-08-25 16:20:50 +05:30

107 lines
3.1 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import { HugeiconsIcon } from '@hugeicons/react';
import { ChevronLeftIcon, ChevronRightIcon } from '@hugeicons/core-free-icons';
import { Button } from '@/components/ui/button';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
interface TablePaginationProps {
page: number;
pageSize: number;
totalRecords: number;
pageSizeOptions?: number[];
onPageChange: (page: number) => void;
onPageSizeChange: (size: number) => void;
}
function buildPageNumbers(page: number, totalPages: number): (number | '...')[] {
if (totalPages <= 7) return Array.from({ length: totalPages }, (_, i) => i + 1);
const pages: (number | '...')[] = [1];
if (page > 3) pages.push('...');
for (let i = Math.max(2, page - 1); i <= Math.min(totalPages - 1, page + 1); i++) {
pages.push(i);
}
if (page < totalPages - 2) pages.push('...');
pages.push(totalPages);
return pages;
}
export function TablePagination({
page,
pageSize,
totalRecords,
pageSizeOptions = [10, 25, 50, 100],
onPageChange,
onPageSizeChange,
}: TablePaginationProps) {
const totalPages = Math.max(1, Math.ceil(totalRecords / pageSize));
const from = Math.min((page - 1) * pageSize + 1, totalRecords);
const to = Math.min(page * pageSize, totalRecords);
const pages = buildPageNumbers(page, totalPages);
return (
<div className="flex flex-col gap-3 px-4 py-3 border-t sm:flex-row sm:items-center sm:justify-between">
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<span>Rows per page:</span>
<Select
value={pageSize}
onValueChange={(v) => onPageSizeChange(Number(v))}
>
<SelectTrigger size="sm" className="w-16">
<SelectValue />
</SelectTrigger>
<SelectContent>
{pageSizeOptions.map(s => (
<SelectItem key={s} value={s}>{s}</SelectItem>
))}
</SelectContent>
</Select>
<span className="ml-2">
{totalRecords === 0 ? '0 records' : `${from}–${to} of ${totalRecords} records`}
</span>
</div>
<div className="flex items-center gap-1">
<Button
variant="outline"
size="icon-sm"
onClick={() => onPageChange(page - 1)}
disabled={page <= 1}
>
<HugeiconsIcon icon={ChevronLeftIcon} className="size-4" />
</Button>
{pages.map((p, i) =>
p === '...' ? (
<span key={`ellipsis-${i}`} className="px-2 text-muted-foreground text-sm">…</span>
) : (
<Button
key={p}
variant={p === page ? 'default' : 'outline'}
size="icon-sm"
onClick={() => onPageChange(p as number)}
>
{p}
</Button>
)
)}
<Button
variant="outline"
size="icon-sm"
onClick={() => onPageChange(page + 1)}
disabled={page >= totalPages}
>
<HugeiconsIcon icon={ChevronRightIcon} className="size-4" />
</Button>
</div>
</div>
);
}