/** * Reusable hook for admin list pages * Provides common functionality: pagination, filtering, error handling */ import { useState } from 'react'; import { useQuery } from '@tanstack/react-query'; import type { UseQueryOptions } from '@tanstack/react-query'; interface UseAdminListPageOptions { queryKey: readonly unknown[]; queryFn: () => Promise; pageSize?: number; queryOptions?: Omit, 'queryKey' | 'queryFn'>; } interface UseAdminListPageResult { data: TData | undefined; isLoading: boolean; error: Error | null; currentPage: number; setCurrentPage: (page: number) => void; pageSize: number; totalPages: number; totalItems: number; hasData: boolean; } /** * Generic hook for admin list pages with pagination and error handling */ export function useAdminListPage( options: UseAdminListPageOptions ): UseAdminListPageResult { const { queryKey, queryFn, pageSize: initialPageSize = 25, queryOptions } = options; const [currentPage, setCurrentPage] = useState(1); const pageSize = initialPageSize; const query = useQuery({ queryKey, queryFn, retry: (failureCount, error: any) => { // Don't retry on 403 (Forbidden) or 401 (Unauthorized) errors if (error?.status === 403 || error?.status === 401) { return false; } // Retry up to 2 times for other errors return failureCount < 2; }, retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000), ...queryOptions, }); // Extract items array from response (handles different response shapes) const items = query.data ? Object.values(query.data).find((value) => Array.isArray(value)) || [] : []; const totalItems = Array.isArray(items) ? items.length : 0; const totalPages = Math.ceil(totalItems / pageSize); return { data: query.data, isLoading: query.isLoading, error: query.error || null, currentPage, setCurrentPage, pageSize, totalPages, totalItems, hasData: totalItems > 0, }; }