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 () {
|
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(
|
return(
|
||||||
<>
|
<>
|
||||||
|
<Table
|
||||||
|
columns={columns}
|
||||||
|
data={data}
|
||||||
|
pageSize={5}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -10,15 +10,18 @@ import {
|
|||||||
getFilteredRowModel,
|
getFilteredRowModel,
|
||||||
} from "@tanstack/react-table"
|
} from "@tanstack/react-table"
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { clsx, type ClassValue } from "clsx"
|
||||||
|
|
||||||
interface DataTableProps<TData, TValue> {
|
interface DataTableProps<TData, TValue> {
|
||||||
columns: ColumnDef<TData, TValue>[]
|
columns: ColumnDef<TData, TValue>[]
|
||||||
data: TData[]
|
data: TData[],
|
||||||
|
pageSize?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Table<TData, TValue>({
|
export default function Table<TData, TValue>({
|
||||||
columns,
|
columns,
|
||||||
data,
|
data,
|
||||||
|
pageSize = 10
|
||||||
}: DataTableProps<TData, TValue>) {
|
}: DataTableProps<TData, TValue>) {
|
||||||
const [rowSelection, setRowSelection] = useState({})
|
const [rowSelection, setRowSelection] = useState({})
|
||||||
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>(
|
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>(
|
||||||
@ -35,26 +38,37 @@ export default function Table<TData, TValue>({
|
|||||||
rowSelection,
|
rowSelection,
|
||||||
columnFilters,
|
columnFilters,
|
||||||
},
|
},
|
||||||
|
initialState: {
|
||||||
|
pagination: {
|
||||||
|
pageSize: pageSize,
|
||||||
|
}
|
||||||
|
},
|
||||||
getFilteredRowModel: getFilteredRowModel(),
|
getFilteredRowModel: getFilteredRowModel(),
|
||||||
onRowSelectionChange: setRowSelection,
|
onRowSelectionChange: setRowSelection,
|
||||||
onColumnFiltersChange: setColumnFilters,
|
onColumnFiltersChange: setColumnFilters,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const totalPages = table.getPageCount()
|
||||||
|
const currentPage = table.getState().pagination.pageIndex + 1
|
||||||
|
|
||||||
function clsx(arg0: string, arg1: { 'bg-gray-300': boolean; }): string | undefined {
|
const getPageNumbers = () => {
|
||||||
throw new Error("Function not implemented.");
|
const pages = []
|
||||||
|
for (let i = 1; i <= totalPages; i++) {
|
||||||
|
pages.push(i)
|
||||||
|
}
|
||||||
|
return pages
|
||||||
}
|
}
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<div>
|
<div>
|
||||||
<div className="rounded-md border">
|
<div className="rounded-lg border border-gray-200">
|
||||||
<table>
|
<table className="w-full overflow-x-auto rounded-lg " style={{ borderTopLeftRadius: '10px', borderTopRightRadius: '10px', }}>
|
||||||
<thead>
|
<thead className="h-10">
|
||||||
{table.getHeaderGroups().map((headerGroup) => (
|
{table.getHeaderGroups().map((headerGroup) => (
|
||||||
<tr key={headerGroup.id}>
|
<tr key={headerGroup.id} className="rounded-lg">
|
||||||
{headerGroup.headers.map((header) => {
|
{headerGroup.headers.map((header) => {
|
||||||
return(
|
return(
|
||||||
<th key={header.id}>
|
<th key={header.id} className="bg-blue-300 p-3 text-start">
|
||||||
{flexRender(
|
{flexRender(
|
||||||
header.column.columnDef.header,
|
header.column.columnDef.header,
|
||||||
header.getContext()
|
header.getContext()
|
||||||
@ -68,9 +82,9 @@ export default function Table<TData, TValue>({
|
|||||||
<tbody>
|
<tbody>
|
||||||
{table.getRowModel().rows.length ? (
|
{table.getRowModel().rows.length ? (
|
||||||
table.getRowModel().rows.map((row) => (
|
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) => (
|
{row.getVisibleCells().map((cell) => (
|
||||||
<td key={cell.id}>
|
<td key={cell.id} className="p-3 text-start">
|
||||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||||
</td>
|
</td>
|
||||||
))}
|
))}
|
||||||
@ -79,7 +93,7 @@ export default function Table<TData, TValue>({
|
|||||||
)
|
)
|
||||||
: (
|
: (
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td colSpan={columns.length}>
|
||||||
Aucun résultats
|
Aucun résultats
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -90,13 +104,32 @@ export default function Table<TData, TValue>({
|
|||||||
|
|
||||||
<div className="flex items-center justify-end space-x-2 py-4">
|
<div className="flex items-center justify-end space-x-2 py-4">
|
||||||
<button
|
<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()}
|
onClick={() => table.previousPage()}
|
||||||
disabled={!table.getCanPreviousPage()}
|
disabled={!table.getCanPreviousPage()}
|
||||||
>
|
>
|
||||||
Précédent
|
Précédent
|
||||||
</button>
|
</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
|
<button
|
||||||
|
className="border bg-gray-200 shadow-xs hover:bg-gray-300 hover:text-black px-3 py-1 rounded"
|
||||||
onClick={() => table.nextPage()}
|
onClick={() => table.nextPage()}
|
||||||
disabled={!table.getCanNextPage()}
|
disabled={!table.getCanNextPage()}
|
||||||
>
|
>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user