`).join('');
}
// --- TAB NAVIGATION ---
function setActiveTab(tabId) {
currentTab = tabId;
tabButtons.forEach(btn => {
btn.classList.toggle('active', btn.dataset.tab === tabId);
});
tabPanes.forEach(pane => {
pane.style.display = pane.id === tabId ? 'block' : 'none';
});
updateNavButtons();
}
function updateNavButtons() {
const currentIndex = tabs.indexOf(currentTab);
prevTabBtn.disabled = currentIndex === 0;
nextTabBtn.disabled = currentIndex === tabs.length - 1;
}
// --- LOGIC & EVENT HANDLERS ---
bookingForm.addEventListener('submit', (e) => {
e.preventDefault();
const newReservation = {
id: Date.now(),
roomId: parseInt(bookingRoomSelect.value),
title: meetingTitleInput.value,
date: bookingDateInput.value,
startTime: startTimeInput.value,
endTime: endTimeInput.value,
};
// Validation
if (newReservation.startTime >= newReservation.endTime) {
showModal('Invalid Time', 'End time must be after start time.');
return;
}
// Conflict Check
const hasConflict = reservations.some(r =>
r.roomId === newReservation.roomId &&
r.date === newReservation.date &&
(
(newReservation.startTime >= r.startTime && newReservation.startTime < r.endTime) ||
(newReservation.endTime > r.startTime && newReservation.endTime <= r.endTime) ||
(newReservation.startTime <= r.startTime && newReservation.endTime >= r.endTime)
)
);
if (hasConflict) {
showModal('Booking Conflict', 'This room is already booked for the selected time slot.');
} else {
reservations.push(newReservation);
showModal('Success!', 'Your meeting room has been successfully booked.');
bookingForm.reset();
const today = new Date().toISOString().split('T')[0];
bookingDateInput.value = today;
updateAll();
setActiveTab('dashboard'); // Navigate to dashboard after booking
}
});
roomForm.addEventListener('submit', (e) => {
e.preventDefault();
const id = parseInt(editRoomIdInput.value);
const roomData = {
name: roomNameInput.value,
capacity: parseInt(roomCapacityInput.value),
amenities: roomAmenitiesInput.value.split(',').map(a => a.trim()).filter(Boolean)
};
if (id) { // Update
const index = rooms.findIndex(r => r.id === id);
if (index !== -1) {
rooms[index] = { ...rooms[index], ...roomData };
}
} else { // Add
roomData.id = rooms.length > 0 ? Math.max(...rooms.map(r => r.id)) + 1 : 1;
rooms.push(roomData);
}
resetRoomForm();
updateAll();
});
function resetRoomForm() {
roomForm.reset();
editRoomIdInput.value = '';
roomFormTitle.textContent = 'Add New Room';
roomSubmitBtn.textContent = 'Add Room';
roomCancelEditBtn.classList.add('hidden');
}
downloadPdfBtn.addEventListener('click', () => {
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
const selectedDate = scheduleDatePicker.value;
const formattedDate = new Date(selectedDate + 'T00:00:00').toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
doc.setFontSize(18);
doc.text('Meeting Room Schedule', 14, 22);
doc.setFontSize(11);
doc.setTextColor(100);
doc.text(`Date: ${formattedDate}`, 14, 30);
const dailyReservations = reservations.filter(r => r.date === selectedDate);
if (dailyReservations.length === 0) {
doc.text('No meetings scheduled for this day.', 14, 40);
} else {
const head = [['Time', 'Room', 'Meeting Title']];
const body = dailyReservations
.sort((a,b) => a.startTime.localeCompare(b.startTime))
.map(r => {
const room = rooms.find(rm => rm.id === r.roomId);
return [`${r.startTime} - ${r.endTime}`, room ? room.name : 'Unknown Room', r.title];
});
doc.autoTable({
head: head,
body: body,
startY: 40,
theme: 'striped',
headStyles: { fillColor: [59, 130, 246] }, // blue-500
});
}
doc.save(`schedule_${selectedDate}.pdf`);
});
// --- MODAL ---
function showModal(title, message) {
modalTitle.textContent = title;
modalMessage.textContent = message;
modal.classList.add('visible');
}
modalCloseBtn.addEventListener('click', () => modal.classList.remove('visible'));
modal.addEventListener('click', (e) => {
if (e.target === modal) {
modal.classList.remove('visible');
}
});
// --- GLOBAL API for inline event handlers ---
window.app = {
editRoom: (id) => {
const room = rooms.find(r => r.id === id);
if (room) {
editRoomIdInput.value = room.id;
roomNameInput.value = room.name;
roomCapacityInput.value = room.capacity;
roomAmenitiesInput.value = room.amenities.join(', ');
roomFormTitle.textContent = 'Edit Room';
roomSubmitBtn.textContent = 'Update Room';
roomCancelEditBtn.classList.remove('hidden');
roomNameInput.focus();
}
},
deleteRoom: (id) => {
const hasFutureReservations = reservations.some(r => r.roomId === id && new Date(r.date) >= new Date(new Date().toISOString().split('T')[0]));
if (hasFutureReservations) {
showModal('Action Denied', 'Cannot delete room with active or future reservations.');
return;
}
rooms = rooms.filter(r => r.id !== id);
updateAll();
}
};
// --- ATTACH EVENT LISTENERS ---
tabButtons.forEach(button => button.addEventListener('click', () => setActiveTab(button.dataset.tab)));
prevTabBtn.addEventListener('click', () => navigateTabs(-1));
nextTabBtn.addEventListener('click', () => navigateTabs(1));
scheduleDatePicker.addEventListener('change', renderSchedule);
roomCancelEditBtn.addEventListener('click', resetRoomForm);
function navigateTabs(direction) {
const currentIndex = tabs.indexOf(currentTab);
const newIndex = currentIndex + direction;
if (newIndex >= 0 && newIndex < tabs.length) {
setActiveTab(tabs[newIndex]);
}
}
// --- START THE APP ---
initialize();
});