"use client" import { useState, useEffect } from "react" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Avatar, AvatarFallback } from "@/components/ui/avatar" import { Badge } from "@/components/ui/badge" import { Trophy, Flame, Medal, Crown } from "lucide-react" import { getApiUrl } from "@/lib/api-config" import { motion } from "framer-motion" interface LeaderboardEntry { rank: number username: string xp: number level: number level_name: string streak: number } const getRankIcon = (rank: number) => { switch (rank) { case 1: return case 2: return case 3: return default: return #{rank} } } const getRankBg = (rank: number) => { switch (rank) { case 1: return "bg-gradient-to-r from-yellow-500/20 to-amber-500/10 border-yellow-500/30" case 2: return "bg-gradient-to-r from-slate-400/20 to-slate-500/10 border-slate-400/30" case 3: return "bg-gradient-to-r from-amber-600/20 to-amber-700/10 border-amber-600/30" default: return "bg-muted/30" } } export function XPLeaderboard() { const [leaderboard, setLeaderboard] = useState([]) const [loading, setLoading] = useState(true) useEffect(() => { fetchLeaderboard() }, []) const fetchLeaderboard = async () => { try { const res = await fetch(`${getApiUrl()}/gamification/leaderboard?limit=10`) if (res.ok) { const data = await res.json() setLeaderboard(data) } } catch (err) { console.error("Failed to fetch leaderboard", err) } finally { setLoading(false) } } if (loading) { return Loading leaderboard... } if (leaderboard.length === 0) { return ( XP Leaderboard No rankings yet. Be the first! ) } return ( XP Leaderboard {leaderboard.map((entry, index) => ( {getRankIcon(entry.rank)} {entry.username.slice(0, 2).toUpperCase()} {entry.username} Lv.{entry.level} {entry.level_name} {entry.xp.toLocaleString()} XP {entry.streak > 0 && ( {entry.streak} )} ))} ) }
No rankings yet. Be the first!
{entry.level_name}