2026-05-12 16:28:47 -08:00
|
|
|
|
(function (drupalSettings) {
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function () {
|
2026-06-03 00:37:13 -08:00
|
|
|
|
var el = document.getElementById('riverside-calendar');
|
2026-05-12 16:28:47 -08:00
|
|
|
|
if (!el) return;
|
|
|
|
|
|
|
2026-06-01 01:46:47 -08:00
|
|
|
|
requestAnimationFrame(function () {
|
2026-06-03 00:37:13 -08:00
|
|
|
|
var selectedDate = null;
|
2026-06-01 01:46:47 -08:00
|
|
|
|
|
2026-06-03 00:37:13 -08:00
|
|
|
|
var panel = document.getElementById('riverside-booking-panel');
|
|
|
|
|
|
var backdrop = document.getElementById('riverside-booking-backdrop');
|
|
|
|
|
|
var panelDate = document.getElementById('riverside-booking-date');
|
|
|
|
|
|
var panelSlots = document.getElementById('riverside-booking-slots');
|
|
|
|
|
|
|
|
|
|
|
|
function closePanel() {
|
|
|
|
|
|
panel.hidden = true;
|
|
|
|
|
|
backdrop.hidden = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function openPanel() {
|
|
|
|
|
|
backdrop.hidden = false;
|
|
|
|
|
|
panel.hidden = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var calendar = new FullCalendar.Calendar(el, {
|
|
|
|
|
|
initialView: 'dayGridMonth',
|
|
|
|
|
|
headerToolbar: { left: 'prev', center: 'title', right: 'next' },
|
|
|
|
|
|
titleFormat: { year: 'numeric', month: 'long' },
|
|
|
|
|
|
dayHeaderFormat: { weekday: 'narrow' },
|
|
|
|
|
|
validRange: function (now) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
start: new Date(now.getFullYear(), now.getMonth(), 1),
|
|
|
|
|
|
end: new Date(now.getFullYear(), now.getMonth() + 7, 1),
|
|
|
|
|
|
};
|
|
|
|
|
|
},
|
|
|
|
|
|
fixedWeekCount: false,
|
|
|
|
|
|
height: 'auto',
|
|
|
|
|
|
events: drupalSettings.riversidePt.eventsUrl,
|
|
|
|
|
|
eventDisplay: 'none',
|
|
|
|
|
|
dayMaxEvents: false,
|
|
|
|
|
|
|
|
|
|
|
|
datesSet: function () {
|
|
|
|
|
|
el.querySelectorAll('.fc-daygrid-day.is-selected').forEach(function (d) {
|
|
|
|
|
|
d.classList.remove('is-selected');
|
|
|
|
|
|
});
|
|
|
|
|
|
selectedDate = null;
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
eventsSet: function (events) {
|
|
|
|
|
|
el.querySelectorAll('.fc-daygrid-day.has-availability').forEach(function (d) {
|
|
|
|
|
|
d.classList.remove('has-availability');
|
2026-05-13 14:26:33 -08:00
|
|
|
|
});
|
2026-06-03 00:37:13 -08:00
|
|
|
|
events.forEach(function (event) {
|
|
|
|
|
|
var dateStr = event.startStr.substring(0, 10);
|
|
|
|
|
|
var dayEl = el.querySelector('.fc-daygrid-day[data-date="' + dateStr + '"]');
|
|
|
|
|
|
if (dayEl) dayEl.classList.add('has-availability');
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
dayCellClassNames: function (arg) {
|
|
|
|
|
|
var date = arg.date.toISOString().substring(0, 10);
|
|
|
|
|
|
if (drupalSettings.riversidePt.holidays[date]) return ['is-holiday'];
|
|
|
|
|
|
},
|
2026-05-12 17:33:59 -08:00
|
|
|
|
|
2026-06-03 00:37:13 -08:00
|
|
|
|
dateClick: function (arg) {
|
|
|
|
|
|
if (!arg.dayEl.classList.contains('has-availability')) return;
|
2026-05-12 17:33:59 -08:00
|
|
|
|
|
2026-06-03 00:37:13 -08:00
|
|
|
|
var dateStr = arg.dateStr;
|
|
|
|
|
|
var dayEvents = calendar.getEvents().filter(function (e) {
|
|
|
|
|
|
return e.startStr.startsWith(dateStr);
|
|
|
|
|
|
});
|
|
|
|
|
|
if (dayEvents.length === 0) return;
|
2026-05-12 17:33:59 -08:00
|
|
|
|
|
2026-06-03 00:37:13 -08:00
|
|
|
|
// Update selected highlight.
|
|
|
|
|
|
el.querySelectorAll('.fc-daygrid-day.is-selected').forEach(function (d) {
|
|
|
|
|
|
d.classList.remove('is-selected');
|
|
|
|
|
|
});
|
|
|
|
|
|
arg.dayEl.classList.add('is-selected');
|
|
|
|
|
|
selectedDate = dateStr;
|
2026-05-12 17:33:59 -08:00
|
|
|
|
|
2026-06-03 00:37:13 -08:00
|
|
|
|
// Build slot list.
|
|
|
|
|
|
panelDate.textContent = arg.date.toLocaleDateString(undefined, {
|
|
|
|
|
|
weekday: 'long', year: 'numeric', month: 'long', day: 'numeric',
|
|
|
|
|
|
});
|
|
|
|
|
|
panelSlots.innerHTML = '';
|
|
|
|
|
|
dayEvents.sort(function (a, b) { return a.start - b.start; }).forEach(function (event) {
|
|
|
|
|
|
var startLabel = event.start.toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit' });
|
|
|
|
|
|
var endLabel = event.end.toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit' });
|
|
|
|
|
|
var li = document.createElement('li');
|
|
|
|
|
|
var a = document.createElement('a');
|
|
|
|
|
|
a.href = '#';
|
|
|
|
|
|
a.textContent = startLabel + ' – ' + endLabel;
|
|
|
|
|
|
a.addEventListener('click', function (e) {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
fetch(drupalSettings.riversidePt.storeSlotUrl, {
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
headers: { 'Content-Type': 'application/json' },
|
|
|
|
|
|
body: JSON.stringify({ start: event.startStr, end: event.endStr }),
|
|
|
|
|
|
}).then(function (res) {
|
|
|
|
|
|
if (res.ok) {
|
|
|
|
|
|
window.location.href = drupalSettings.riversidePt.bookingUrl;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
a.textContent += ' (no longer available)';
|
|
|
|
|
|
a.style.pointerEvents = 'none';
|
|
|
|
|
|
a.style.opacity = '0.5';
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
li.appendChild(a);
|
|
|
|
|
|
panelSlots.appendChild(li);
|
|
|
|
|
|
});
|
|
|
|
|
|
openPanel();
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
2026-05-12 16:28:47 -08:00
|
|
|
|
|
2026-06-03 00:37:13 -08:00
|
|
|
|
document.getElementById('riverside-booking-close').addEventListener('click', closePanel);
|
|
|
|
|
|
backdrop.addEventListener('click', closePanel);
|
|
|
|
|
|
document.addEventListener('keydown', function (e) {
|
|
|
|
|
|
if (e.key === 'Escape') closePanel();
|
|
|
|
|
|
});
|
2026-06-01 01:46:47 -08:00
|
|
|
|
|
2026-06-03 00:37:13 -08:00
|
|
|
|
calendar.render();
|
2026-06-01 01:46:47 -08:00
|
|
|
|
}); // end requestAnimationFrame
|
2026-05-12 16:28:47 -08:00
|
|
|
|
});
|
|
|
|
|
|
})(drupalSettings);
|