"use client"; import React, { useEffect, useRef, useState } from "react"; import { useQuery } from "@tanstack/react-query"; import { getThumbnails, ThumbnailRequest } from "@/lib/thumbnailLoader"; import { Skeleton } from "../ui/skeleton"; import Image from "next/image"; interface LazyLoadedImageProps { imgId: string; alt: string; width?: number; height?: number; className?: string; lazyFetch?: boolean; // true for avatars, false for game thumbnails size?: string; // optional fetch size } const LazyLoadedImage: React.FC = ({ imgId, alt, width = 1024, height = 1024, className, lazyFetch = true, size = "720x720", ...props }) => { const [isVisible, setIsVisible] = useState(!lazyFetch); const ref = useRef(null); const [type, targetIdStr] = imgId.split("_"); const targetId = Number(targetIdStr); // React Query to fetch thumbnail when visible or immediately if lazyFetch=false const { data: thumbnails, isLoading } = useQuery({ queryKey: ["thumbnails", targetId, size], queryFn: async () => { const result = await getThumbnails([ { type: type as any, targetId, format: "webp", size } ]); return result; }, enabled: isVisible, staleTime: 60_000 * 60 * 60 // 1 hour }); const imgUrl = thumbnails?.[0]?.imageUrl; // IntersectionObserver only used if lazyFetch=true useEffect(() => { if (!lazyFetch || !ref.current) return; const observer = new IntersectionObserver( ([entry]) => setIsVisible(entry.isIntersecting), { rootMargin: "200px" } ); observer.observe(ref.current); return () => observer.disconnect(); }, [lazyFetch]); return (
{imgUrl && !isLoading ? ( {alt} ) : ( )}
); }; export default LazyLoadedImage;