feat: add pagination table
This commit is contained in:
parent
9dfe9bfe81
commit
43f5423cf9
@ -22,6 +22,7 @@
|
|||||||
"@emotion/react": "^11.11.4",
|
"@emotion/react": "^11.11.4",
|
||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "^11.11.0",
|
||||||
"@reduxjs/toolkit": "^2.2.1",
|
"@reduxjs/toolkit": "^2.2.1",
|
||||||
|
"@tanstack/react-table": "^8.13.2",
|
||||||
"ace-builds": "^1.32.7",
|
"ace-builds": "^1.32.7",
|
||||||
"framer-motion": "^11.0.13",
|
"framer-motion": "^11.0.13",
|
||||||
"github-markdown-css": "^5.5.1",
|
"github-markdown-css": "^5.5.1",
|
||||||
|
@ -26,6 +26,9 @@ dependencies:
|
|||||||
'@reduxjs/toolkit':
|
'@reduxjs/toolkit':
|
||||||
specifier: ^2.2.1
|
specifier: ^2.2.1
|
||||||
version: 2.2.1(react-redux@9.1.0)(react@18.2.0)
|
version: 2.2.1(react-redux@9.1.0)(react@18.2.0)
|
||||||
|
'@tanstack/react-table':
|
||||||
|
specifier: ^8.13.2
|
||||||
|
version: 8.13.2(react-dom@18.2.0)(react@18.2.0)
|
||||||
ace-builds:
|
ace-builds:
|
||||||
specifier: ^1.32.7
|
specifier: ^1.32.7
|
||||||
version: 1.32.7
|
version: 1.32.7
|
||||||
@ -2374,6 +2377,23 @@ packages:
|
|||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@tanstack/react-table@8.13.2(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-b6mR3mYkjRtJ443QZh9sc7CvGTce81J35F/XMr0OoWbx0KIM7TTTdyNP2XKObvkLpYnLpCrYDwI3CZnLezWvpg==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=16'
|
||||||
|
react-dom: '>=16'
|
||||||
|
dependencies:
|
||||||
|
'@tanstack/table-core': 8.13.2
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@tanstack/table-core@8.13.2:
|
||||||
|
resolution: {integrity: sha512-/2saD1lWBUV6/uNAwrsg2tw58uvMJ07bO2F1IWMxjFRkJiXKQRuc3Oq2aufeobD3873+4oIM/DRySIw7+QsPPw==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/babel__core@7.20.5:
|
/@types/babel__core@7.20.5:
|
||||||
resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
|
resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
136
src/components/Table.tsx
Normal file
136
src/components/Table.tsx
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardFooter,
|
||||||
|
Flex,
|
||||||
|
IconButton,
|
||||||
|
Select,
|
||||||
|
SkeletonText,
|
||||||
|
Table as ChakraTable,
|
||||||
|
Tbody,
|
||||||
|
Td,
|
||||||
|
Text,
|
||||||
|
Th,
|
||||||
|
Thead,
|
||||||
|
Tr,
|
||||||
|
useColorModeValue,
|
||||||
|
} from "@chakra-ui/react";
|
||||||
|
import type { ColumnDef, PaginationState } from "@tanstack/react-table";
|
||||||
|
import { flexRender, getCoreRowModel, getFilteredRowModel, useReactTable } from "@tanstack/react-table";
|
||||||
|
import { HiChevronDoubleLeft, HiChevronDoubleRight, HiChevronLeft, HiChevronRight } from "react-icons/hi";
|
||||||
|
|
||||||
|
interface TableProps<T> {
|
||||||
|
data: T[];
|
||||||
|
columns: ColumnDef<T>[];
|
||||||
|
total: number;
|
||||||
|
paging: PaginationState;
|
||||||
|
setPaging: (state: PaginationState | ((old: PaginationState) => PaginationState)) => void;
|
||||||
|
isLoading: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Table<T>(props: TableProps<T>) {
|
||||||
|
const bg = useColorModeValue("gray.100", "gray.900");
|
||||||
|
|
||||||
|
const table = useReactTable({
|
||||||
|
data: props.data,
|
||||||
|
columns: props.columns,
|
||||||
|
rowCount: props.total,
|
||||||
|
state: { pagination: props.paging },
|
||||||
|
onPaginationChange: props.setPaging,
|
||||||
|
manualPagination: true,
|
||||||
|
getCoreRowModel: getCoreRowModel(),
|
||||||
|
getFilteredRowModel: getFilteredRowModel(),
|
||||||
|
debugTable: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { pageSize, pageIndex } = table.getState().pagination;
|
||||||
|
const pageCount = table.getPageCount().toLocaleString();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Card flexDirection="column" flex={1} maxWidth="100%" width="100%">
|
||||||
|
<SkeletonText noOfLines={6} spacing="4" skeletonHeight="3" isLoaded={!props.isLoading}>
|
||||||
|
<ChakraTable>
|
||||||
|
<Thead>
|
||||||
|
{table.getHeaderGroups().map((headerGroup) => (
|
||||||
|
<Tr key={headerGroup.id}>
|
||||||
|
{headerGroup.headers.map((header) => (
|
||||||
|
<Th key={header.id} colSpan={header.colSpan} bg={bg} py={4} px={6}>
|
||||||
|
<Text fontWeight="bold">
|
||||||
|
{header.isPlaceholder
|
||||||
|
? null
|
||||||
|
: flexRender(header.column.columnDef.header, header.getContext())}
|
||||||
|
</Text>
|
||||||
|
</Th>
|
||||||
|
))}
|
||||||
|
</Tr>
|
||||||
|
))}
|
||||||
|
</Thead>
|
||||||
|
<Tbody>
|
||||||
|
{table.getRowModel().rows.map((row) => (
|
||||||
|
<Tr key={row.id}>
|
||||||
|
{row.getVisibleCells().map((cell) => (
|
||||||
|
<Td key={cell.id}>
|
||||||
|
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||||
|
</Td>
|
||||||
|
))}
|
||||||
|
</Tr>
|
||||||
|
))}
|
||||||
|
</Tbody>
|
||||||
|
</ChakraTable>
|
||||||
|
<CardFooter justify="space-between" alignItems="center" overflow="hidden" p={3}>
|
||||||
|
<Flex flexDirection="row">
|
||||||
|
<IconButton
|
||||||
|
aria-label="goto to first page"
|
||||||
|
size="sm"
|
||||||
|
ml={4}
|
||||||
|
mr={2}
|
||||||
|
icon={<HiChevronDoubleLeft size={20} />}
|
||||||
|
onClick={() => table.firstPage()}
|
||||||
|
isDisabled={!table.getCanPreviousPage()}
|
||||||
|
/>
|
||||||
|
<IconButton
|
||||||
|
aria-label="go to previous page"
|
||||||
|
size="sm"
|
||||||
|
mr={2}
|
||||||
|
icon={<HiChevronLeft size={20} />}
|
||||||
|
onClick={() => table.previousPage()}
|
||||||
|
isDisabled={!table.getCanPreviousPage()}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
<Flex justifyContent="center" alignItems="center">
|
||||||
|
<Text mr={4}>
|
||||||
|
Page {pageIndex + 1} of {pageCount}
|
||||||
|
</Text>
|
||||||
|
<Select w={28} value={pageSize} onChange={(e) => table.setPageSize(Number(e.target.value))}>
|
||||||
|
{[5, 10, 15, 20].map((pageSize) => (
|
||||||
|
<option key={pageSize} value={pageSize}>
|
||||||
|
Show {pageSize}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</Flex>
|
||||||
|
<Flex flexDirection="row">
|
||||||
|
<IconButton
|
||||||
|
aria-label="go to next page"
|
||||||
|
size="sm"
|
||||||
|
ml={2}
|
||||||
|
icon={<HiChevronRight size={20} />}
|
||||||
|
onClick={() => table.nextPage()}
|
||||||
|
isDisabled={!table.getCanNextPage()}
|
||||||
|
/>
|
||||||
|
<IconButton
|
||||||
|
aria-label="go to last page"
|
||||||
|
size="sm"
|
||||||
|
ml={2}
|
||||||
|
mr={4}
|
||||||
|
icon={<HiChevronDoubleRight size={20} />}
|
||||||
|
onClick={() => table.lastPage()}
|
||||||
|
isDisabled={!table.getCanNextPage()}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</CardFooter>
|
||||||
|
</SkeletonText>
|
||||||
|
</Card>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user