Files
KCal/public/js/kiosk.js
T
ort 66b8fc5d4d Add self-hosted kids calendar app
Express + SQLite (node:sqlite, no native build step) family calendar:
parent accounts with household invites, per-child calendars with
save/duplicate/print, a token-gated read-only kiosk view for tablets,
and polling to keep parent and kiosk views in sync. Defaults to port 3007.
2026-08-15 13:48:01 -04:00

60 lines
1.6 KiB
JavaScript

const token = window.location.pathname.split('/').filter(Boolean).pop();
const weekdayBoard = document.getElementById('weekdayBoard');
const weekendWrap = document.getElementById('weekendWrap');
async function apiGet(path) {
const res = await fetch(path, { credentials: 'omit' });
if (!res.ok) throw new Error('request failed');
return res.json();
}
async function apiPatch(path, body) {
const res = await fetch(path, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
if (!res.ok) throw new Error('request failed');
return res.json();
}
const handlers = {
onToggleDone: (taskId, done) => apiPatch(`/api/kiosk/${token}/tasks/${taskId}`, { done }).catch(() => {}),
};
function todayName() {
return new Date().toLocaleDateString('en-US', { weekday: 'long' });
}
function draw(calendar) {
document.getElementById('childName').textContent = calendar.childName || '';
document.getElementById('calTitle').textContent = calendar.title || '';
renderCalendar({
calendar,
editable: false,
weekdayBoard,
weekendWrap,
handlers,
todayName: todayName(),
});
}
async function poll() {
try {
const data = await apiGet(`/api/kiosk/${token}/calendar`);
if (!data.calendar) {
document.getElementById('emptyState').style.display = 'block';
document.getElementById('childName').textContent = data.child ? data.child.name : '';
return;
}
document.getElementById('emptyState').style.display = 'none';
draw(data.calendar);
} catch {
// transient network error — try again next tick
}
}
poll();
setInterval(poll, 4000);