130 lines
4.3 KiB
TypeScript
130 lines
4.3 KiB
TypeScript
import { Button } from "@/components/ui/button";
|
|
import { useMediaQuery } from "@/hooks/use-media-query";
|
|
import { Table } from "@tanstack/react-table";
|
|
import {
|
|
ChevronLeft,
|
|
ChevronRight,
|
|
ChevronsLeft,
|
|
ChevronsRight,
|
|
} from "lucide-react";
|
|
import { useSearchParams, useRouter } from "next/navigation";
|
|
import React, { useEffect, useState } from "react";
|
|
|
|
interface DataTablePaginationProps {
|
|
table: Table<any>;
|
|
totalPage: number; // Total jumlah halaman
|
|
totalData: number; // Total jumlah data
|
|
visiblePageCount?: number; // Jumlah halaman yang ditampilkan (default 5)
|
|
}
|
|
|
|
const TablePagination = ({
|
|
table,
|
|
totalPage,
|
|
totalData,
|
|
visiblePageCount = 5,
|
|
}: DataTablePaginationProps) => {
|
|
const router = useRouter();
|
|
const searchParams = useSearchParams();
|
|
|
|
const [currentPageIndex, setCurrentPageIndex] = useState<number>(1);
|
|
|
|
const isMobile = useMediaQuery("(min-width: 768px)");
|
|
if (!isMobile) {
|
|
visiblePageCount = 3;
|
|
}
|
|
|
|
useEffect(() => {
|
|
const pageFromUrl = searchParams?.get("page");
|
|
if (pageFromUrl) {
|
|
const pageIndex = Math.min(Math.max(1, Number(pageFromUrl)), totalPage);
|
|
setCurrentPageIndex(pageIndex);
|
|
table.setPageIndex(pageIndex - 1); // Sinkronisasi tabel dengan URL
|
|
}
|
|
}, [searchParams, totalPage, table]);
|
|
|
|
const handlePageChange = (pageIndex: number) => {
|
|
const clampedPageIndex = Math.min(Math.max(1, pageIndex), totalPage);
|
|
const searchParams = new URLSearchParams(window.location.search);
|
|
searchParams.set("page", clampedPageIndex.toString());
|
|
|
|
router.push(`${window.location.pathname}?${searchParams.toString()}`);
|
|
setCurrentPageIndex(clampedPageIndex);
|
|
table.setPageIndex(clampedPageIndex - 1); // Perbarui tabel dengan index berbasis 0
|
|
};
|
|
|
|
const generatePageNumbers = () => {
|
|
const halfVisible = Math.floor(visiblePageCount / 2);
|
|
let startPage = Math.max(1, currentPageIndex - halfVisible);
|
|
let endPage = Math.min(totalPage, startPage + visiblePageCount - 1);
|
|
|
|
if (endPage - startPage + 1 < visiblePageCount) {
|
|
startPage = Math.max(1, endPage - visiblePageCount + 1);
|
|
}
|
|
|
|
return Array.from(
|
|
{ length: endPage - startPage + 1 },
|
|
(_, i) => startPage + i
|
|
);
|
|
};
|
|
|
|
return (
|
|
<div className="flex flex-col md:flex-row items-center justify-between py-4 px-10 space-y-4 md:space-y-0">
|
|
<div className="flex-1 text-sm text-muted-foreground text-center md:text-left">
|
|
{table.getFilteredSelectedRowModel().rows.length} of {totalData} row(s)
|
|
selected.
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<Button
|
|
variant="outline"
|
|
size="icon"
|
|
onClick={() => handlePageChange(1)}
|
|
disabled={currentPageIndex === 1}
|
|
className="min-w-[2rem] h-8 px-2 flex items-center justify-center"
|
|
>
|
|
<ChevronsLeft className="w-4 h-4" />
|
|
</Button>
|
|
<Button
|
|
variant="outline"
|
|
size="icon"
|
|
onClick={() => handlePageChange(currentPageIndex - 1)}
|
|
disabled={currentPageIndex === 1}
|
|
className="min-w-[2rem] h-8 px-2 flex items-center justify-center"
|
|
>
|
|
<ChevronLeft className="w-4 h-4" />
|
|
</Button>
|
|
{generatePageNumbers().map((pageIndex) => (
|
|
<Button
|
|
key={pageIndex}
|
|
onClick={() => handlePageChange(pageIndex)}
|
|
size="icon"
|
|
className="min-w-[2rem] h-8 px-2 flex items-center justify-center"
|
|
variant={currentPageIndex === pageIndex ? "default" : "outline"}
|
|
>
|
|
{pageIndex}
|
|
</Button>
|
|
))}
|
|
<Button
|
|
variant="outline"
|
|
size="icon"
|
|
onClick={() => handlePageChange(currentPageIndex + 1)}
|
|
disabled={currentPageIndex === totalPage}
|
|
className="min-w-[2rem] h-8 px-2 flex items-center justify-center"
|
|
>
|
|
<ChevronRight className="w-4 h-4" />
|
|
</Button>
|
|
<Button
|
|
variant="outline"
|
|
size="icon"
|
|
onClick={() => handlePageChange(totalPage)}
|
|
disabled={currentPageIndex === totalPage}
|
|
className="min-w-[2rem] h-8 px-2 flex items-center justify-center"
|
|
>
|
|
<ChevronsRight className="w-4 h-4" />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default TablePagination;
|