Let JS own the live status labels instead of sharing them with data-i18n

#chain-status-label and #draw-label carried a data-i18n attribute *and* were
written from live state by app.js, so a language switch had both mechanisms
fighting over them: applyStaticTranslations reset each to its static default
and the next poll put the real value back. On the draw label that was a
flicker. On the status bar it was a false statement — with the connection
down, the bar went back to claiming "connecting" until a further fetch failed,
up to a full poll interval later.

The attribute is gone from both. The status bar is now rendered from
remembered state (last payload, plus whether we're in the offline state)
rather than straight from the response that triggered it, so a language switch
repaints it correctly and immediately, with no fetch involved.

logout() also stops wiping the chosen language: localStorage.clear() took
plm_lang with it, dropping the user back to the browser-detected default on
the one screen where they'd have to go find the switcher again.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-26 21:55:37 +02:00
co-authored by Claude Opus 5
parent 28c1179e9b
commit d4e0974881
2 changed files with 39 additions and 4 deletions
+34 -2
View File
@@ -159,11 +159,36 @@ const CHAIN_STATUS_KEYS = {
paying_out: 'chain.status.paying_out',
};
// The bar is rendered from remembered state rather than straight from the
// response that triggered it, so a language switch can repaint it immediately
// instead of waiting for the next poll. That wait used to make it lie: with the
// connection down, switching language reset the label to "connecting" until a
// further fetch failed.
let lastChainData = null;
let chainOffline = false;
function updateChainStatusBar(data) {
lastChainData = data;
chainOffline = false;
renderChainStatusBar();
}
function renderChainStatusBar() {
const dot = document.getElementById('chain-status-dot');
const label = document.getElementById('chain-status-label');
const block = document.getElementById('chain-block');
if (chainOffline) {
dot.className = 'status-dot status-offline';
label.textContent = t('chain.connectionLost');
return; // block height deliberately left showing its last known value
}
if (lastChainData === null) {
label.textContent = t('chain.connecting');
return;
}
const data = lastChainData;
// The dot's color/pulse only distinguishes waiting/open/drawing (that's all
// the CSS defines) — closing and paying_out both pulse like drawing, they
// just get their own text label below.
@@ -189,8 +214,8 @@ const STALE_AFTER_FAILURES = 2;
let consecutiveFetchFailures = 0;
function showConnectionLost() {
document.getElementById('chain-status-dot').className = 'status-dot status-offline';
document.getElementById('chain-status-label').textContent = t('chain.connectionLost');
chainOffline = true;
renderChainStatusBar();
}
function noteFetchOutcome(ok) {
@@ -575,7 +600,12 @@ function resetToLoggedOutUI() {
}
function logout() {
// The chosen language is a device preference, not session state — clearing it
// on logout would drop the user back to the browser-detected default on the
// very screen where they'd have to find the switcher again.
const lang = localStorage.getItem(LANG_STORAGE_KEY);
localStorage.clear();
if (lang) localStorage.setItem(LANG_STORAGE_KEY, lang);
resetToLoggedOutUI();
}
@@ -774,6 +804,7 @@ function connectRoundEvents() {
// those are built from server data + t() rather than fixed markup.
function onLanguageChange() {
renderBetButton();
renderChainStatusBar(); // repaints from remembered state, without waiting for the next poll
if (token) {
refreshRound();
refreshMe();
@@ -787,5 +818,6 @@ function onLanguageChange() {
}
renderBetButton();
renderChainStatusBar();
connectRoundEvents();
initAuthState();
+5 -2
View File
@@ -59,7 +59,10 @@
<div class="chain-bar" id="chain-bar">
<span class="chain-status-pill">
<span class="status-dot" id="chain-status-dot"></span>
<span id="chain-status-label" data-i18n="chain.connecting">Connecting…</span>
<!-- No data-i18n on this one or on #draw-label below: both are written by
app.js from live state, and letting applyStaticTranslations() also own
them made a language switch flash (or, here, assert) a stale value. -->
<span id="chain-status-label">Connecting…</span>
</span>
<span class="chain-bar-right">
<span class="chain-block mono" id="chain-block"></span>
@@ -157,7 +160,7 @@
<div class="draw-state" id="draw-state">
<div class="draw-spinner"></div>
<div class="draw-label" id="draw-label" data-i18n="draw.defaultLabel">Estrazione del vincitore in corso</div>
<div class="draw-label" id="draw-label">Drawing the winner</div>
</div>
<div class="hidden" id="draw-result"></div>