customer-riverside/web/modules/custom/riverside_pt/js/calendar.js
Philip Peterson b0eaca462f Add testimonials carousel, redesign calendar, fix trusted host
- rpt-testimonials: pixel-offset carousel with DOM-measured max scroll,
  cards overflow the 1200px safe area to the right; red debug border on container
- calendar: circle-per-day design replacing event bars; teal outline for
  available days, filled for selected; dateClick replaces moreLinkClick
- settings.php: normalize BASE_URL before parse_url to fix trusted host
  error when scheme is missing; always include localhost fallback patterns

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 01:37:13 -07:00

124 lines
4.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(function (drupalSettings) {
document.addEventListener('DOMContentLoaded', function () {
var el = document.getElementById('riverside-calendar');
if (!el) return;
requestAnimationFrame(function () {
var selectedDate = null;
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');
});
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'];
},
dateClick: function (arg) {
if (!arg.dayEl.classList.contains('has-availability')) return;
var dateStr = arg.dateStr;
var dayEvents = calendar.getEvents().filter(function (e) {
return e.startStr.startsWith(dateStr);
});
if (dayEvents.length === 0) return;
// 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;
// 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();
},
});
document.getElementById('riverside-booking-close').addEventListener('click', closePanel);
backdrop.addEventListener('click', closePanel);
document.addEventListener('keydown', function (e) {
if (e.key === 'Escape') closePanel();
});
calendar.render();
}); // end requestAnimationFrame
});
})(drupalSettings);