import { useCallback, useEffect, useState } from 'react'; type PaginatedResourceResponse = { items: TItem[]; page: number; pageSize: number; total: number; totalPages: number; }; type UsePaginatedResourceOptions = { load: (params: { q: string; page: number; pageSize: number; sort?: string; }) => Promise>; sort?: string; debounceMs?: number; initialQuery?: string; initialPage?: number; initialPageSize?: number; }; export function usePaginatedResource({ load, sort, debounceMs = 250, initialQuery = '', initialPage = 1, initialPageSize = 10, }: UsePaginatedResourceOptions) { const [items, setItems] = useState([]); const [q, setQ] = useState(initialQuery); const [page, setPage] = useState(initialPage); const [pageSize, setPageSize] = useState(initialPageSize); const [total, setTotal] = useState(0); const [totalPages, setTotalPages] = useState(0); const [error, setError] = useState(null); const [isLoading, setIsLoading] = useState(true); useEffect(() => { let cancelled = false; setIsLoading(true); setError(null); const timer = setTimeout(() => { void (async () => { try { const response = await load({ q, page, pageSize, sort, }); if (cancelled) { return; } setItems(response.items); setTotal(response.total); setTotalPages(response.totalPages); setPage(response.page); setPageSize(response.pageSize); } catch (err) { if (!cancelled) { setError( err instanceof Error ? err.message : 'Request failed. Please try again.', ); } } finally { if (!cancelled) { setIsLoading(false); } } })(); }, debounceMs); return () => { cancelled = true; clearTimeout(timer); }; }, [q, page, pageSize, sort, load, debounceMs]); const setQuery = useCallback((value: string) => { setQ(value); setPage(1); }, []); const setPageSizeAndResetPage = useCallback((value: number) => { setPageSize(value); setPage(1); }, []); return { items, q, page, pageSize, total, totalPages, error, isLoading, setQuery, setPage, setPageSize: setPageSizeAndResetPage, }; }