From 05a4b9a6739d8a7029e592c1603adf05543f0683 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 21 Dec 2025 20:53:52 +0000 Subject: [PATCH] Refactor user stats display to use tables Co-authored-by: mathieumoran1 --- public/js/app_user-stat.js | 159 +++++++++++++++++++++++-------------- public/user-stat.html | 41 +++++++--- 2 files changed, 130 insertions(+), 70 deletions(-) diff --git a/public/js/app_user-stat.js b/public/js/app_user-stat.js index c4bbd0a..e290b8d 100644 --- a/public/js/app_user-stat.js +++ b/public/js/app_user-stat.js @@ -41,11 +41,15 @@ window.onload = async function () { } function renderWinners(winners) { - const winnersList = document.getElementById('winners-list'); - if (!winnersList) return; + const tbody = document.getElementById('winners-table-body'); + if (!tbody) return; const list = Array.isArray(winners) ? winners : []; if (!list.length) { - winnersList.innerHTML = '
Aucun gagnant défini.
'; + tbody.innerHTML = ` + + Aucun gagnant défini. + + `; return; } @@ -64,7 +68,7 @@ window.onload = async function () { }); const years = Array.from(byYear.keys()).map(Number).sort((a, b) => b - a); - winnersList.innerHTML = ''; + tbody.innerHTML = ''; years.forEach((year) => { const winnersForYear = byYear.get(String(year)) || []; @@ -77,35 +81,56 @@ window.onload = async function () { return String(a.name || '').localeCompare(String(b.name || ''), 'fr', { sensitivity: 'base' }); }); - const item = document.createElement('div'); - item.className = 'list-group-item'; - const tieLabel = sorted.length > 1 ? ' (égalité)' : ''; + const tr = document.createElement('tr'); - const winnersHtml = sorted - .map((w) => { - const pts = w.points === null || Number.isNaN(w.points) ? null : w.points; - const ptsLabel = pts === null ? '' : ` — ${pts} pts`; - return `
${w.name}${ptsLabel}
`; - }) - .join(''); + const tdYear = document.createElement('td'); + tdYear.className = 'fw-semibold'; + tdYear.textContent = String(year); + if (sorted.length > 1) { + const small = document.createElement('div'); + small.className = 'text-muted small'; + small.textContent = 'égalité'; + tdYear.appendChild(document.createElement('br')); + tdYear.appendChild(small); + } - item.innerHTML = ` -
-
${year}${tieLabel}
- ${sorted.length} -
-
${winnersHtml}
- `; - winnersList.appendChild(item); + const tdWinners = document.createElement('td'); + sorted.forEach((w, idx) => { + const row = document.createElement('div'); + if (idx > 0) row.classList.add('mt-1'); + + const name = document.createElement('span'); + name.className = 'fw-semibold'; + name.textContent = w?.name || '(utilisateur supprimé)'; + row.appendChild(name); + + const pts = w.points === null || Number.isNaN(w.points) ? null : w.points; + if (pts !== null) { + const ptsSpan = document.createElement('span'); + ptsSpan.className = 'text-muted'; + ptsSpan.textContent = ` — ${pts} pts`; + row.appendChild(ptsSpan); + } + + tdWinners.appendChild(row); + }); + + tr.appendChild(tdYear); + tr.appendChild(tdWinners); + tbody.appendChild(tr); }); } function renderCompletions(completions) { - const root = document.getElementById('completers-by-year'); - if (!root) return; + const tbody = document.getElementById('completers-table-body'); + if (!tbody) return; if (!completions || typeof completions !== 'object') { - root.innerHTML = '
Impossible de charger les finisseurs 100%.
'; + tbody.innerHTML = ` + + Impossible de charger les finisseurs 100%. + + `; return; } @@ -114,48 +139,62 @@ window.onload = async function () { const byYear = completions?.completersByYear && typeof completions.completersByYear === 'object' ? completions.completersByYear : {}; if (!years.length) { - root.innerHTML = '
Aucune année trouvée.
'; + tbody.innerHTML = ` + + Aucune année trouvée. + + `; return; } - // Build a simple accordion - const accordionId = 'completersAccordion'; - root.innerHTML = `
`; - const acc = root.querySelector('.accordion'); + const sortedYears = years + .map((y) => Number(y)) + .filter((y) => Number.isInteger(y)) + .sort((a, b) => b - a); - years.forEach((y, idx) => { + tbody.innerHTML = ''; + sortedYears.forEach((y) => { const yearStr = String(y); const total = Number(totals?.[yearStr] ?? 0); const completers = Array.isArray(byYear?.[yearStr]) ? byYear[yearStr] : []; const count = completers.length; - const collapseId = `completers-${yearStr}`; - const headingId = `heading-${yearStr}`; - const show = idx === 0 ? 'show' : ''; - const collapsed = idx === 0 ? '' : 'collapsed'; - const expanded = idx === 0 ? 'true' : 'false'; + const tr = document.createElement('tr'); - const bodyHtml = count - ? `` - : `
Aucun utilisateur à 100%.
`; + const tdYear = document.createElement('td'); + tdYear.className = 'fw-semibold'; + tdYear.textContent = yearStr; - const item = document.createElement('div'); - item.className = 'accordion-item'; - item.innerHTML = ` -

- -

-
-
- ${bodyHtml} -
-
- `; - acc.appendChild(item); + const tdCount = document.createElement('td'); + const badge = document.createElement('span'); + badge.className = 'badge bg-secondary'; + badge.textContent = String(count); + tdCount.appendChild(badge); + + const tdTotal = document.createElement('td'); + tdTotal.textContent = String(Number.isFinite(total) ? total : 0); + + const tdNames = document.createElement('td'); + if (!count) { + tdNames.className = 'text-muted'; + tdNames.textContent = '—'; + } else { + const wrap = document.createElement('div'); + wrap.className = 'd-flex flex-wrap gap-1'; + completers.forEach((u) => { + const name = document.createElement('span'); + name.className = 'badge bg-light text-dark border'; + name.textContent = u?.name || '(sans nom)'; + wrap.appendChild(name); + }); + tdNames.appendChild(wrap); + } + + tr.appendChild(tdYear); + tr.appendChild(tdCount); + tr.appendChild(tdTotal); + tr.appendChild(tdNames); + tbody.appendChild(tr); }); } @@ -241,8 +280,8 @@ window.onload = async function () { }); // Hide spinner and show table after loading - spinner.style.display = 'none'; - table.style.display = 'table'; + if (spinner) spinner.classList.add('d-none'); + if (table) table.classList.remove('d-none'); if (statsError) statsError.classList.add('d-none'); // Add event listener for user links @@ -275,8 +314,8 @@ window.onload = async function () { const spinner = document.getElementById('loading-spinner'); const table = document.querySelector('.user-table'); const statsError = document.getElementById('stats-error'); - if (spinner) spinner.style.display = 'none'; - if (table) table.style.display = 'none'; + if (spinner) spinner.classList.add('d-none'); + if (table) table.classList.add('d-none'); if (statsError) { statsError.textContent = "Impossible de charger le classement pour le moment."; statsError.classList.remove('d-none'); diff --git a/public/user-stat.html b/public/user-stat.html index d76b403..0de9db8 100644 --- a/public/user-stat.html +++ b/public/user-stat.html @@ -20,10 +20,6 @@ .user-table { margin-top: 20px; } - .ratio { - font-weight: bold; - margin-top: 10px; - } .navbar-toggler { border-color: white; /* Make the border white */ } @@ -100,7 +96,7 @@ - + @@ -117,9 +113,20 @@

Gagnants

-
Définis dans l’admin (optionnel).
-
-
Chargement…
+
+
Nom
+ + + + + + + + + + + +
AnnéeGagnant(s)
Chargement…
@@ -127,8 +134,22 @@

Utilisateurs ayant terminé 100% (par année)

Completion = 100% pour l’année (tous les films de l’année vus).
-
-
Chargement…
+
+ + + + + + + + + + + + + + +
AnnéeFinisseur(s)Total filmsNoms
Chargement…
-- 2.54.0