import { state } from './state.js'; import { applyLocale } from './i18n.js'; import { api, loadGoals } from './api.js'; import { updateHeader } from './ui.js'; import { showLogin, showRegister, showResetPassword } from './auth.js'; import { openNew, openData } from './sheets.js'; import { render } from './render.js'; document.addEventListener('session-expired', () => showLogin()); document.getElementById('btnNew').onclick = openNew; document.getElementById('btnData').onclick = openData; document.querySelector('.hdr-logo').onclick = () => { loadGoals().then(g => { state.goals = g; render(); }).catch(() => {}); }; updateHeader(); const _qs = new URLSearchParams(window.location.search); const inviteToken = _qs.get('invite'); const resetSelector = _qs.get('reset_selector'); const resetToken = _qs.get('reset_token'); if (inviteToken || resetSelector) history.replaceState(null, '', location.pathname); if (resetSelector && resetToken) { applyLocale(null); render(); showResetPassword(resetSelector, resetToken); } else { api('GET', 'me') .then(r => { state.userName = r.name || ''; state.isAdmin = r.is_admin || false; applyLocale(r.locale); updateHeader(); return loadGoals(); }) .then(g => { state.goals = g; render(); }) .catch(() => { applyLocale(null); render(); if (inviteToken) showRegister(inviteToken); else showLogin(); }); } function scheduleMidnight() { const n = new Date(); const ms = new Date(n.getFullYear(), n.getMonth(), n.getDate() + 1, 0, 0, 5).getTime() - n.getTime(); setTimeout(() => { state.TODAY = new Date(); state.TODAY.setHours(0, 0, 0, 0); state.selDay = {}; state.collapsed = {}; updateHeader(); render(); scheduleMidnight(); }, ms); } scheduleMidnight(); document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'visible') { const n = new Date(); n.setHours(0, 0, 0, 0); if (n.getTime() !== state.TODAY.getTime()) { state.TODAY = n; state.selDay = {}; state.collapsed = {}; render(); scheduleMidnight(); } loadGoals().then(g => { state.goals = g; render(); }).catch(() => {}); } }); (function() { const swEl = document.getElementById('sw'); let swState = 0, start = 0, elapsed = 0, raf = null, wakeLock = null; function acquireWakeLock() { if (!('wakeLock' in navigator)) return; navigator.wakeLock.request('screen').then(s => { wakeLock = s; }).catch(() => {}); } function releaseWakeLock() { if (wakeLock) { wakeLock.release(); wakeLock = null; } } document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'visible' && swState === 1) acquireWakeLock(); }); function getMs() { return swState === 1 ? elapsed + (Date.now() - start) : elapsed; } function updateFillBtns() { const show = getMs() >= 1000; document.querySelectorAll('.btn-sw-fill').forEach(b => { b.style.display = show ? '' : 'none'; }); } function fmt(ms) { return (ms / 1000).toFixed(2) + 's'; } function tick() { swEl.textContent = fmt(Date.now() - start + elapsed); updateFillBtns(); raf = requestAnimationFrame(tick); } swEl.addEventListener('click', () => { if (swState === 0) { start = Date.now(); elapsed = 0; swEl.classList.add('running'); swState = 1; tick(); acquireWakeLock(); } else if (swState === 1) { cancelAnimationFrame(raf); elapsed += Date.now() - start; swEl.textContent = fmt(elapsed); swEl.classList.remove('running'); swState = 2; updateFillBtns(); releaseWakeLock(); } else { cancelAnimationFrame(raf); elapsed = 0; swEl.textContent = '0.00s'; swEl.classList.remove('running'); swState = 0; updateFillBtns(); releaseWakeLock(); } }); document.addEventListener('click', e => { if (!e.target.classList.contains('btn-sw-fill')) return; const inp = e.target.closest('.add-row, .qb-row').querySelector('.num-in'); if (inp) { inp.value = Math.floor(getMs() / 1000); inp.dispatchEvent(new Event('input')); } }); })();