/** * Leaderboard component for Golf game. * Handles leaderboard display, metric switching, and player stats modal. */ class LeaderboardComponent { constructor() { this.currentMetric = 'wins'; this.cache = new Map(); this.cacheTimeout = 60000; // 1 minute cache this.elements = { screen: document.getElementById('leaderboard-screen'), backBtn: document.getElementById('leaderboard-back-btn'), openBtn: document.getElementById('leaderboard-btn'), tabs: document.getElementById('leaderboard-tabs'), content: document.getElementById('leaderboard-content'), statsModal: document.getElementById('player-stats-modal'), statsContent: document.getElementById('player-stats-content'), statsClose: document.getElementById('player-stats-close'), }; this.metricLabels = { wins: 'Total Wins', win_rate: 'Win Rate', avg_score: 'Avg Score', knockouts: 'Knockouts', streak: 'Best Streak', rating: 'Rating', }; this.metricFormats = { wins: (v) => v.toLocaleString(), win_rate: (v) => `${v.toFixed(1)}%`, avg_score: (v) => v.toFixed(1), knockouts: (v) => v.toLocaleString(), streak: (v) => v.toLocaleString(), rating: (v) => Math.round(v).toLocaleString(), }; this.init(); } init() { // Open leaderboard this.elements.openBtn?.addEventListener('click', () => this.show()); // Back button this.elements.backBtn?.addEventListener('click', () => this.hide()); // Tab switching this.elements.tabs?.addEventListener('click', (e) => { if (e.target.classList.contains('leaderboard-tab')) { this.switchMetric(e.target.dataset.metric); } }); // Close player stats modal this.elements.statsClose?.addEventListener('click', () => this.closePlayerStats()); this.elements.statsModal?.addEventListener('click', (e) => { if (e.target === this.elements.statsModal) { this.closePlayerStats(); } }); // Handle clicks on player names this.elements.content?.addEventListener('click', (e) => { const playerLink = e.target.closest('.player-link'); if (playerLink) { const userId = playerLink.dataset.userId; if (userId) { this.showPlayerStats(userId); } } }); } show() { // Hide other screens, show leaderboard document.querySelectorAll('.screen').forEach(s => s.classList.remove('active')); this.elements.screen.classList.add('active'); this.loadLeaderboard(this.currentMetric); } hide() { this.elements.screen.classList.remove('active'); document.getElementById('lobby-screen').classList.add('active'); } switchMetric(metric) { if (metric === this.currentMetric) return; this.currentMetric = metric; // Update tab styling this.elements.tabs.querySelectorAll('.leaderboard-tab').forEach(tab => { tab.classList.toggle('active', tab.dataset.metric === metric); }); this.loadLeaderboard(metric); } async loadLeaderboard(metric) { // Check cache const cacheKey = `leaderboard_${metric}`; const cached = this.cache.get(cacheKey); if (cached && Date.now() - cached.time < this.cacheTimeout) { this.renderLeaderboard(cached.data, metric); return; } // Show loading this.elements.content.innerHTML = '
Failed to load leaderboard
No players on the leaderboard yet.
Play 5+ games to appear here!
| # | Player | ${this.metricLabels[metric]} | Games |
|---|---|---|---|
| ${medal || entry.rank} | ${this.escapeHtml(entry.username)}${isMe ? ' (you)' : ''} | ${formatValue(entry.value)} | ${entry.games_played} |
Failed to load player stats
Ranked Player
' : 'Unranked (needs 5+ games)
'}