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.
60 lines
1.6 KiB
JavaScript
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);
|