import { useState, useEffect, useRef, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { Link } from 'react-router-dom'; import api from '../api'; import SEO from '../components/SEO'; import PluginCard from '../components/PluginCard'; import { getPluginUrl } from '../utils/url'; // Global cache to persist data across component unmounts (navigation) let homeCache: { popular: any[]; newest: any[]; all: any[]; } | null = null; const Home = () => { const { i18n } = useTranslation(); const [popular, setPopular] = useState(homeCache?.popular || []); const [newest, setNewest] = useState(homeCache?.newest || []); const [allPlugins, setAllPlugins] = useState(homeCache?.all || []); const [loading, setLoading] = useState(false); const [heroIndex, setHeroIndex] = useState(0); const [heroSubImageIndex, setHeroSubImageIndex] = useState(0); const popularRef = useRef(null); const newestRef = useRef(null); const fetched = useRef({ popular: !!homeCache?.popular, newest: !!homeCache?.newest, all: !!homeCache?.all }); const saveSection = (key: 'popular' | 'newest' | 'all', data: any[]) => { if (key === 'popular') setPopular(data); if (key === 'newest') setNewest(data); if (key === 'all') setAllPlugins(data); homeCache = { popular: key === 'popular' ? data : homeCache?.popular || [], newest: key === 'newest' ? data : homeCache?.newest || [], all: key === 'all' ? data : homeCache?.all || [] }; fetched.current[key] = true; }; useEffect(() => { if (fetched.current.popular && fetched.current.newest && fetched.current.all) return; const loadSections = async () => { setLoading(true); try { const [popRes, newRes, allRes] = await Promise.all([ api.get('/plugins', { params: { sort: 'downloads' } }), api.get('/plugins', { params: { sort: 'newest' } }), api.get('/plugins') ]); saveSection('popular', Array.isArray(popRes.data) ? popRes.data : []); saveSection('newest', Array.isArray(newRes.data) ? newRes.data : []); saveSection('all', Array.isArray(allRes.data) ? allRes.data : []); } catch (err) { console.error('Fetch error for home sections:', err); } finally { setLoading(false); } }; loadSections(); }, []); // Featured plugins for top Steam-like carousel const featuredPlugins = useMemo(() => popular.slice(0, 5), [popular]); // Auto rotate hero slide every 6s useEffect(() => { if (featuredPlugins.length <= 1) return; const timer = setInterval(() => { setHeroIndex((prev) => (prev + 1) % featuredPlugins.length); setHeroSubImageIndex(0); }, 6000); return () => clearInterval(timer); }, [featuredPlugins.length]); const activeFeatured = featuredPlugins[heroIndex]; const featuredImages = useMemo(() => { if (!activeFeatured) return []; const imgs = []; if (activeFeatured.preview_path) imgs.push(activeFeatured.preview_path); if (activeFeatured.screenshots && activeFeatured.screenshots.length > 0) { imgs.push(...activeFeatured.screenshots); } return imgs; }, [activeFeatured]); const activeImage = featuredImages[heroSubImageIndex] || featuredImages[0]; const getDesc = (translatedStr?: string) => { if (!translatedStr) return 'Discover this high performance Minecraft plugin.'; try { const data = JSON.parse(translatedStr); const currentLang = i18n.language.split('-')[0]; return data[currentLang] || data.en || Object.values(data)[0] || 'Discover this high performance Minecraft plugin.'; } catch { return 'Discover this high performance Minecraft plugin.'; } }; if (loading && popular.length === 0) { return (

Discovering best plugins...

); } return ( <> {activeFeatured && (
{/* Main visual display */}
{activeImage ? ( {activeFeatured.name} ) : (
{activeFeatured.name.charAt(0).toUpperCase()}
)}
Trending & Popular {activeFeatured.type === 'free' ? ( Free ) : activeFeatured.sale_active && activeFeatured.sale_discount_percent > 0 ? ( -{activeFeatured.sale_discount_percent}% OFF ) : ( €{((activeFeatured.price_cents || 0) / 100).toFixed(2)} )}
{/* Sidebar Info */}

{activeFeatured.name}

by {activeFeatured.dev_name}

{featuredImages.slice(0, 4).map((src: string, idx: number) => (
{ e.preventDefault(); setHeroSubImageIndex(idx); }} > thumbnail
))}

{getDesc(activeFeatured.translated_descriptions)}

{(activeFeatured.downloads || 0).toLocaleString()} Downloads
{activeFeatured.version && ( v{activeFeatured.version} )}
View Plugin
{/* Navigation Dots / Controls */}
{featuredPlugins.map((item, idx) => ( ))}
)}

Most Popular

{popular.length > 0 ? ( popular.map((plugin) => ( )) ) : (
{loading ? 'Loading popular plugins...' : 'Scroll to load popular plugins'}
)}

New & Trending

{newest.length > 0 ? ( newest.map((plugin) => ( )) ) : (
{loading ? 'Loading new plugins...' : 'Scroll to load new plugins'}
)}

All Plugins ({allPlugins.length})

{allPlugins.length > 0 ? ( allPlugins.map((plugin) => ( )) ) : (
{loading ? 'Loading all plugins...' : 'No plugins available'}
)}
{(fetched.current?.popular && fetched.current?.newest && popular.length === 0 && newest.length === 0 && allPlugins.length === 0) && (

No plugins found. Check back later!

)}
); }; export default Home;