172 lines
5.5 KiB
TypeScript
172 lines
5.5 KiB
TypeScript
"use client";
|
|
|
|
import { type Table } from "@tanstack/react-table";
|
|
import {
|
|
Pagination,
|
|
PaginationContent,
|
|
PaginationEllipsis,
|
|
PaginationItem,
|
|
} from "@kandev/ui/pagination";
|
|
import { Button } from "@kandev/ui/button";
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@kandev/ui/select";
|
|
import {
|
|
IconChevronLeft,
|
|
IconChevronRight,
|
|
IconChevronsLeft,
|
|
IconChevronsRight,
|
|
} from "@tabler/icons-react";
|
|
|
|
interface DataTablePaginationProps<TData> {
|
|
table: Table<TData>;
|
|
}
|
|
|
|
function getPageNumbers(currentPage: number, pageCount: number): (number | "ellipsis")[] {
|
|
const pages: (number | "ellipsis")[] = [];
|
|
const showPages = 5;
|
|
if (pageCount <= showPages) {
|
|
for (let i = 1; i <= pageCount; i++) pages.push(i);
|
|
return pages;
|
|
}
|
|
pages.push(1);
|
|
if (currentPage > 3) pages.push("ellipsis");
|
|
const start = Math.max(2, currentPage - 1);
|
|
const end = Math.min(pageCount - 1, currentPage + 1);
|
|
for (let i = start; i <= end; i++) pages.push(i);
|
|
if (currentPage < pageCount - 2) pages.push("ellipsis");
|
|
if (pageCount > 1) pages.push(pageCount);
|
|
return pages;
|
|
}
|
|
|
|
function PageButtons({
|
|
pages,
|
|
currentPage,
|
|
onPageChange,
|
|
}: {
|
|
pages: (number | "ellipsis")[];
|
|
currentPage: number;
|
|
onPageChange: (page: number) => void;
|
|
}) {
|
|
return (
|
|
<>
|
|
{pages.map((page, idx) =>
|
|
page === "ellipsis" ? (
|
|
<PaginationItem key={`ellipsis-${idx}`}>
|
|
<PaginationEllipsis />
|
|
</PaginationItem>
|
|
) : (
|
|
<PaginationItem key={page}>
|
|
<Button
|
|
variant={page === currentPage ? "outline" : "ghost"}
|
|
size="icon"
|
|
className="cursor-pointer"
|
|
onClick={() => onPageChange(page - 1)}
|
|
>
|
|
{page}
|
|
</Button>
|
|
</PaginationItem>
|
|
),
|
|
)}
|
|
</>
|
|
);
|
|
}
|
|
|
|
export function DataTablePagination<TData>({ table }: DataTablePaginationProps<TData>) {
|
|
const currentPage = table.getState().pagination.pageIndex + 1;
|
|
const pageCount = table.getPageCount();
|
|
const pages = getPageNumbers(currentPage, pageCount);
|
|
const pagination = table.getState().pagination;
|
|
|
|
return (
|
|
<div className="flex items-center justify-between px-2">
|
|
<div className="flex-1 text-sm text-muted-foreground">
|
|
{table.getFilteredRowModel().rows.length > 0 && (
|
|
<>
|
|
Showing {pagination.pageIndex * pagination.pageSize + 1} to{" "}
|
|
{Math.min((pagination.pageIndex + 1) * pagination.pageSize, table.getRowCount())} of{" "}
|
|
{table.getRowCount()} results
|
|
</>
|
|
)}
|
|
</div>
|
|
<div className="flex items-center space-x-6 lg:space-x-8">
|
|
<div className="flex items-center space-x-2">
|
|
<p className="text-sm font-medium whitespace-nowrap">Rows per page</p>
|
|
<Select
|
|
value={`${pagination.pageSize}`}
|
|
onValueChange={(value) => {
|
|
table.setPageSize(Number(value));
|
|
}}
|
|
>
|
|
<SelectTrigger className="h-8 w-[70px]">
|
|
<SelectValue placeholder={pagination.pageSize} />
|
|
</SelectTrigger>
|
|
<SelectContent side="top">
|
|
{[10, 25, 50].map((pageSize) => (
|
|
<SelectItem key={pageSize} value={`${pageSize}`}>
|
|
{pageSize}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
<Pagination>
|
|
<PaginationContent>
|
|
<PaginationItem>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="hidden lg:flex cursor-pointer"
|
|
onClick={() => table.setPageIndex(0)}
|
|
disabled={!table.getCanPreviousPage()}
|
|
>
|
|
<span className="sr-only">Go to first page</span>
|
|
<IconChevronsLeft className="h-4 w-4" />
|
|
</Button>
|
|
</PaginationItem>
|
|
<PaginationItem>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="cursor-pointer"
|
|
onClick={() => table.previousPage()}
|
|
disabled={!table.getCanPreviousPage()}
|
|
>
|
|
<span className="sr-only">Go to previous page</span>
|
|
<IconChevronLeft className="h-4 w-4" />
|
|
</Button>
|
|
</PaginationItem>
|
|
<PageButtons
|
|
pages={pages}
|
|
currentPage={currentPage}
|
|
onPageChange={(p) => table.setPageIndex(p)}
|
|
/>
|
|
<PaginationItem>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="cursor-pointer"
|
|
onClick={() => table.nextPage()}
|
|
disabled={!table.getCanNextPage()}
|
|
>
|
|
<span className="sr-only">Go to next page</span>
|
|
<IconChevronRight className="h-4 w-4" />
|
|
</Button>
|
|
</PaginationItem>
|
|
<PaginationItem>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="hidden lg:flex cursor-pointer"
|
|
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
|
|
disabled={!table.getCanNextPage()}
|
|
>
|
|
<span className="sr-only">Go to last page</span>
|
|
<IconChevronsRight className="h-4 w-4" />
|
|
</Button>
|
|
</PaginationItem>
|
|
</PaginationContent>
|
|
</Pagination>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|