feat: add pagination on data table
This commit is contained in:
parent
130473d3e4
commit
98d68a535b
@ -1,10 +1,129 @@
|
||||
"use client"
|
||||
|
||||
import Table from "#/components/table/table"
|
||||
import { ColumnDef } from "@tanstack/react-table"
|
||||
|
||||
|
||||
export default function HomePage () {
|
||||
type Payment = {
|
||||
id: string
|
||||
amount: number
|
||||
status: "pending" | "processing" | "success" | "failed"
|
||||
email: string
|
||||
}
|
||||
|
||||
|
||||
const data: Payment[] = [
|
||||
{
|
||||
id: "728ed52f",
|
||||
amount: 100,
|
||||
status: "pending",
|
||||
email: "m@example.com",
|
||||
},
|
||||
{
|
||||
id: "728ed521",
|
||||
amount: 200,
|
||||
status: "pending",
|
||||
email: "j@example.com",
|
||||
},
|
||||
{
|
||||
id: "728ed528",
|
||||
amount: 300,
|
||||
status: "processing",
|
||||
email: "f@example.com",
|
||||
},
|
||||
{
|
||||
id: "728ed52g",
|
||||
amount: 600,
|
||||
status: "success",
|
||||
email: "h@example.com",
|
||||
},
|
||||
{
|
||||
id: "728ed520",
|
||||
amount: 50,
|
||||
status: "failed",
|
||||
email: "k@example.com",
|
||||
},
|
||||
{
|
||||
id: "728ed529",
|
||||
amount: 200,
|
||||
status: "pending",
|
||||
email: "l@example.com",
|
||||
},
|
||||
{
|
||||
id: "728ed526",
|
||||
amount: 150,
|
||||
status: "processing",
|
||||
email: "d@example.com",
|
||||
},
|
||||
{
|
||||
id: "728ed523",
|
||||
amount: 100,
|
||||
status: "success",
|
||||
email: "o@example.com",
|
||||
},
|
||||
{
|
||||
id: "728ed52y",
|
||||
amount: 100,
|
||||
status: "failed",
|
||||
email: "v@example.com",
|
||||
},
|
||||
// ...
|
||||
]
|
||||
|
||||
|
||||
|
||||
const columns: ColumnDef<Payment>[] = [
|
||||
{
|
||||
id: "select",
|
||||
header: ({ table }) => (
|
||||
<input checked={
|
||||
table.getIsAllPageRowsSelected() ||
|
||||
(table.getIsSomePageRowsSelected() && undefined)
|
||||
} onChange={(value) => table.toggleAllPageRowsSelected(!!value)} type="checkbox" name="" id="" />
|
||||
),
|
||||
cell: ({ row }) => (
|
||||
<input checked={row.getIsSelected()} onChange={(value) => row.toggleSelected(!!value)} type="checkbox" name="" id="" />
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Status",
|
||||
},
|
||||
{
|
||||
accessorKey: "email",
|
||||
header: ({ column }) => {
|
||||
return (
|
||||
<p>Email</p>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "amount",
|
||||
header: () => <div className="">Amount</div>,
|
||||
cell: ({ row }) => {
|
||||
const amount = parseFloat(row.getValue("amount"))
|
||||
const formatted = new Intl.NumberFormat("en-US", {
|
||||
style: "currency",
|
||||
currency: "USD",
|
||||
}).format(amount)
|
||||
|
||||
return <div className="font-medium">{formatted}</div>
|
||||
},
|
||||
|
||||
|
||||
|
||||
},
|
||||
|
||||
]
|
||||
|
||||
return(
|
||||
<>
|
||||
|
||||
<Table
|
||||
columns={columns}
|
||||
data={data}
|
||||
pageSize={5}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -10,15 +10,18 @@ import {
|
||||
getFilteredRowModel,
|
||||
} from "@tanstack/react-table"
|
||||
import { useState } from "react";
|
||||
import { clsx, type ClassValue } from "clsx"
|
||||
|
||||
interface DataTableProps<TData, TValue> {
|
||||
columns: ColumnDef<TData, TValue>[]
|
||||
data: TData[]
|
||||
data: TData[],
|
||||
pageSize?: number
|
||||
}
|
||||
|
||||
export default function Table<TData, TValue>({
|
||||
columns,
|
||||
data,
|
||||
pageSize = 10
|
||||
}: DataTableProps<TData, TValue>) {
|
||||
const [rowSelection, setRowSelection] = useState({})
|
||||
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>(
|
||||
@ -35,26 +38,37 @@ export default function Table<TData, TValue>({
|
||||
rowSelection,
|
||||
columnFilters,
|
||||
},
|
||||
initialState: {
|
||||
pagination: {
|
||||
pageSize: pageSize,
|
||||
}
|
||||
},
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
onRowSelectionChange: setRowSelection,
|
||||
onColumnFiltersChange: setColumnFilters,
|
||||
})
|
||||
|
||||
const totalPages = table.getPageCount()
|
||||
const currentPage = table.getState().pagination.pageIndex + 1
|
||||
|
||||
function clsx(arg0: string, arg1: { 'bg-gray-300': boolean; }): string | undefined {
|
||||
throw new Error("Function not implemented.");
|
||||
const getPageNumbers = () => {
|
||||
const pages = []
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
pages.push(i)
|
||||
}
|
||||
return pages
|
||||
}
|
||||
|
||||
return(
|
||||
<div>
|
||||
<div className="rounded-md border">
|
||||
<table>
|
||||
<thead>
|
||||
<div className="rounded-lg border border-gray-200">
|
||||
<table className="w-full overflow-x-auto rounded-lg " style={{ borderTopLeftRadius: '10px', borderTopRightRadius: '10px', }}>
|
||||
<thead className="h-10">
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<tr key={headerGroup.id}>
|
||||
<tr key={headerGroup.id} className="rounded-lg">
|
||||
{headerGroup.headers.map((header) => {
|
||||
return(
|
||||
<th key={header.id}>
|
||||
<th key={header.id} className="bg-blue-300 p-3 text-start">
|
||||
{flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
@ -68,9 +82,9 @@ export default function Table<TData, TValue>({
|
||||
<tbody>
|
||||
{table.getRowModel().rows.length ? (
|
||||
table.getRowModel().rows.map((row) => (
|
||||
<tr key={row.id} className={clsx('hover:bg-gray-300', { 'bg-gray-300': row.getIsSelected()})}>
|
||||
<tr key={row.id} className={clsx('hover:bg-gray-300 border-t border-gray-200', { 'bg-gray-300': row.getIsSelected()})}>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<td key={cell.id}>
|
||||
<td key={cell.id} className="p-3 text-start">
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</td>
|
||||
))}
|
||||
@ -79,7 +93,7 @@ export default function Table<TData, TValue>({
|
||||
)
|
||||
: (
|
||||
<tr>
|
||||
<td>
|
||||
<td colSpan={columns.length}>
|
||||
Aucun résultats
|
||||
</td>
|
||||
</tr>
|
||||
@ -90,13 +104,32 @@ export default function Table<TData, TValue>({
|
||||
|
||||
<div className="flex items-center justify-end space-x-2 py-4">
|
||||
<button
|
||||
className="border bg-gray-200 shadow-xs hover:bg-gray-300 hover:text-black"
|
||||
className="border bg-gray-200 shadow-xs hover:bg-gray-300 hover:text-black px-3 py-1 rounded"
|
||||
onClick={() => table.previousPage()}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
>
|
||||
Précédent
|
||||
</button>
|
||||
|
||||
<div className="flex space-x-1">
|
||||
{getPageNumbers().map((pageNumber) => (
|
||||
<button
|
||||
key={pageNumber}
|
||||
className={clsx(
|
||||
"px-3 py-1 rounded",
|
||||
pageNumber === currentPage
|
||||
? "bg-blue-500 text-white"
|
||||
: "bg-gray-200 hover:bg-gray-300"
|
||||
)}
|
||||
onClick={() => table.setPageIndex(pageNumber - 1)}
|
||||
>
|
||||
{pageNumber}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<button
|
||||
className="border bg-gray-200 shadow-xs hover:bg-gray-300 hover:text-black px-3 py-1 rounded"
|
||||
onClick={() => table.nextPage()}
|
||||
disabled={!table.getCanNextPage()}
|
||||
>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user