From cebc4c8ca931967f814bd6d1fee3a66f548801b3 Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Thu, 17 Jul 2025 20:32:24 -0500 Subject: [PATCH] Add pagination. --- frontend/src/components/tables/LogosTable.jsx | 120 ++++++++++++++++-- 1 file changed, 111 insertions(+), 9 deletions(-) diff --git a/frontend/src/components/tables/LogosTable.jsx b/frontend/src/components/tables/LogosTable.jsx index 61a325c2..64822cb5 100644 --- a/frontend/src/components/tables/LogosTable.jsx +++ b/frontend/src/components/tables/LogosTable.jsx @@ -31,6 +31,8 @@ import { TextInput, Menu, Checkbox, + Pagination, + NativeSelect, } from '@mantine/core'; import { CustomTable, useTable } from './CustomTable'; import ConfirmationDialog from '../ConfirmationDialog'; @@ -101,6 +103,12 @@ const LogosTable = () => { }); const [debouncedNameFilter, setDebouncedNameFilter] = useState(''); const [selectedRows, setSelectedRows] = useState(new Set()); + const [pageSize, setPageSize] = useLocalStorage('logos-page-size', 25); + const [pagination, setPagination] = useState({ + pageIndex: 0, + pageSize: pageSize, + }); + const [paginationString, setPaginationString] = useState(''); // Debounce the name filter useEffect(() => { @@ -132,6 +140,13 @@ const LogosTable = () => { return filteredLogos.sort((a, b) => a.id - b.id); }, [logos, debouncedNameFilter, filters.used]); + // Get paginated data + const paginatedData = useMemo(() => { + const startIndex = pagination.pageIndex * pagination.pageSize; + const endIndex = startIndex + pagination.pageSize; + return data.slice(startIndex, endIndex); + }, [data, pagination.pageIndex, pagination.pageSize]); + // Calculate unused logos count const unusedLogosCount = useMemo(() => { const allLogos = Object.values(logos || {}); @@ -270,6 +285,29 @@ const LogosTable = () => { setSelectedRows(new Set()); }, [data.length]); + // Update pagination when pageSize changes + useEffect(() => { + setPagination(prev => ({ + ...prev, + pageSize: pageSize, + })); + }, [pageSize]); + + // Calculate pagination string + useEffect(() => { + const startItem = pagination.pageIndex * pagination.pageSize + 1; + const endItem = Math.min( + (pagination.pageIndex + 1) * pagination.pageSize, + data.length + ); + setPaginationString(`${startItem} to ${endItem} of ${data.length}`); + }, [pagination.pageIndex, pagination.pageSize, data.length]); + + // Calculate page count + const pageCount = useMemo(() => { + return Math.ceil(data.length / pagination.pageSize); + }, [data.length, pagination.pageSize]); + /** * useMemo */ @@ -425,17 +463,38 @@ const LogosTable = () => { setSelectedRows(new Set(newSelection)); }, []); + const onPageSizeChange = (e) => { + const newPageSize = parseInt(e.target.value); + setPageSize(newPageSize); + setPagination(prev => ({ + ...prev, + pageSize: newPageSize, + pageIndex: 0, // Reset to first page + })); + }; + + const onPageIndexChange = (pageIndex) => { + if (!pageIndex || pageIndex > pageCount) { + return; + } + + setPagination(prev => ({ + ...prev, + pageIndex: pageIndex - 1, + })); + }; + const table = useTable({ columns, - data, - allRowIds: data.map((logo) => logo.id), - enablePagination: false, + data: paginatedData, + allRowIds: paginatedData.map((logo) => logo.id), + enablePagination: false, // Disable internal pagination since we're handling it manually enableRowSelection: true, enableRowVirtualization: false, renderTopToolbar: false, manualSorting: false, manualFiltering: false, - manualPagination: false, + manualPagination: true, // Enable manual pagination onRowSelectionChange: onRowSelectionChange, headerCellRenderFns: { actions: renderHeaderCell, @@ -571,14 +630,57 @@ const LogosTable = () => { -
- - -
+ +
+ + +
+
+ + {/* Pagination Controls */} + + + Page Size + + + {paginationString} + +