freesched/public/js/components/calendar.js

172 lines
6.2 KiB
JavaScript

// js/components/calendar.js
// Import time utilities
import { timeToMinutes, formatDate } from '../utils/time-utils.js';
import { fetchAvailability } from '../utils/api.js';
// Global variables for calendar
let currentAdminDate = new Date();
let currentAdminMonth = currentAdminDate.getMonth();
let currentAdminYear = currentAdminDate.getFullYear();
let selectedAdminDate = null;
const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
// Render the admin calendar with available dates highlighted
async function renderAdminCalendar(month, year) {
const adminCalendarDates = document.getElementById('adminCalendarDates');
const adminMonthYear = document.getElementById('adminMonthYear');
if (!adminCalendarDates || !adminMonthYear) {
console.error('Required calendar elements not found');
return;
}
// Clear existing calendar
adminCalendarDates.innerHTML = '';
adminMonthYear.textContent = `${months[month]} ${year}`;
// Get current UID and availability
const selectedUid = document.getElementById('uidSelect').value;
if (!selectedUid) {
// If no UID selected, just show empty calendar
return;
}
const firstDay = new Date(year, month, 1).getDay();
const daysInMonth = new Date(year, month + 1, 0).getDate();
const today = new Date();
const currentMinutes = today.getHours() * 60 + today.getMinutes();
const availability = await fetchAvailability();
// Start of today (midnight)
const startOfToday = new Date(today.getFullYear(), today.getMonth(), today.getDate());
// Create blank cells for days before the first day of the month
for (let i = 0; i < firstDay; i++) {
const blank = document.createElement('div');
blank.classList.add('date-item', 'p-2', 'rounded-pill', 'text-center', 'text-muted', 'empty-cell');
blank.style.cursor = 'default'; // Remove pointer cursor
blank.style.pointerEvents = 'none'; // Disable hover and click events
adminCalendarDates.appendChild(blank);
}
// Clear any existing selected date
const existingSelected = adminCalendarDates.querySelector('.selected');
if (existingSelected) {
existingSelected.classList.remove('selected');
}
// Populate the calendar with days
let todayElement = null;
for (let i = 1; i <= daysInMonth; i++) {
const day = document.createElement('div');
day.classList.add('date-item', 'p-2', 'rounded-pill', 'text-center');
day.textContent = i;
const date = new Date(year, month, i);
const dateStr = formatDate(date);
// Check if date is in the past
const isPastDate = date < startOfToday;
const isToday = date.toDateString() === today.toDateString();
if (isToday) {
day.classList.add('current');
todayElement = day;
}
// Check if the date has available time slots
let hasAvailableTimes = false;
if (availability[dateStr]) {
let times = [];
if (typeof availability[dateStr] === 'string') {
times = availability[dateStr].split(',').map(t => t.trim());
} else if (Array.isArray(availability[dateStr])) {
times = availability[dateStr].map(t => t.trim());
}
// For today, filter out past times
if (isToday) {
times = times.filter(time => timeToMinutes(time) > currentMinutes);
}
// Only mark as available if there are valid times
hasAvailableTimes = times.length > 0;
}
// Only add 'available' class if the date is not in the past AND has available times
if (hasAvailableTimes && !isPastDate) {
day.classList.add('available');
}
if (isPastDate) {
day.classList.add('disabled');
} else {
day.addEventListener('click', () => selectAdminDate(date, firstDay));
}
adminCalendarDates.appendChild(day);
}
// If a date was previously selected, re-select it
if (selectedAdminDate &&
selectedAdminDate.getMonth() === month &&
selectedAdminDate.getFullYear() === year) {
selectAdminDate(selectedAdminDate, firstDay);
}
}
// Handle admin date selection
async function selectAdminDate(date, firstDay) {
// Check if the date is in the past
const today = new Date();
const startOfToday = new Date(today.getFullYear(), today.getMonth(), today.getDate());
if (date < startOfToday) {
console.warn('Attempted to select a past date');
return;
}
// Update selected date
selectedAdminDate = date;
// Get the date string for the selected date
const dateStr = formatDate(date);
// Trigger the updateTimeSlots function in admin.js
const event = new CustomEvent('dateSelected', {
detail: { dateStr: dateStr }
});
document.dispatchEvent(event);
// Update UI to show selected date
const dateItems = document.querySelectorAll('#adminCalendarDates .date-item');
dateItems.forEach(item => item.classList.remove('selected')); // Ensure only one date is selected
// Find the exact date item for the clicked date
const selectedDay = Array.from(dateItems).find(item => {
const dayText = item.textContent;
if (!dayText || isNaN(parseInt(dayText))) return false;
const itemDate = new Date(currentAdminYear, currentAdminMonth, parseInt(dayText));
return itemDate.toDateString() === date.toDateString();
});
if (selectedDay) selectedDay.classList.add('selected');
const selectedDateDisplay = document.getElementById('selectedDateDisplay');
if (selectedDateDisplay) {
selectedDateDisplay.textContent = '';
}
// Show the availability section
const availabilitySection = document.getElementById('availabilitySection');
if (availabilitySection) {
availabilitySection.classList.remove('d-none');
}
}
// Export functions for use in other files
export {
renderAdminCalendar,
selectAdminDate,
currentAdminMonth,
currentAdminYear,
selectedAdminDate,
months
};