import { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import api from '../services/api'; import './Leaderboards.css'; import './Game.css'; interface LeaderboardEntry { rank: number; player_id: number; username: string; name: string; level: number; value: number; } interface StatOption { key: string; label: string; icon: string; color: string; } const STAT_OPTIONS: StatOption[] = [ { key: 'enemies_killed', label: 'Enemies Killed', icon: 'โš”๏ธ', color: '#ff6b6b' }, { key: 'distance_walked', label: 'Distance Traveled', icon: '๐Ÿšถ', color: '#6bb9f0' }, { key: 'combats_initiated', label: 'Combats Started', icon: '๐Ÿ’ฅ', color: '#f093fb' }, { key: 'damage_dealt', label: 'Damage Dealt', icon: '๐Ÿ—ก๏ธ', color: '#ff8787' }, { key: 'damage_taken', label: 'Damage Taken', icon: '๐Ÿ›ก๏ธ', color: '#ffa94d' }, { key: 'items_collected', label: 'Items Collected', icon: '๐Ÿ“ฆ', color: '#51cf66' }, { key: 'items_used', label: 'Items Used', icon: '๐Ÿงช', color: '#74c0fc' }, { key: 'hp_restored', label: 'HP Restored', icon: 'โค๏ธ', color: '#ff6b9d' }, { key: 'stamina_restored', label: 'Stamina Restored', icon: 'โšก', color: '#ffd93d' }, ]; export default function Leaderboards() { const navigate = useNavigate(); const [selectedStat, setSelectedStat] = useState(STAT_OPTIONS[0]); const [leaderboard, setLeaderboard] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [currentPage, setCurrentPage] = useState(1); const [mobileHeaderOpen, setMobileHeaderOpen] = useState(false); const [statDropdownOpen, setStatDropdownOpen] = useState(false); const ITEMS_PER_PAGE = 25; useEffect(() => { setCurrentPage(1); // Reset to page 1 when stat changes fetchLeaderboard(selectedStat.key); }, [selectedStat]); const fetchLeaderboard = async (statName: string) => { setLoading(true); setError(null); try { const response = await api.get(`/api/leaderboard/${statName}`, { params: { limit: 100 } }); setLeaderboard(response.data.leaderboard || []); } catch (err) { setError(err instanceof Error ? err.message : 'An error occurred'); } finally { setLoading(false); } }; const formatStatValue = (value: number, statKey: string): string => { if (statKey === 'playtime') { const hours = Math.floor(value / 3600); const minutes = Math.floor((value % 3600) / 60); return `${hours}h ${minutes}m`; } return value.toLocaleString(); }; const getRankBadge = (rank: number): string => { if (rank === 1) return '๐Ÿฅ‡'; if (rank === 2) return '๐Ÿฅˆ'; if (rank === 3) return '๐Ÿฅ‰'; return `#${rank}`; }; const getRankClass = (rank: number): string => { if (rank === 1) return 'rank-gold'; if (rank === 2) return 'rank-silver'; if (rank === 3) return 'rank-bronze'; return ''; }; return (
{/* Game Header is now in GameLayout */} {/* Mobile Header Toggle */}

Select Statistic

{STAT_OPTIONS.map((stat) => ( ))}
setStatDropdownOpen(!statDropdownOpen)} > {selectedStat.icon}

{selectedStat.label}

{statDropdownOpen ? 'โ–ฒ' : 'โ–ผ'}
{/* Dropdown options */} {statDropdownOpen && (
{STAT_OPTIONS.filter(stat => stat.key !== selectedStat.key).map((stat) => ( ))}
)} {!loading && !error && leaderboard.length > ITEMS_PER_PAGE && (
{currentPage} / {Math.ceil(leaderboard.length / ITEMS_PER_PAGE)}
)}
{loading && (

Loading leaderboard...

)} {error && (

โŒ {error}

)} {!loading && !error && leaderboard.length === 0 && (

๐Ÿ“Š No data available yet

)} {!loading && !error && leaderboard.length > 0 && ( <>
Rank
Player
Level
Value
{leaderboard .slice((currentPage - 1) * ITEMS_PER_PAGE, currentPage * ITEMS_PER_PAGE) .map((entry, index) => { const rank = (currentPage - 1) * ITEMS_PER_PAGE + index + 1; return (
navigate(`/profile/${entry.player_id}`)} >
{getRankBadge(rank)}
{entry.name}
@{entry.username}
Lv {entry.level}
{formatStatValue(entry.value, selectedStat.key)}
); })}
{Math.ceil(leaderboard.length / ITEMS_PER_PAGE) > 1 && (
{currentPage} / {Math.ceil(leaderboard.length / ITEMS_PER_PAGE)}
)} )}
); }