import React, { useEffect, useRef, useCallback } from "react"; import { LoaderCircle } from "lucide-react"; interface InfiniteScrollWrapperProps { children: React.ReactNode; hasMore?: boolean; onLoadMore?: () => Promise; isLoadingMore?: boolean; className?: string; loadingMessage?: string; endMessage?: string; threshold?: number; rootMargin?: string; showEndMessage?: boolean; } export function InfiniteScrollWrapper({ children, hasMore = false, onLoadMore, isLoadingMore = false, className = "", loadingMessage = "Loading more posts...", endMessage = "No more posts to load", threshold = 0.1, rootMargin = "100px", showEndMessage = true, }: InfiniteScrollWrapperProps) { const loadMoreRef = useRef(null); const observerRef = useRef(null); // Intersection Observer for infinite scroll const handleObserver = useCallback( (entries: IntersectionObserverEntry[]) => { const [target] = entries; if (target.isIntersecting && hasMore && onLoadMore && !isLoadingMore) { onLoadMore(); } }, [hasMore, onLoadMore, isLoadingMore] ); useEffect(() => { const element = loadMoreRef.current; if (!element || !onLoadMore) return; // Disconnect existing observer if (observerRef.current) { observerRef.current.disconnect(); } // Create new observer observerRef.current = new IntersectionObserver(handleObserver, { threshold, rootMargin, }); observerRef.current.observe(element); return () => { if (observerRef.current) { observerRef.current.disconnect(); } }; }, [ handleObserver, threshold, rootMargin, onLoadMore, isLoadingMore, hasMore, ]); return (
{children} {/* Infinite scroll trigger and loading states */} {hasMore && (
{isLoadingMore ? (
{loadingMessage}
) : (
Scroll to load more
)}
)} {/* End of posts indicator */} {!hasMore && showEndMessage && (

{endMessage}

)}
); }