Files
web-core/src/hooks/usePaginatedResource.ts
Beatrice Dellacà cbabf43584
All checks were successful
continuous-integration/drone/push Build is passing
update prettier
2026-02-23 14:23:46 +01:00

112 lines
3.0 KiB
TypeScript

import { useCallback, useEffect, useState } from 'react';
type PaginatedResourceResponse<TItem> = {
items: TItem[];
page: number;
pageSize: number;
total: number;
totalPages: number;
};
type UsePaginatedResourceOptions<TItem> = {
load: (params: {
q: string;
page: number;
pageSize: number;
sort?: string;
}) => Promise<PaginatedResourceResponse<TItem>>;
sort?: string;
debounceMs?: number;
initialQuery?: string;
initialPage?: number;
initialPageSize?: number;
};
export function usePaginatedResource<TItem>({
load,
sort,
debounceMs = 250,
initialQuery = '',
initialPage = 1,
initialPageSize = 10,
}: UsePaginatedResourceOptions<TItem>) {
const [items, setItems] = useState<TItem[]>([]);
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<string | null>(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,
};
}