/** * Leaderboard Panel * Displays high scores with period filtering */ const Leaderboard = { _isLoading: false, _currentPeriod: 'all', _currentBoard: 'champions', // paid solo (and generic opt-in crypto match) | free | prestige PvP _profileId: null, _cryptoMatchResultsEnabled: false, updateConfig: function(config) { config = config || {}; this._profileId = config.operatedProductProfileId || null; this._cryptoMatchResultsEnabled = !!(config.modes && config.modes.match && config.modes.match.economies && config.modes.match.economies.crypto_race); if ($('#leaderboard-panel').length) this._updateTabs(); }, init: function() { $('#leaderboardButton').on('click', function() { Leaderboard.show(); }); // Listen for real-time leaderboard updates if (window.socket) { window.socket.on('leaderboard_update', function(data) { // Refresh if modal is visible if ($('#leaderboard-panel').is(':visible')) { Leaderboard._fetchAndRender(); } }); } }, show: function() { this._ensurePanel(); $('#leaderboard-panel').show(); this._fetchAndRender(); }, _ensurePanel: function() { if ($('#leaderboard-panel').length) return; var panel = $( '' ); $('body').append(panel); $('#close-leaderboard').on('click', function() { $('#leaderboard-panel').hide(); }); var self = this; $(document).on('click', '.lb-tab', function() { self._currentPeriod = $(this).data('period'); self._updateTabs(); self._fetchAndRender(); }); $(document).on('click', '.lb-board', function() { self._currentBoard = $(this).data('board'); self._updateTabs(); self._fetchAndRender(); }); this._updateTabs(); }, _updateTabs: function() { var current = this._currentPeriod; $('.lb-tab').each(function() { if ($(this).data('period') === current) { $(this).css({ background: '#92400e', color: '#fff', borderColor: '#f59e0b' }); } else { $(this).css({ background: '#1a1a2e', color: '#aaa', borderColor: '#555' }); } }); var board = this._currentBoard; $('.lb-board').each(function() { var selected = $(this).data('board') === board; $(this).attr('aria-pressed', selected ? 'true' : 'false'); if (selected) { $(this).css({ background: '#92400e', color: '#fff', borderColor: '#f59e0b' }); } else { $(this).css({ background: '#1a1a2e', color: '#aaa', borderColor: '#555' }); } }); var championsNote; if (this._profileId === 'such-play-wow-prestige') { championsNote = 'Credit-entry solo scores only; no prizes, payouts, cash-out, or crypto-match results. Never mixed with Free or Prestige.'; } else if (this._profileId === 'such-monerogue-stagenet') { championsNote = 'Direct-entry and credit-entry solo scores only; no crypto-match results. Never mixed with Free or Prestige.'; } else if (this._cryptoMatchResultsEnabled) { championsNote = 'Paid solo and explicitly enabled crypto-match results; never mixed with Free or Prestige.'; } else { championsNote = 'Paid solo scores plus any historical crypto-match results recorded while that mode was enabled; never mixed with Free or Prestige.'; } var boardMeta = { champions: { title: '🏅 Hall of Champions', note: championsNote }, prestige: { title: '✨ PvP Prestige', note: 'Credit-entry competitive PvP scores only; never mixed with Free or the Hall of Champions.' }, pleb: { title: '🪙 Free / Pleb Board', note: 'Free solo and free competitive results only; no paid entries or payouts.' } }[board] || {}; $('#leaderboard-title').text(boardMeta.title || 'Scores'); $('#leaderboard-board-note').text(boardMeta.note || ''); }, _fetchAndRender: function() { if (this._isLoading) return; this._isLoading = true; $('#leaderboard-content').html('
Loading...
'); var self = this; $.getJSON('/api/leaderboard?period=' + this._currentPeriod + '&board=' + this._currentBoard + '&limit=20') .done(function(data) { self._render(data.leaderboard || []); }) .fail(function() { $('#leaderboard-content').html('
Failed to load leaderboard
'); }) .always(function() { self._isLoading = false; }); }, _render: function(entries) { if (!entries.length) { $('#leaderboard-content').html('
No scores yet. Play a game to be first!
'); return; } var html = ''; html += ''; html += ''; html += ''; html += ''; html += ''; html += ''; html += ''; for (var i = 0; i < entries.length; i++) { var e = entries[i]; var rankColor = i === 0 ? '#fbbf24' : (i === 1 ? '#c0c0c0' : (i === 2 ? '#cd7f32' : '#888')); var rankIcon = i === 0 ? '🥇' : (i === 1 ? '🥈' : (i === 2 ? '🥉' : (i + 1))); var bgColor = i % 2 === 0 ? 'rgba(255,255,255,0.03)' : 'transparent'; html += ''; html += ''; html += ''; html += ''; html += ''; html += ''; html += ''; } html += '
#PlayerBestWinsGames
' + rankIcon + '' + Leaderboard._escapeHtml(e.name) + '' + (e.best_score || 0) + '' + (e.wins || 0) + '' + (e.games_played || 0) + '
'; $('#leaderboard-content').html(html); }, _escapeHtml: function(str) { // Delegate to the shared helper (single source of truth). Falls back to a local // implementation if the helper somehow isn't loaded. if (typeof window !== 'undefined' && typeof window.escapeHtml === 'function') { return window.escapeHtml(str); } if (!str) return ''; return String(str) .replace(/&/g, '&').replace(//g, '>') .replace(/"/g, '"').replace(/'/g, '''); } }; // Initialize when DOM is ready $(document).ready(function() { Leaderboard.init(); });