import { useEffect, useState, useRef, useCallback } from "react"; import { ProgressSpinner } from 'primereact/progressspinner'; import { Dialog } from 'primereact/dialog'; import { Image } from 'primereact/image'; import { toast } from 'react-toastify'; import { API_URL } from '../config'; const MEME_API_URL = `${API_URL}/memes/list_memes`; const BASE_IMAGE_URL = "https://codey.lol/meme"; const Memes = () => { const [images, setImages] = useState([]); const [page, setPage] = useState(1); const [loading, setLoading] = useState(false); const [hasMore, setHasMore] = useState(true); const [selectedImage, setSelectedImage] = useState(null); const observerRef = useRef(); const loadImages = async (pageNum, attempt = 0) => { if (loading || !hasMore) return; setLoading(true); try { const res = await fetch(`${MEME_API_URL}?page=${pageNum}`); if (res.status === 429) { const backoff = Math.min(1000 * Math.pow(2, attempt), 10000); // max 10s console.warn(`Rate limited. Retrying in ${backoff}ms`); setTimeout(() => { loadImages(pageNum, attempt + 1); }, backoff); return; } if (!res.ok) throw new Error(`HTTP ${res.status}`); const data = await res.json(); const newMemes = data?.memes || []; if (newMemes.length === 0 || data.paging.current >= data.paging.of) { setHasMore(false); } const imageObjects = newMemes.map(m => ({ id: m.id, timestamp: new Date(m.timestamp * 1000) .toString().split(" ") .splice(0, 4).join(" "), url: `${BASE_IMAGE_URL}/${m.id}.png`, })); setImages(prev => [...prev, ...imageObjects]); setPage(prev => prev + 1); } catch (e) { console.error("Failed to load memes", e); toast.error("Failed to load more memes."); } finally { setLoading(false); } }; const lastImageRef = useCallback(node => { if (loading) return; if (observerRef.current) observerRef.current.disconnect(); observerRef.current = new IntersectionObserver(entries => { if (entries[0].isIntersecting && hasMore) { loadImages(page); } }); if (node) observerRef.current.observe(node); }, [loading, hasMore, page]); useEffect(() => { loadImages(1); }, []); return ( <>