Files

100 lines
4.4 KiB
JavaScript

const PageHome = {
_el: null,
_refreshTimer: null,
init() {
this._el = document.getElementById('page-home');
},
async render() {
this._el.innerHTML = this._template();
this._startRefresh();
await this._refreshCards();
},
async _refreshCards() {
try {
const status = await API.getStatus();
this._updateCard('card-server', status.server_running ? Lang.t('running') : Lang.t('stopped'), status.server_running ? 'success' : 'danger');
this._updateCard('card-telemetry', status.telemetry_running ? Lang.t('listening') : Lang.t('notStarted'), status.telemetry_running ? 'success' : 'warning');
this._updateCard('card-game', status.selected_game_id || Lang.t('notSelected'), 'info');
this._updateCard('card-connections', Lang.t('connectionsCount').replace('%d', status.ws_clients), status.ws_clients > 0 ? 'success' : 'secondary');
this._updateCard('card-packets', Lang.t('packetsCount').replace('%d', status.packet_count), status.packet_count > 0 ? 'success' : 'secondary');
const lastTime = status.last_packet_time;
if (lastTime > 0) {
const ago = Math.round((Date.now() / 1000) - lastTime);
this._updateCard('card-last-packet', Lang.t('secondsAgo').replace('%d', ago), ago < 5 ? 'success' : 'warning');
} else {
this._updateCard('card-last-packet', Lang.t('noData'), 'secondary');
}
const td = status.latest_data;
if (td) {
this._updateCard('card-speed', `${(td.speed_kmh || 0).toFixed(1)} km/h`, 'primary');
this._updateCard('card-rpm', `${(td.rpm || 0).toFixed(0)} RPM`, 'primary');
this._updateCard('card-gear', Lang.t('gearLabel').replace('%s', td.gear || 'N'), 'primary');
}
} catch (e) {
console.error('Failed to refresh status:', e);
}
},
_updateCard(id, value, type) {
const el = document.getElementById(id);
if (!el) return;
const valEl = el.querySelector('.status-card-value');
if (valEl) valEl.textContent = value;
const badgeEl = el.querySelector('.badge');
if (badgeEl) {
badgeEl.className = `badge badge-${type}`;
}
},
_startRefresh() {
if (this._refreshTimer) clearInterval(this._refreshTimer);
this._refreshTimer = setInterval(() => this._refreshCards(), 2000);
},
cleanup() {
if (this._refreshTimer) {
clearInterval(this._refreshTimer);
this._refreshTimer = null;
}
},
_template() {
return `
<div class="animated">
<h2 style="font-size:24px;font-weight:700;margin-bottom:8px;">${Lang.t('systemOverview')}</h2>
<p style="color:var(--text-secondary);margin-bottom:24px;">${Lang.t('overviewDesc')}</p>
</div>
<div class="status-grid animated" style="animation-delay:0.1s">
${this._cardHtml('card-speed', Lang.t('liveSpeed'), '-- km/h', 'primary')}
${this._cardHtml('card-rpm', Lang.t('liveRpm'), '-- RPM', 'primary')}
${this._cardHtml('card-gear', Lang.t('liveGear'), '--', 'primary')}
</div>
<div class="status-grid animated" style="animation-delay:0.15s">
${this._cardHtml('card-server', Lang.t('serverStatus'), Lang.t('running'), 'success')}
${this._cardHtml('card-telemetry', Lang.t('telemetryStatus'), Lang.t('notStarted'), 'warning')}
${this._cardHtml('card-connections', Lang.t('wsConnections'), Lang.t('connectionsCount').replace('%d', 0), 'secondary')}
${this._cardHtml('card-packets', Lang.t('packetCount'), Lang.t('packetsCount').replace('%d', 0), 'secondary')}
${this._cardHtml('card-last-packet', Lang.t('lastPacket'), Lang.t('noData'), 'secondary')}
${this._cardHtml('card-game', Lang.t('currentGame'), Lang.t('notSelected'), 'info')}
</div>`;
},
_cardHtml(id, title, value, type) {
return `
<div class="glass-card status-card" id="${id}">
<div class="status-card-header">
<span class="status-card-title">${title}</span>
<span class="badge badge-${type}">●</span>
</div>
<div class="status-card-value">${value}</div>
</div>`;
}
};
window.PageHome = PageHome;