172 lines
6.2 KiB
JavaScript
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
|
||
|
};
|