feat: add page size selection to AdvancedTable and update useServerTable hook

This commit is contained in:
estifanos
2026-08-11 11:36:59 +00:00
parent 0573e01769
commit 1b0a21c683
4 changed files with 46 additions and 16 deletions

View File

@@ -164,9 +164,10 @@ function ProfessionTab() {
const locale = i18n.language as "en" | "am";
const { handleError } = useErrorHandler();
const { data: deptRes } = useGetOrganizationsQuery();
const { pageIndex, setPageIndex, setQ, skip, take } = useServerTable({
pageSize: 10,
});
const { pageIndex, setPageIndex, setQ, pageSize, setPageSize, skip, take } =
useServerTable({
pageSize: 10,
});
const {
data: profRes,
isLoading,
@@ -371,7 +372,8 @@ function ProfessionTab() {
itemCount={totalCount}
pageIndex={pageIndex}
onPageChange={setPageIndex}
pageSize={10}
pageSize={pageSize}
onPageSizeChange={setPageSize}
refresh={refetch}
onSearchChange={setQ}
isLoading={isFetching}

View File

@@ -56,6 +56,8 @@ Copy `AdvancedTable.tsx` and `useServerTable.ts` into the new project (e.g. `src
| `pageIndex` | `number` | yes | 0-based current page. |
| `onPageChange` | `(pageIndex: number) => void` | yes | |
| `pageSize` | `number` | no | Default `10`. Pagination only renders when `itemCount > pageSize`. |
| `onPageSizeChange` | `(pageSize: number) => void` | no | Shows a page-size `<Select>` (10/20/50/100 by default) next to the pagination when given. |
| `pageSizeOptions` | `number[]` | no | Options for the page-size select. Default `[10, 20, 50, 100]`. |
| `refresh` | `() => void` | no | Shows a Refresh button when provided. |
| `onSearchChange` | `(q: string) => void` | no | Reserved for a search box; not currently rendered by the component itself (wire your own input and call this, or drive `useServerTable`'s `setQ`). |
| `isLoading` | `boolean` | no | Shows a loader row; also spins the Refresh button. |
@@ -66,10 +68,10 @@ Rows should have an `id: string \| number` field — used as the React key (fall
### `useServerTable(opts?)`
```ts
const { pageIndex, setPageIndex, q, setQ, pageSize, skip, take } = useServerTable({ pageSize: 10 });
const { pageIndex, setPageIndex, q, setQ, pageSize, setPageSize, skip, take } = useServerTable({ pageSize: 10 });
```
Centralizes page-index + search-query state for a server-paginated list. `setQ` resets `pageIndex` back to 0. `skip`/`take` are ready to drop into an offset-based API call.
Centralizes page-index + search-query state for a server-paginated list. `setQ` and `setPageSize` both reset `pageIndex` back to 0. `skip`/`take` are ready to drop into an offset-based API call. Wire `setPageSize` into `AdvancedTable`'s `onPageSizeChange` to expose the page-size select.
## Behavior notes

View File

@@ -10,6 +10,7 @@ import {
Loader,
Center,
Paper,
Select,
} from "@mantine/core";
import { IconRefresh, IconAdjustmentsHorizontal , IconInbox, } from "@tabler/icons-react";
import { useTranslation } from "react-i18next";
@@ -37,6 +38,10 @@ interface AdvancedTableProps<T> {
pageIndex: number;
onPageChange: (pageIndex: number) => void;
pageSize?: number;
/** Shows a page-size <Select> when given; called with the chosen size. */
onPageSizeChange?: (pageSize: number) => void;
/** Options for the page-size select. Default [10, 20, 50, 100]. */
pageSizeOptions?: number[];
refresh?: () => void;
/** Server-side search — debounced internally. Omit to hide the search box. */
onSearchChange?: (q: string) => void;
@@ -67,6 +72,8 @@ export function AdvancedTable<T extends { id?: string | number }>({
pageIndex,
onPageChange,
pageSize = 10,
onPageSizeChange,
pageSizeOptions = [10, 20, 50, 100],
refresh,
isLoading = false,
emptyText,
@@ -213,16 +220,28 @@ export function AdvancedTable<T extends { id?: string | number }>({
</Table>
</Table.ScrollContainer>
{itemCount > pageSize && (
{(itemCount > pageSize || onPageSizeChange) && (
<Group justify="flex-end" mt="md">
<Pagination
total={Math.ceil(itemCount / pageSize)}
value={pageIndex + 1}
onChange={(page) => onPageChange(page - 1)}
size="sm"
siblings={0}
boundaries={1}
/>
{onPageSizeChange && (
<Select
size="sm"
w={100}
data={pageSizeOptions.map((n) => String(n))}
value={String(pageSize)}
onChange={(v) => v && onPageSizeChange(Number(v))}
allowDeselect={false}
/>
)}
{itemCount > pageSize && (
<Pagination
total={Math.ceil(itemCount / pageSize)}
value={pageIndex + 1}
onChange={(page) => onPageChange(page - 1)}
size="sm"
siblings={0}
boundaries={1}
/>
)}
</Group>
)}
</Paper>

View File

@@ -8,8 +8,9 @@ interface UseServerTableOptions {
* Centralizes the page-index + search-query state a server-paginated table
* needs. Changing the search query resets paging back to page 0.
*/
export function useServerTable({ pageSize = 10 }: UseServerTableOptions = {}) {
export function useServerTable({ pageSize: initialPageSize = 10 }: UseServerTableOptions = {}) {
const [pageIndex, setPageIndex] = useState(0);
const [pageSize, setPageSizeInternal] = useState(initialPageSize);
const [q, setQInternal] = useState('');
const setQ = useCallback((value: string) => {
@@ -17,6 +18,11 @@ export function useServerTable({ pageSize = 10 }: UseServerTableOptions = {}) {
setPageIndex(0);
}, []);
const setPageSize = useCallback((value: number) => {
setPageSizeInternal(value);
setPageIndex(0);
}, []);
// Slice an already-fetched array for AdvancedTable when the endpoint has no
// skip/take of its own. Clamps pageIndex so deleting the last row of the
// last page doesn't strand the table on an empty slice.
@@ -39,6 +45,7 @@ export function useServerTable({ pageSize = 10 }: UseServerTableOptions = {}) {
q,
setQ,
pageSize,
setPageSize,
skip: pageIndex * pageSize,
take: pageSize,
paginate,