From 8a9de3c1cb06c0fe514d2f2b822347d9ece1fbc8 Mon Sep 17 00:00:00 2001 From: Tomas Dvorak Date: Fri, 13 Jun 2025 15:07:46 +0200 Subject: [PATCH] test --- rezervace-aut.html | 404 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 374 insertions(+), 30 deletions(-) diff --git a/rezervace-aut.html b/rezervace-aut.html index 7134a62..c5de475 100644 --- a/rezervace-aut.html +++ b/rezervace-aut.html @@ -211,6 +211,103 @@ font-size: 0.875rem; } + /* Enhanced calendar event styles */ + .fc-event { + border: none !important; + border-radius: 6px !important; + padding: 4px 6px !important; + box-shadow: 0 2px 4px rgba(0,0,0,0.1) !important; + margin: 2px 0 !important; + background: white !important; + } + + .fc-event-title { + font-weight: 500 !important; + font-size: 0.9rem !important; + } + + .fc-event-time { + font-weight: 600 !important; + opacity: 0.8 !important; + } + + /* Vehicle-specific event colors */ + .event-vw-caddy { + border-left: 4px solid #1a73e8 !important; + background: #e6f3ff !important; + } + + .event-vw-golf { + border-left: 4px solid #28a745 !important; + background: #e6ffe6 !important; + } + + .event-skoda-fabia { + border-left: 4px solid #fd7e14 !important; + background: #fff3e6 !important; + } + + .event-bmw-218d { + border-left: 4px solid #6f42c1 !important; + background: #f3e6ff !important; + } + + .event-skoda-superb { + border-left: 4px solid #dc3545 !important; + background: #ffe6e6 !important; + } + + /* Reservation list styles */ + .reservations-list { + margin-top: 2rem; + background: white; + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0,0,0,0.05); + overflow: hidden; + } + + .reservations-list-header { + background: #f8fafc; + padding: 1rem; + border-bottom: 1px solid #e5e7eb; + } + + .reservations-list-body { + max-height: 400px; + overflow-y: auto; + } + + .reservation-item { + padding: 1rem; + border-bottom: 1px solid #e5e7eb; + display: flex; + align-items: center; + gap: 1rem; + } + + .reservation-item:last-child { + border-bottom: none; + } + + .reservation-vehicle-badge { + padding: 0.25rem 0.75rem; + border-radius: 9999px; + font-size: 0.875rem; + font-weight: 500; + } + + /* High traffic warning styles */ + .high-traffic-warning { + display: none; + background: #fff3e6; + border-left: 4px solid #fd7e14; + padding: 0.75rem 1rem; + margin-top: 0.5rem; + border-radius: 0.375rem; + font-size: 0.875rem; + color: #c05621; + } + /* Form container styles */ .form-container { max-width: 600px; @@ -452,6 +549,44 @@ .reservation-modal .close-button:hover { color: #333; } + + /* Availability and warning styles */ + .form-group button[type="submit"]:disabled { + opacity: 0.5; + cursor: not-allowed; + } + + #availabilityStatus, #highTrafficWarning { + display: flex; + align-items: center; + font-size: 0.875rem; + margin-top: 0.5rem; + padding: 0.5rem; + border-radius: 0.375rem; + transition: all 0.3s ease; + } + + #availabilityStatus i, #highTrafficWarning i { + margin-right: 0.5rem; + } + + #availabilityStatus.bg-green-50 { + background-color: #f0fdf4; + color: #166534; + border: 1px solid #bbf7d0; + } + + #availabilityStatus.bg-red-50 { + background-color: #fef2f2; + color: #991b1b; + border: 1px solid #fecaca; + } + + #highTrafficWarning { + background-color: #fff7ed; + color: #9a3412; + border: 1px solid #fed7aa; + } @@ -517,15 +652,24 @@ -
-
+
-
+ + +
+
+

Nadcházející rezervace

+
+
+ +
+
+
@@ -538,7 +682,7 @@ class="w-full p-2 border border-gray-300 rounded-md">
- +
@@ -552,6 +696,13 @@
+ + + +
@@ -695,16 +846,100 @@ const reservationForm = document.getElementById('reservationForm'); const statusMessage = document.getElementById('statusMessage'); const modal = document.getElementById('eventModal'); + const highTrafficWarning = document.getElementById('highTrafficWarning'); + const availabilityStatus = document.getElementById('availabilityStatus'); let currentEventId = null; - // Initialize FullCalendar - const calendarEl = document.getElementById('calendar'); calendar = new FullCalendar.Calendar(calendarEl, { + // Function to check availability and traffic + async function checkAvailabilityAndTraffic() { + const vehicle = document.getElementById('vehicle').value; + const startDate = document.getElementById('startDate').value; + const startTime = document.getElementById('startTime').value; + const endDate = document.getElementById('endDate').value; + const endTime = document.getElementById('endTime').value; + + if (!vehicle || !startDate || !startTime || !endDate || !endTime) { + return; + } + + try { + const response = await fetch(`/api/check-availability?vehicle=${encodeURIComponent(vehicle)}&startDate=${startDate}&startTime=${startTime}&endDate=${endDate}&endTime=${endTime}`); + const data = await response.json(); + + // Update availability status + availabilityStatus.classList.remove('hidden', 'bg-green-50', 'text-green-700', 'bg-red-50', 'text-red-700'); + + if (data.available) { + availabilityStatus.classList.add('bg-green-50', 'text-green-700'); + availabilityStatus.innerHTML = 'Vozidlo je v tomto čase k dispozici'; + } else { + availabilityStatus.classList.add('bg-red-50', 'text-red-700'); + availabilityStatus.innerHTML = 'Vozidlo je v tomto čase již rezervované'; + } + availabilityStatus.classList.remove('hidden'); + + // Check for high traffic + if (data.reservationCount >= 3) { + highTrafficWarning.querySelector('.warning-message').textContent = + `Toto vozidlo má v daný den již ${data.reservationCount} rezervací.`; + highTrafficWarning.classList.remove('hidden'); + } else { + highTrafficWarning.classList.add('hidden'); + } + + // Disable submit button if not available + const submitButton = reservationForm.querySelector('button[type="submit"]'); + submitButton.disabled = !data.available; + submitButton.classList.toggle('opacity-50', !data.available); + submitButton.classList.toggle('cursor-not-allowed', !data.available); + + return data.available; + } catch (error) { + console.error('Error checking availability:', error); + return false; + } + } + + // Add event listeners for form inputs + const formInputs = ['vehicle', 'startDate', 'startTime', 'endDate', 'endTime']; + formInputs.forEach(inputId => { + document.getElementById(inputId).addEventListener('change', checkAvailabilityAndTraffic); + }); + + // Modify form submission to check availability first + reservationForm.addEventListener('submit', async function(e) { + e.preventDefault(); + + const isAvailable = await checkAvailabilityAndTraffic(); + if (!isAvailable) { + return; + } + + // Rest of the form submission code + // ...existing code... + }); // Initialize calendar + const calendarEl = document.getElementById('calendar'); + function createEventContent(arg) { + return { + html: ` +
+
${arg.timeText}
+
${arg.event.extendedProps.driverName}
+
${arg.event.extendedProps.vehicle}
+
+ ` + }; + } + const calendarConfig = { initialView: 'timeGridWeek', headerToolbar: { left: 'prev,next today', center: 'title', right: 'dayGridMonth,timeGridWeek,timeGridDay' }, + validRange: { + start: new Date().toISOString().split('T')[0] + }, locale: 'cs', slotMinTime: '06:00:00', slotMaxTime: '22:00:00', @@ -716,41 +951,37 @@ eventTimeFormat: { hour12: false }, + eventClassNames: function(arg) { + return ['event-' + arg.event.extendedProps.vehicle.toLowerCase().replace(/\s+/g, '-')]; + }, + eventContent: { + html: function(arg) { + return ` +
+
${arg.timeText}
+
${arg.event.extendedProps.driverName}
+
${arg.event.extendedProps.vehicle}
+
+ `; + } + }, dateClick: function(info) { - // Store the timestamp of the last click const now = Date.now(); if (this.lastClick && (now - this.lastClick < 300)) { - // Double click detected showReservationForm(info.date); } this.lastClick = now; }, - eventContent: function(arg) { - return { - html: ` -
-
${arg.event.extendedProps.vehicle}
-
${arg.event.extendedProps.driverName}
- ${arg.event.extendedProps.purpose ? `
${arg.event.extendedProps.purpose}
` : ''} -
- ` - }; - }, eventClick: function(info) { showEventModal(info.event); - }, - eventConstraint: { - dows: [0,1,2,3,4,5,6] - }, - selectConstraint: { - startTime: '06:00', - endTime: '22:00', - dows: [0,1,2,3,4,5,6] } - }); + }; + calendar = new FullCalendar.Calendar(calendarEl, calendarConfig); calendar.render(); + // Rest of the JavaScript code + // ...existing code... // Reservation modal functions const reservationModal = document.getElementById('reservationModal'); const closeReservationModal = document.getElementById('closeReservationModal'); function showReservationForm(date) { @@ -789,6 +1020,111 @@ } } + // Function to check vehicle availability and high traffic + async function checkVehicleAvailability(vehicle, startDate, endDate) { + try { + const response = await fetch(`/api/check-availability?vehicle=${encodeURIComponent(vehicle)}&startDate=${startDate}&startTime=${startTime}&endDate=${endDate}&endTime=${endTime}`); + const data = await response.json(); + + // Check for high traffic (more than 3 reservations for the same vehicle on the same day) + if (data.reservationCount > 3) { + showHighTrafficWarning(vehicle); + } else { + hideHighTrafficWarning(); + } + + return data.available; + } catch (error) { + console.error('Error checking availability:', error); + return false; + } + } + + // Function to show high traffic warning + function showHighTrafficWarning(vehicle) { + const warningEl = document.querySelector('.high-traffic-warning'); + if (!warningEl) { + const warning = document.createElement('div'); + warning.className = 'high-traffic-warning'; + warning.innerHTML = ` +
+ + Upozornění: Vozidlo ${vehicle} má v tento den vysoký počet rezervací. +
+ `; + document.getElementById('vehicle').parentNode.appendChild(warning); + } + warningEl.style.display = 'block'; + } + + // Function to hide high traffic warning + function hideHighTrafficWarning() { + const warningEl = document.querySelector('.high-traffic-warning'); + if (warningEl) { + warningEl.style.display = 'none'; + } + } + + // Function to update reservations list + function updateReservationsList() { + const reservationsList = document.getElementById('reservationsList'); + const events = calendar.getEvents(); + + // Sort events by start date + events.sort((a, b) => a.start - b.start); + + // Filter future events + const futureEvents = events.filter(event => event.start >= new Date()); + + if (futureEvents.length === 0) { + reservationsList.innerHTML = '
Žádné nadcházející rezervace
'; + return; + } + + reservationsList.innerHTML = futureEvents.map(event => { + const vehicleClass = 'event-' + event.extendedProps.vehicle.toLowerCase().replace(/\s+/g, '-'); + return ` +
+
+ ${event.extendedProps.vehicle} +
+
+
${event.extendedProps.driverName}
+
+ ${formatDateTime(event.start)} - ${formatDateTime(event.end)} +
+
+
+ ${event.extendedProps.purpose || 'Bez účelu'} +
+
+ `; + }).join(''); + } + + // Update the eventContent function to add vehicle-specific styling + // (Already defined in calendarConfig above, so this duplicate is removed) + + // Call updateReservationsList when events change + calendar.on('eventAdd', updateReservationsList); + calendar.on('eventRemove', updateReservationsList); + calendar.on('eventChange', updateReservationsList); + + // Initial update of reservations list + updateReservationsList(); + + // Vehicle select change handler + document.getElementById('vehicle').addEventListener('change', async function() { + const startDate = document.getElementById('startDate').value; + const startTime = document.getElementById('startTime').value; + const endDate = document.getElementById('endDate').value; + const endTime = document.getElementById('endTime').value; + + if (startDate && startTime && endDate && endTime) { + await checkVehicleAvailability(this.value, startDate, endDate); + } + }); + // Check vehicle availability async function checkVehicleAvailability(vehicle, startDate, endDate) { try { @@ -1025,8 +1361,16 @@ reservationModal.style.display = 'block'; }); - // Rest of the JavaScript code - // ...existing code... + // Initialize time dropdowns when page loads + document.addEventListener('DOMContentLoaded', function() { + populateTimeDropdowns(); + + // Set default dates to today + const today = new Date(); + const dateStr = today.toISOString().split('T')[0]; + document.getElementById('startDate').value = dateStr; + document.getElementById('endDate').value = dateStr; + }); });