class TemperatureCard extends HTMLElement { constructor() { super(); this.source = null; } connectedCallback() { this.innerHTML = `

Live temperature

Server-Sent Events
--°C
--°F
Disconnected
`; window.addEventListener('app:login', event => this.start(event.detail.token)); window.addEventListener('beforeunload', () => this.stop()); if (window.App && window.App.token()) this.start(window.App.token()); } disconnectedCallback() { this.stop(); } setState(text, connected) { this.querySelector('#state').textContent = text; this.querySelector('#dot').classList.toggle('on', !!connected); } start(token) { this.stop(); if (!token || !window.EventSource) { this.setState('Unavailable', false); return; } this.setState('Connecting', false); this.source = new EventSource('/api/temperature/events?token=' + encodeURIComponent(token)); this.source.addEventListener('open', () => this.setState('Connected', true)); this.source.addEventListener('temperature', event => { try { const json = JSON.parse(event.data); const connected = !!json.sensorConnected && json.temperatureC !== null && json.temperatureF !== null; this.querySelector('#temperatureC').textContent = connected ? Number(json.temperatureC).toFixed(2) : '--'; this.querySelector('#temperatureF').textContent = connected ? Number(json.temperatureF).toFixed(2) : '--'; this.setState(connected ? 'Connected' : 'Sensor unavailable', connected); } catch (error) { this.setState('Invalid event', false); } }); this.source.addEventListener('error', () => this.setState('Reconnecting', false)); } stop() { if (this.source) this.source.close(); this.source = null; } } customElements.define('temperature-card', TemperatureCard);