67 lines
1.8 KiB
TypeScript
67 lines
1.8 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useEffect, useCallback, useMemo } from 'react';
|
|
|
|
interface UseCollectionOptions {
|
|
page?: number;
|
|
limit?: number;
|
|
filter?: Record<string, unknown>;
|
|
}
|
|
|
|
interface CollectionResponse<T> {
|
|
data: T[];
|
|
total: number;
|
|
page: number;
|
|
limit: number;
|
|
totalPages: number;
|
|
}
|
|
|
|
export function useCollection<T = Record<string, unknown>>(
|
|
collectionName: string,
|
|
options: UseCollectionOptions = {}
|
|
) {
|
|
const [data, setData] = useState<T[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [total, setTotal] = useState(0);
|
|
const [totalPages, setTotalPages] = useState(0);
|
|
|
|
const { page = 1, limit = 20, filter = {} } = options;
|
|
|
|
// Mémoriser la chaîne JSON du filtre pour éviter les re-renders inutiles
|
|
const filterString = useMemo(() => JSON.stringify(filter), [filter]);
|
|
|
|
const fetchData = useCallback(async () => {
|
|
try {
|
|
setLoading(true);
|
|
const params = new URLSearchParams({
|
|
page: page.toString(),
|
|
limit: limit.toString(),
|
|
filter: filterString
|
|
});
|
|
|
|
const response = await fetch(`/api/collections/${collectionName}?${params}`);
|
|
if (!response.ok) throw new Error(`Erreur lors du chargement de ${collectionName}`);
|
|
|
|
const result: CollectionResponse<T> = await response.json();
|
|
setData(result.data);
|
|
setTotal(result.total);
|
|
setTotalPages(result.totalPages);
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : 'Erreur inconnue');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, [collectionName, page, limit, filterString]);
|
|
|
|
useEffect(() => {
|
|
fetchData();
|
|
}, [fetchData]);
|
|
|
|
const refetch = useCallback(() => {
|
|
return fetchData();
|
|
}, [fetchData]);
|
|
|
|
return { data, loading, error, total, totalPages, refetch };
|
|
}
|