feat: add server-side table sorting

This commit is contained in:
2026-06-17 10:59:50 +05:30
parent db11a512bf
commit bd0782a55f
28 changed files with 209 additions and 29 deletions

View File

@@ -58,6 +58,7 @@ export function useUserColumns({
{
accessorKey: 'roles',
header: 'Roles',
enableSorting: false,
cell: ({ row }) => (
<div className="flex flex-wrap gap-1">
{row.original.roles?.length ? (
@@ -93,6 +94,7 @@ export function useUserColumns({
columns.push({
id: 'actions',
header: () => <div className="text-right">Actions</div>,
enableSorting: false,
cell: ({ row }) => {
const user = row.original;
return (

View File

@@ -1,7 +1,7 @@
'use client';
import type { ReactNode } from 'react';
import type { ColumnDef } from '@tanstack/react-table';
import type { ColumnDef, SortingState } from '@tanstack/react-table';
import { DataTable } from '@/components/data-table';
import type { AdministrationUser } from '@/types';
@@ -14,8 +14,10 @@ interface UserTableProps {
skip: number;
limit: number;
total: number;
sorting: SortingState;
onPageChange: (skip: number) => void;
onLimitChange: (limit: number) => void;
onSortingChange: (sorting: SortingState) => void;
}
export function UserTable({
@@ -26,8 +28,10 @@ export function UserTable({
skip,
limit,
total,
sorting,
onPageChange,
onLimitChange,
onSortingChange,
}: UserTableProps) {
return (
<DataTable
@@ -44,6 +48,8 @@ export function UserTable({
onPageChange,
onLimitChange,
}}
sorting={sorting}
onSortingChange={onSortingChange}
/>
);
}

View File

@@ -2,6 +2,7 @@
import { useDebounce } from '@/hooks/useDebounce';
import type { UserStatus } from '@/types';
import type { SortingState } from '@tanstack/react-table';
import { useCallback, useState } from 'react';
export type StatusFilter = 'all' | UserStatus;
@@ -9,6 +10,7 @@ export type StatusFilter = 'all' | UserStatus;
export function useUserFilters() {
const [skip, setSkip] = useState(0);
const [limit, setLimitValue] = useState(10);
const [sorting, setSortingValue] = useState<SortingState>([]);
const [searchTerm, setSearchTermValue] = useState('');
const [statusFilter, setStatusFilterValue] = useState<StatusFilter>('all');
const debouncedSearchTerm = useDebounce(searchTerm.trim(), 400);
@@ -28,11 +30,18 @@ export function useUserFilters() {
setSkip(0);
}, []);
const setSorting = useCallback((value: SortingState) => {
setSortingValue(value);
setSkip(0);
}, []);
return {
skip,
setSkip,
limit,
setLimit,
sorting,
setSorting,
searchTerm,
debouncedSearchTerm,
setSearchTerm,

View File

@@ -2,7 +2,9 @@
import { useMemo } from 'react';
import { useQuery } from '@tanstack/react-query';
import type { SortingState } from '@tanstack/react-table';
import { getServerSortParams } from '@/components/data-table/sorting';
import { userService } from '@/services/api';
import type { UserListParams } from '@/types';
import { userKeys } from '../queries/userKeys';
@@ -13,6 +15,7 @@ interface UseUsersQueryParams {
limit: number;
searchTerm: string;
statusFilter: StatusFilter;
sorting: SortingState;
}
function buildUserListParams({
@@ -20,22 +23,22 @@ function buildUserListParams({
limit,
searchTerm,
statusFilter,
sorting,
}: UseUsersQueryParams): UserListParams {
return {
skip,
limit,
search_term: searchTerm || undefined,
effective_status: statusFilter === 'all' ? undefined : statusFilter,
sort_by: 'created_at',
sort_order: 'desc',
...getServerSortParams(sorting),
};
}
export function useUsersQuery(params: UseUsersQueryParams) {
const { skip, limit, searchTerm, statusFilter } = params;
const { skip, limit, searchTerm, statusFilter, sorting } = params;
const listParams = useMemo(
() => buildUserListParams({ skip, limit, searchTerm, statusFilter }),
[limit, searchTerm, skip, statusFilter],
() => buildUserListParams({ skip, limit, searchTerm, statusFilter, sorting }),
[limit, searchTerm, skip, sorting, statusFilter],
);
return useQuery({

View File

@@ -27,6 +27,8 @@ export default function UsersPage() {
setSkip,
limit,
setLimit,
sorting,
setSorting,
searchTerm,
debouncedSearchTerm,
setSearchTerm,
@@ -39,6 +41,7 @@ export default function UsersPage() {
limit,
searchTerm: debouncedSearchTerm,
statusFilter,
sorting,
});
const userForm = useUserForm({
onSaved: () => setIsSheetOpen(false),
@@ -128,8 +131,10 @@ export default function UsersPage() {
skip={skip}
limit={limit}
total={total}
sorting={sorting}
onPageChange={setSkip}
onLimitChange={setLimit}
onSortingChange={setSorting}
/>
<PoweredBy />