Show round timer, players and jackpot in the dashboard

A card above the section menu polls GET /rounds/current every 15s and
ticks a mm:ss countdown to closes_at every second locally, showing
status (aperto/in chiusura/estrazione/pagamento), participant count
and jackpot in PLM. Refreshed immediately after placing a bet, and
timers are cleared on logout.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-21 10:57:39 +02:00
co-authored by Claude Sonnet 5
parent 7f2d0bcec6
commit 63bc1d911b
+58
View File
@@ -198,6 +198,23 @@
</div> </div>
</div> </div>
<div class="card">
<div class="row-between">
<h2 id="round-title">Round —</h2>
<span class="mono" id="round-timer" style="font-size:1.1rem;font-weight:700">--:--</span>
</div>
<div class="row-between" style="margin-top:10px">
<div>
<div class="hint" style="margin-bottom:2px">Giocatori</div>
<span class="mono" id="round-players"></span>
</div>
<div style="text-align:right">
<div class="hint" style="margin-bottom:2px">Jackpot</div>
<span class="mono" id="round-jackpot"></span> <span class="balance-unit">PLM</span>
</div>
</div>
</div>
<nav class="menu" aria-label="Sezioni"> <nav class="menu" aria-label="Sezioni">
<button class="nav-item active" id="nav-deposit" onclick="switchPanel('deposit')"> <button class="nav-item active" id="nav-deposit" onclick="switchPanel('deposit')">
<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="7" width="20" height="14" rx="2"/><path d="M16 21V5a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v16"/></svg> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="7" width="20" height="14" rx="2"/><path d="M16 21V5a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v16"/></svg>
@@ -316,6 +333,39 @@ function switchPanel(name) {
} }
} }
let roundCloseAt = null;
let roundTimerInterval = null;
let roundPollInterval = null;
const ROUND_STATUS_LABELS = {
open: 'aperto',
closing: 'in chiusura',
drawing: 'estrazione in corso',
paying_out: 'pagamento in corso',
};
function updateRoundTimer() {
const el = document.getElementById('round-timer');
if (!roundCloseAt) { el.textContent = '--:--'; return; }
const totalSec = Math.max(0, Math.floor((roundCloseAt - new Date()) / 1000));
const mm = String(Math.floor(totalSec / 60)).padStart(2, '0');
const ss = String(totalSec % 60).padStart(2, '0');
el.textContent = mm + ':' + ss;
}
async function refreshRound() {
try {
const data = await call('GET', '/rounds/current');
document.getElementById('round-title').textContent = data.round_id
? 'Round #' + data.round_id + ' — ' + (ROUND_STATUS_LABELS[data.status] || data.status)
: 'Nessun round attivo';
document.getElementById('round-players').textContent = data.participant_count;
document.getElementById('round-jackpot').textContent = data.jackpot_sats / SATS_PER_PLM;
roundCloseAt = data.closes_at ? new Date(data.closes_at) : null;
updateRoundTimer();
} catch (e) {}
}
function showDashboard() { function showDashboard() {
document.getElementById('auth-section').classList.add('hidden'); document.getElementById('auth-section').classList.add('hidden');
document.getElementById('dashboard-section').classList.remove('hidden'); document.getElementById('dashboard-section').classList.remove('hidden');
@@ -323,6 +373,11 @@ function showDashboard() {
document.getElementById('dash-address').textContent = address; document.getElementById('dash-address').textContent = address;
document.getElementById('dash-qr').src = '/qr/' + encodeURIComponent(address); document.getElementById('dash-qr').src = '/qr/' + encodeURIComponent(address);
refreshMe(); refreshMe();
refreshRound();
clearInterval(roundTimerInterval);
clearInterval(roundPollInterval);
roundTimerInterval = setInterval(updateRoundTimer, 1000);
roundPollInterval = setInterval(refreshRound, 15000);
} }
function persistSession(data, u) { function persistSession(data, u) {
@@ -367,6 +422,8 @@ async function login() {
function logout() { function logout() {
localStorage.clear(); localStorage.clear();
token = username = address = null; token = username = address = null;
clearInterval(roundTimerInterval);
clearInterval(roundPollInterval);
document.getElementById('dashboard-section').classList.add('hidden'); document.getElementById('dashboard-section').classList.add('hidden');
document.getElementById('auth-section').classList.remove('hidden'); document.getElementById('auth-section').classList.remove('hidden');
} }
@@ -403,6 +460,7 @@ async function placeBet() {
} }
}); });
refreshMe(); refreshMe();
refreshRound();
} }
async function withdraw() { async function withdraw() {