(function () { "use strict"; var loadingDiv = document.getElementById("scoreboard-loading"); var recentSection = document.getElementById("recent-games-section"); var recentTbody = document.querySelector("#recent-games-table tbody"); var popularSection = document.getElementById("popular-section"); var popularRow = document.getElementById("popular-row"); var leaderboardsSection = document.getElementById("leaderboards-section"); var leaderboardsContainer = document.getElementById("leaderboards-container"); var emptyDiv = document.getElementById("scoreboard-empty"); function formatTime(seconds) { var mins = Math.floor(seconds / 60); var secs = Math.floor(seconds % 60); return mins + ":" + (secs < 10 ? "0" : "") + secs; } function formatDate(iso) { return new Date(iso).toLocaleDateString(); } function titleCase(str) { return str.charAt(0).toUpperCase() + str.slice(1); } function escapeHtml(str) { var div = document.createElement("div"); div.textContent = str; return div.innerHTML; } // Recent games from localStorage function getRecentGames() { try { return JSON.parse(localStorage.getItem("ws-recent-games") || "[]"); } catch (e) { return []; } } function renderRecentGames(games) { recentTbody.innerHTML = ""; games.forEach(function (g) { var tr = document.createElement("tr"); tr.innerHTML = "" + escapeHtml(titleCase(g.category)) + "" + "" + escapeHtml(g.player_name) + "" + "" + escapeHtml(g.time_display || formatTime(g.time_seconds)) + "" + "" + g.board_size + "x" + g.board_size + "" + "" + g.word_count + "" + "" + formatDate(g.completed_at) + ""; recentTbody.appendChild(tr); }); } function renderPopularCategories(categories) { popularRow.innerHTML = ""; var active = categories.filter(function (c) { return c.completed_games > 0; }); active.forEach(function (c) { var col = document.createElement("div"); col.className = "col-md-4 col-lg-3"; col.innerHTML = '
' + '
' + '
' + escapeHtml(titleCase(c.name)) + '
' + '

' + c.completed_games + ' games completed

' + ' Play' + '
' + '
'; popularRow.appendChild(col); }); } function renderLeaderboards(leaderboards) { leaderboardsContainer.innerHTML = ""; var names = Object.keys(leaderboards); names.sort(); names.forEach(function (catName) { var entries = leaderboards[catName]; var card = document.createElement("div"); card.className = "card mb-3"; var header = '
' + ' ' + escapeHtml(titleCase(catName)) + '
'; var rows = ""; entries.forEach(function (e, i) { rows += "" + "" + (i + 1) + "" + "" + escapeHtml(e.player_name) + "" + "" + formatTime(e.time_seconds) + "" + "" + e.board_size + "x" + e.board_size + "" + "" + e.word_count + "" + "" + formatDate(e.completed_at) + "" + ""; }); card.innerHTML = header + '
' + '
' + '' + '' + '' + '' + '' + '' + rows + '' + '
#PlayerTimeBoardWordsDate
'; leaderboardsContainer.appendChild(card); }); } async function loadScoreboard() { try { var resp = await fetch("/api/scoreboard"); if (!resp.ok) throw new Error("Failed to load"); var data = await resp.json(); loadingDiv.classList.add("d-none"); // Recent games from localStorage var recent = getRecentGames(); if (recent.length > 0) { renderRecentGames(recent); recentSection.classList.remove("d-none"); } // Popular categories var hasCompleted = data.popular_categories.some(function (c) { return c.completed_games > 0; }); if (hasCompleted) { renderPopularCategories(data.popular_categories); popularSection.classList.remove("d-none"); } // Leaderboards var hasLeaderboards = Object.keys(data.leaderboards).length > 0; if (hasLeaderboards) { renderLeaderboards(data.leaderboards); leaderboardsSection.classList.remove("d-none"); } // Empty state if (!hasCompleted && !hasLeaderboards && recent.length === 0) { emptyDiv.classList.remove("d-none"); } } catch (err) { loadingDiv.innerHTML = '

Failed to load scoreboard data.

'; } } loadScoreboard(); })();