FactuGES_ERP/packages/rdx-ui/src/components/datatable/data-table-pagination.tsx

150 lines
5.2 KiB
TypeScript

import {
Pagination,
PaginationContent,
PaginationItem,
PaginationLink,
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@repo/shadcn-ui/components";
import { cn } from "@repo/shadcn-ui/lib/utils";
import type { Table } from "@tanstack/react-table";
import {
ChevronLeftIcon,
ChevronRightIcon,
ChevronsLeftIcon,
ChevronsRightIcon,
} from "lucide-react";
import { useTranslation } from "../../locales/i18n.ts";
import type { DataTableMeta } from "./data-table.tsx";
interface DataTablePaginationProps<TData> {
table: Table<TData>;
className?: string;
}
export function DataTablePagination<TData>({ table, className }: DataTablePaginationProps<TData>) {
const { t } = useTranslation();
const { pageIndex: rawIndex, pageSize: rawSize } = table.getState().pagination;
const meta = table.options.meta as DataTableMeta<TData>;
const totalRows = meta?.totalItems ?? table.getFilteredRowModel().rows.length;
const pageIndex = Number.isFinite(rawIndex) && rawIndex >= 0 ? rawIndex : 0;
const pageSize = Number.isFinite(rawSize) && rawSize > 0 ? rawSize : 10;
const pageCount = Math.max(1, Math.ceil(totalRows / pageSize));
const hasSelected = table.getFilteredSelectedRowModel().rows.length > 0;
const start = totalRows > 0 ? pageIndex * pageSize + 1 : 0;
const end = totalRows > 0 ? Math.min(start + pageSize - 1, totalRows) : 0;
const gotoPage = (index: number) => {
const nextIndex = Math.max(0, Math.min(index, pageCount - 1));
table.setPageIndex(nextIndex);
};
const handlePageSizeChange = (size: string) => {
table.setPageSize(Number(size));
};
return (
<div className={cn("flex items-center justify-between text-muted-foreground", className)}>
<div className="flex flex-1 flex-col items-center gap-4 sm:flex-row">
<span aria-live="polite">
{t("components.datatable.pagination.showing_range", { start, end, total: totalRows })}
</span>
{hasSelected && (
<span aria-live="polite">
{t("components.datatable.pagination.rows_selected", {
count: table.getFilteredSelectedRowModel().rows.length,
total: table.getFilteredRowModel().rows.length,
})}
</span>
)}
</div>
<div className="flex items-center gap-2">
<div className="flex items-center gap-2">
<span>{t("components.datatable.pagination.rows_per_page")}</span>
<Select onValueChange={handlePageSizeChange} value={String(pageSize)}>
<SelectTrigger className="h-8 w-20 border-gray-200 bg-white">
<SelectValue placeholder={String(pageSize)} />
</SelectTrigger>
<SelectContent>
{[5, 10, 20, 25, 30, 40, 50].map((size) => (
<SelectItem key={size} value={String(size)}>
{size}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationLink
aria-label={t("components.datatable.pagination.goto_first_page")}
className="cursor-pointer px-2.5"
isActive={pageIndex > 0}
onClick={() => pageIndex > 0 && gotoPage(0)}
size="sm"
>
<ChevronsLeftIcon className="size-4" />
</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink
aria-label={t("components.datatable.pagination.goto_previous_page")}
className="cursor-pointer px-2.5"
isActive={pageIndex > 0}
onClick={() => pageIndex > 0 && gotoPage(pageIndex - 1)}
size="sm"
>
<ChevronLeftIcon className="size-4" />
</PaginationLink>
</PaginationItem>
<span aria-live="polite" className="px-2 text-sm text-muted-foreground">
{t("components.datatable.pagination.page_of", {
page: pageIndex + 1,
of: pageCount,
})}
</span>
<PaginationItem>
<PaginationLink
aria-label={t("components.datatable.pagination.goto_next_page")}
className="cursor-pointer px-2.5"
isActive={pageIndex < pageCount - 1}
onClick={() => pageIndex < pageCount - 1 && gotoPage(pageIndex + 1)}
size="sm"
>
<ChevronRightIcon className="size-4" />
</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink
aria-label={t("components.datatable.pagination.goto_last_page")}
className="cursor-pointer px-2.5"
isActive={pageIndex < pageCount - 1}
onClick={() => pageIndex < pageCount - 1 && gotoPage(pageCount - 1)}
size="sm"
>
<ChevronsRightIcon className="size-4" />
</PaginationLink>
</PaginationItem>
</PaginationContent>
</Pagination>
</div>
</div>
);
}