/* global usScheduler */ (function () { 'use strict'; const app = document.getElementById('us-booking-app'); if (!app) return; const slotList = document.getElementById('us-slot-list'); const confirm = document.getElementById('us-booking-confirmation'); const errorBox = document.getElementById('us-booking-error'); const { restUrl, nonce } = usScheduler; function apiFetch(path, options = {}) { return fetch(restUrl + path, { ...options, headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': nonce, ...(options.headers || {}), }, }).then(async (res) => { const data = await res.json(); if (!res.ok) throw new Error(data.message || 'Request failed'); return data; }); } function showError(message) { errorBox.textContent = message; errorBox.style.display = 'block'; } function dayKey(dt) { return String(dt).slice(0, 10); } function timeOf(dt) { return String(dt).slice(11, 16); } function dayLabel(key) { const date = new Date(key + 'T00:00:00'); if (Number.isNaN(date.getTime())) return key; return date.toLocaleDateString(undefined, { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', }); } function groupByDay(slots) { const groups = new Map(); slots.forEach((slot) => { const key = dayKey(slot.start_dt); if (!groups.has(key)) groups.set(key, []); groups.get(key).push(slot); }); return [...groups.entries()].sort((a, b) => a[0].localeCompare(b[0])); } // Agenda-style calendar: available slots grouped by day. The richer booking // UX (offering selection, intake questions, policy acceptance) lands with the // booking-flow work. function renderSlots(slots) { if (!slots.length) { slotList.innerHTML = '

No available lesson slots at this time.

'; return; } slotList.innerHTML = groupByDay(slots).map(([key, daySlots]) => `

${escHtml(dayLabel(key))}

${daySlots.map((slot) => `
${escHtml(timeOf(slot.start_dt))}–${escHtml(timeOf(slot.end_dt))} (${escHtml(String(slot.duration_minutes))} min)
`).join('')}
`).join(''); slotList.querySelectorAll('.us-book-btn').forEach((btn) => { btn.addEventListener('click', () => bookSlot(Number(btn.dataset.slotId))); }); } function escHtml(str) { return String(str) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"'); } function bookSlot(slotId) { errorBox.style.display = 'none'; apiFetch('bookings', { method: 'POST', body: JSON.stringify({ slot_id: slotId }), }) .then(() => { slotList.style.display = 'none'; confirm.style.display = 'block'; }) .catch((err) => showError(err.message)); } apiFetch('availability') .then(renderSlots) .catch((err) => showError(err.message)); }());