const status = document.querySelector('#status'); const buttons = [...document.querySelectorAll('.group-button')]; const apiPrefix = document.body.dataset.apiPrefix; const url = new URL(window.location.href); const suppliedKey = url.searchParams.get('key'); if (suppliedKey) { sessionStorage.setItem('fasthue-api-key', suppliedKey); url.searchParams.delete('key'); history.replaceState({}, '', url); } const apiKey = sessionStorage.getItem('fasthue-api-key'); function apiFetch(path, options = {}) { return fetch(path, { ...options, headers: { ...options.headers, Authorization: `Bearer ${apiKey || ''}` }, }); } function showStatus(message, persistent = false) { status.textContent = message; status.classList.add('visible'); if (!persistent) window.setTimeout(() => status.classList.remove('visible'), 1800); } async function refresh() { try { const response = await apiFetch(`${apiPrefix}/groups`, { cache: 'no-store' }); const body = await response.json(); if (!response.ok) throw new Error(body.error || 'Could not check the bridge'); const states = new Map(body.groups.map(group => [group.id, group])); buttons.forEach(button => { const group = states.get(button.dataset.id); button.classList.toggle('is-on', group?.on === true); button.querySelector('small').textContent = group?.scene || ''; }); status.classList.remove('visible'); } catch (error) { showStatus(error.message, true); } } async function activateNextScene(button) { button.disabled = true; try { const response = await apiFetch(`${apiPrefix}/groups/${button.dataset.id}/next-scene`, { method: 'POST' }); const body = await response.json(); if (!response.ok) throw new Error(body.error || 'Could not control the bridge'); showStatus(`${button.querySelector('span').textContent}: ${body.scene}`); button.querySelector('small').textContent = body.scene; window.setTimeout(refresh, 350); } catch (error) { showStatus(error.message, true); } finally { button.disabled = false; } } async function turnOff(button) { button.disabled = true; try { const response = await apiFetch(`${apiPrefix}/groups/${button.dataset.id}/off`, { method: 'POST' }); const body = await response.json(); if (!response.ok) throw new Error(body.error || 'Could not turn off the lights'); button.classList.remove('is-on'); button.querySelector('small').textContent = 'Lights off'; showStatus(`${button.querySelector('span').textContent}: off`); window.setTimeout(refresh, 350); } catch (error) { showStatus(error.message, true); } finally { button.disabled = false; } } buttons.forEach(button => { let pressTimer; let longPressHandled = false; const clearPressTimer = () => window.clearTimeout(pressTimer); button.addEventListener('pointerdown', () => { longPressHandled = false; pressTimer = window.setTimeout(() => { longPressHandled = true; turnOff(button); }, 650); }); button.addEventListener('pointerup', clearPressTimer); button.addEventListener('pointercancel', clearPressTimer); button.addEventListener('pointerleave', clearPressTimer); button.addEventListener('click', event => { if (longPressHandled) { event.preventDefault(); longPressHandled = false; return; } activateNextScene(button); }); }); refresh(); window.setInterval(refresh, 15000);