import { useState, useMemo, useCallback } from 'react'; import { UI_CONSTANTS } from '../constants'; interface PaginationConfig { itemsPerPage?: number; initialPage?: number; autoLoadMore?: boolean; } interface PaginationResult { // Current state currentPage: number; items: T[]; hasMore: boolean; isLoading: boolean; // Actions loadMore: () => void; resetPage: () => void; setPage: (page: number) => void; setSearchTerm: (term: string) => void; // Computed values totalItems: number; totalPages: number; startIndex: number; endIndex: number; searchTerm: string; } export const usePaginatedData = ( allItems: T[], config: PaginationConfig = {} ): PaginationResult => { const { itemsPerPage = UI_CONSTANTS.PAGINATION.ITEMS_PER_PAGE, initialPage = 1, autoLoadMore = false } = config; const [currentPage, setCurrentPage] = useState(initialPage); const [searchTerm, setSearchTerm] = useState(''); const [isLoading, setIsLoading] = useState(false); // Filter items by search term if provided const filteredItems = useMemo(() => { if (!searchTerm.trim()) return allItems; // Simple search implementation - can be overridden by passing filtered items return allItems.filter((item: T) => { if (typeof item === 'string') { return (item || '').toLowerCase().includes((searchTerm || '').toLowerCase()); } if (typeof item === 'object' && item !== null) { return Object.values(item as Record).some(value => String(value || '').toLowerCase().includes((searchTerm || '').toLowerCase()) ); } return false; }); }, [allItems, searchTerm]); // Calculate pagination values const totalItems = filteredItems.length; const totalPages = Math.ceil(totalItems / itemsPerPage); const startIndex = 0; const endIndex = currentPage * itemsPerPage; // Get paginated items const items = useMemo(() => { return filteredItems.slice(startIndex, endIndex); }, [filteredItems, endIndex]); // Check if there are more items to load const hasMore = useMemo(() => { return totalItems > itemsPerPage && items.length < totalItems; }, [totalItems, itemsPerPage, items.length]); // Load more items const loadMore = useCallback(() => { if (hasMore && !isLoading) { setIsLoading(true); // Simulate a small delay to show loading state setTimeout(() => { setCurrentPage(prev => prev + 1); setIsLoading(false); }, 100); } }, [hasMore, isLoading]); // Reset to first page const resetPage = useCallback(() => { setCurrentPage(initialPage); }, [initialPage]); // Set specific page const setPage = useCallback((page: number) => { setCurrentPage(page); }, []); // Handle search term changes const handleSearchTermChange = useCallback((term: string) => { setSearchTerm(term); resetPage(); // Reset to first page when searching }, [resetPage]); // Auto-load more if enabled and we're near the end useMemo(() => { if (autoLoadMore && hasMore && !isLoading && items.length > 0) { const lastItemIndex = items.length - 1; if (lastItemIndex >= endIndex - 5) { // Load more when 5 items away from end loadMore(); } } }, [autoLoadMore, hasMore, isLoading, items.length, endIndex, loadMore]); return { // Current state currentPage, items, hasMore, isLoading, // Actions loadMore, resetPage, setPage, setSearchTerm: handleSearchTermChange, // Computed values totalItems, totalPages, startIndex, endIndex, searchTerm, }; };