fix: speedrun scores, dashboard icons, N+1 queries, typeof guards
This commit is contained in:
+33
-51
@@ -364,11 +364,11 @@ async function loadDashboard() {
|
||||
}
|
||||
|
||||
function renderDashboard({ stats, rank, elo, eloRank: rankLabel, online, recent, daily }) {
|
||||
const r = eloRankFor(elo || 1000);
|
||||
const myRank = eloRankFor(elo || 1000);
|
||||
setText('dash-hero-name', state.user.user);
|
||||
setText('dash-rank-label', rankLabel || r.label);
|
||||
setText('dash-rank-label', rankLabel || myRank.label);
|
||||
setText('dash-elo', elo || 1000);
|
||||
setText('dash-rank-icon', r.icon);
|
||||
setText('dash-rank-icon', myRank.icon);
|
||||
|
||||
setText('dash-total-score', stats.totalScore || 0);
|
||||
setText('dash-rank', rank ? '#' + rank.position : 'Unranked');
|
||||
@@ -389,14 +389,15 @@ function renderDashboard({ stats, rank, elo, eloRank: rankLabel, online, recent,
|
||||
if (!recent?.length) {
|
||||
tbody.innerHTML = '<tr><td colspan="4" class="muted">No sessions yet</td></tr>';
|
||||
} else {
|
||||
tbody.innerHTML = recent.map(r =>
|
||||
`<tr>
|
||||
<td><img class="stratagem-icon-sm" src="${esc(r.icon || '')}" alt="" ${r.icon ? '' : 'style="display:none"'}>${esc(r.stratagem)}</td>
|
||||
tbody.innerHTML = recent.map(r => {
|
||||
const icon = state.stratagems.find(s => s.name === r.stratagem)?.icon || '';
|
||||
return `<tr>
|
||||
<td><img class="stratagem-icon-sm" src="${esc(icon)}" alt="" ${icon ? '' : 'style="display:none"'}>${esc(r.stratagem)}</td>
|
||||
<td><span class="badge">${esc(r.mode || 'timed')}</span></td>
|
||||
<td>${r.score}</td>
|
||||
<td>${(r.time_ms / 1000).toFixed(2)}s</td>
|
||||
</tr>`
|
||||
).join('');
|
||||
</tr>`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
updateDashboardOnline(online);
|
||||
@@ -412,23 +413,18 @@ function renderDailySequencePreview(sequence) {
|
||||
function updateDashboardOnline(online) {
|
||||
const el = document.getElementById('dash-online');
|
||||
if (!el) return;
|
||||
const players = (online || []).filter(u => {
|
||||
const name = typeof u === 'object' ? u.name : u;
|
||||
return name !== state.user?.user;
|
||||
});
|
||||
const players = (online || []).filter(u => u.name !== state.user?.user);
|
||||
if (!players.length) {
|
||||
el.innerHTML = '<span class="muted">No other Helldivers online</span>';
|
||||
} else {
|
||||
el.innerHTML = players.map(u => {
|
||||
const name = typeof u === 'object' ? u.name : u;
|
||||
const elo = typeof u === 'object' ? u.elo : '';
|
||||
return `<div class="online-user">
|
||||
el.innerHTML = players.map(u =>
|
||||
`<div class="online-user">
|
||||
<span class="online-dot"></span>
|
||||
<span style="flex:1;font-family:var(--font-mono)">${esc(name)}</span>
|
||||
${elo ? `<span class="player-elo">${elo}</span>` : ''}
|
||||
<button class="btn btn-sm btn-accent" data-action="challenge" data-user="${esc(name)}">⚔ Challenge</button>
|
||||
</div>`;
|
||||
}).join('');
|
||||
<span style="flex:1;font-family:var(--font-mono)">${esc(u.name)}</span>
|
||||
${u.elo ? `<span class="player-elo">${u.elo}</span>` : ''}
|
||||
<button class="btn btn-sm btn-accent" data-action="challenge" data-user="${esc(u.name)}">⚔ Challenge</button>
|
||||
</div>`
|
||||
).join('');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -602,19 +598,13 @@ function nextStratagem() {
|
||||
if (!p.speedrunPool.length) {
|
||||
const totalMs = Date.now() - p.speedrunStart;
|
||||
clearInterval(p.timerHandle);
|
||||
api('POST', '/scores/practice', {
|
||||
stratagem: '__speedrun__',
|
||||
category: 'All',
|
||||
time_ms: totalMs,
|
||||
score: p.score,
|
||||
mode: 'speedrun',
|
||||
}).catch(() => {});
|
||||
showToast(`Speedrun complete! ${(totalMs / 1000).toFixed(2)}s`);
|
||||
openSessionSummary();
|
||||
return;
|
||||
}
|
||||
strat = p.speedrunPool[0];
|
||||
} else {
|
||||
// timed & endless: pick random from pool
|
||||
const pool = getPool();
|
||||
if (!pool.length) { showPracticeIdle(); return; }
|
||||
strat = pool[Math.floor(Math.random() * pool.length)];
|
||||
@@ -836,15 +826,13 @@ function handlePracticeInput(dir) {
|
||||
// Score popup
|
||||
showScorePopup('+' + pts);
|
||||
|
||||
if (mode !== 'speedrun') {
|
||||
api('POST', '/scores/practice', {
|
||||
stratagem: p.current.name,
|
||||
category: p.current.category,
|
||||
time_ms: elapsed,
|
||||
score: pts,
|
||||
mode: mode,
|
||||
}).catch(() => {});
|
||||
}
|
||||
api('POST', '/scores/practice', {
|
||||
stratagem: p.current.name,
|
||||
category: p.current.category,
|
||||
time_ms: elapsed,
|
||||
score: pts,
|
||||
mode: mode,
|
||||
}).catch(() => {});
|
||||
|
||||
if (mode === 'drill') {
|
||||
p.drillPool.shift();
|
||||
@@ -995,10 +983,7 @@ document.getElementById('btn-summary-restart')?.addEventListener('click', () =>
|
||||
|
||||
// ── Lobby ─────────────────────────────────────────────────────────────────────
|
||||
function updateLobbyView() {
|
||||
const others = state.lobby.online.filter(u => {
|
||||
const name = typeof u === 'object' ? u.name : u;
|
||||
return name !== state.user?.user;
|
||||
});
|
||||
const others = state.lobby.online.filter(u => u.name !== state.user?.user);
|
||||
const el = document.getElementById('lobby-players');
|
||||
if (!el) return;
|
||||
|
||||
@@ -1008,17 +993,14 @@ function updateLobbyView() {
|
||||
<p>No other Helldivers online.<br>Waiting for reinforcements...</p>
|
||||
</div>`;
|
||||
} else {
|
||||
el.innerHTML = others.map(u => {
|
||||
const name = typeof u === 'object' ? u.name : u;
|
||||
const elo = typeof u === 'object' ? u.elo : '';
|
||||
const rank = typeof u === 'object' ? u.rank : '';
|
||||
return `<div class="lobby-player">
|
||||
el.innerHTML = others.map(u =>
|
||||
`<div class="lobby-player">
|
||||
<span class="online-dot"></span>
|
||||
<span class="player-name">${esc(name)}</span>
|
||||
${elo ? `<span class="player-elo">${esc(rank)} · ${elo}</span>` : ''}
|
||||
<button class="btn btn-sm btn-accent" data-action="challenge" data-user="${esc(name)}">⚔ Challenge</button>
|
||||
</div>`;
|
||||
}).join('');
|
||||
<span class="player-name">${esc(u.name)}</span>
|
||||
${u.elo ? `<span class="player-elo">${esc(u.rank)} · ${u.elo}</span>` : ''}
|
||||
<button class="btn btn-sm btn-accent" data-action="challenge" data-user="${esc(u.name)}">⚔ Challenge</button>
|
||||
</div>`
|
||||
).join('');
|
||||
}
|
||||
|
||||
const challEl = document.getElementById('lobby-challenges');
|
||||
|
||||
Reference in New Issue
Block a user