Files
PPve/rezervace-aut.html
T
Tomas Dvorak 289eb93c26 etst
2025-06-13 14:51:56 +02:00

1033 lines
39 KiB
HTML
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.
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Poppe Potthoff - Rezervace služebních vozů</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" />
<link href='https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.css' rel='stylesheet' />
<script src='https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.js'></script>
<script src='https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/locales/cs.js'></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
'brand-blue': '#004990',
'brand-light-blue': '#0072b0',
'brand-gray': '#f0f2f5'
}
}
}
}
</script>
<style>
/* Existing styles */
.fc-event {
cursor: pointer;
border-radius: 6px;
border: none;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
transition: transform 0.2s, box-shadow 0.2s;
}
.fc-event:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
}
.fc-toolbar-title {
text-transform: capitalize;
font-weight: 600;
color: #2d3748;
}
/* Calendar navigation buttons */
.fc .fc-button-primary {
background-color: #004990;
border-color: #004990;
text-transform: uppercase;
font-size: 0.875rem;
font-weight: 500;
padding: 0.5rem 1rem;
transition: all 0.2s;
border-radius: 0.375rem;
}
.fc .fc-button-primary:not(:disabled):hover {
background-color: #003970;
border-color: #003970;
transform: translateY(-1px);
}
.fc .fc-button-primary:not(:disabled):active,
.fc .fc-button-primary:not(:disabled).fc-button-active {
background-color: #002950;
border-color: #002950;
}
.fc .fc-toolbar-title {
font-size: 1.25rem;
font-weight: 600;
}
.fc .fc-today-button {
text-transform: capitalize;
}
.fc .fc-button-primary {
background-color: #004990;
border-color: #004990;
text-transform: uppercase;
font-size: 0.875rem;
font-weight: 500;
padding: 0.5rem 1rem;
transition: all 0.2s;
}
.fc .fc-button-primary:hover {
background-color: #0072b0;
border-color: #0072b0;
transform: translateY(-1px);
}
.fc .fc-button-primary:not(:disabled).fc-button-active,
.fc .fc-button-primary:not(:disabled):active {
background-color: #0072b0;
border-color: #0072b0;
}
.fc-view-harness {
background: white;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0,0,0,0.05);
}
.fc-scrollgrid {
border: none !important;
}
.fc-col-header-cell {
background: #f8fafc;
padding: 1rem 0;
}
.fc-day-today {
background: #e8f4ff !important;
}
.fc-timegrid-slot {
height: 2rem !important;
}
.fc-timegrid-slot-label {
font-size: 0.75rem !important;
padding: 0 !important;
}
.reservation-card {
transition: all 0.3s ease;
}
.reservation-card:hover {
transform: translateY(-2px);
box-shadow: 0 8px 16px rgba(0,0,0,0.1);
}
/* Vehicle badges */
.vehicle-badge {
display: inline-flex;
align-items: center;
padding: 0.25rem 0.75rem;
border-radius: 9999px;
font-size: 0.875rem;
font-weight: 500;
margin-right: 0.5rem;
}
.vehicle-badge i {
margin-right: 0.5rem;
}
/* Vehicle-specific colors */
.vehicle-vw-caddy { background-color: #e6f3ff; color: #1a73e8; }
.vehicle-vw-golf { background-color: #e6ffe6; color: #28a745; }
.vehicle-skoda-fabia { background-color: #fff3e6; color: #fd7e14; }
.vehicle-bmw-218d { background-color: #f3e6ff; color: #6f42c1; }
.vehicle-skoda-superb { background-color: #ffe6e6; color: #dc3545; }
/* Calendar size adjustments */
.calendar-container {
max-width: 1000px;
margin: 0 auto;
padding: 1rem;
}
/* Responsive calendar styles */
@media (max-width: 768px) {
.fc .fc-toolbar {
flex-direction: column;
gap: 0.5rem;
}
.fc .fc-toolbar-title {
font-size: 1.2rem;
}
.fc-header-toolbar {
padding: 0.5rem !important;
}
.fc-view-harness {
height: 400px !important;
}
.fc .fc-button {
padding: 0.4rem 0.8rem;
font-size: 0.875rem;
}
}
/* Adjust calendar size for desktop */
.fc-view-harness {
height: 450px !important;
}
/* Improve event styling */
.fc-event {
padding: 2px 4px;
margin: 1px 0;
border-radius: 4px;
border: none !important;
background: #fff;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.fc-event-title {
font-weight: 500;
font-size: 0.875rem;
}
/* Form container styles */
.form-container {
max-width: 600px;
margin: 2rem auto;
padding: 2rem;
background: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
/* Form group spacing */
.form-group {
margin-bottom: 1.5rem;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
color: #374151;
}
/* Form field styles */
.form-group select {
appearance: none;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
background-position: right 0.5rem center;
background-repeat: no-repeat;
background-size: 1.5em 1.5em;
}
.form-group .select-wrapper {
position: relative;
}
.form-group .select-icon {
position: absolute;
left: 0.75rem;
top: 50%;
transform: translateY(-50%);
color: #6b7280;
pointer-events: none;
}
.form-group select {
width: 100%;
padding: 0.5rem 2rem 0.5rem 2.5rem;
border: 1px solid #d1d5db;
border-radius: 0.375rem;
background-color: white;
color: #111827;
}
.form-group select:focus {
outline: 2px solid transparent;
outline-offset: 2px;
border-color: #004990;
box-shadow: 0 0 0 1px #004990;
}
.form-group select option {
padding: 0.5rem;
}
/* Time input styling */
.time-input-wrapper {
position: relative;
}
.time-input-wrapper i {
position: absolute;
left: 0.75rem;
top: 50%;
transform: translateY(-50%);
color: #6b7280;
pointer-events: none;
}
.time-input-wrapper input[type="time"] {
width: 100%;
padding: 0.5rem 0.75rem 0.5rem 2.5rem;
border: 1px solid #d1d5db;
border-radius: 0.375rem;
appearance: none;
background-color: white;
color: #111827;
}
.time-input-wrapper input[type="time"]:focus {
outline: 2px solid transparent;
outline-offset: 2px;
border-color: #004990;
box-shadow: 0 0 0 1px #004990;
}
/* Hide default time picker icon in Edge/Chrome */
.time-input-wrapper input[type="time"]::-webkit-calendar-picker-indicator {
background: none;
padding-right: 0.5rem;
}
/* Style for Firefox */
.time-input-wrapper input[type="time"]::-moz-calendar-picker-indicator {
background: none;
}
/* Responsive form layout */
@media (max-width: 640px) {
.form-container {
padding: 1rem;
margin: 1rem;
}
.grid-cols-2 {
grid-template-columns: 1fr !important;
}
.form-group {
margin-bottom: 1rem;
}
}
/* Improve button responsiveness */
.btn {
width: 100%;
padding: 0.75rem;
border-radius: 0.5rem;
transition: all 0.2s;
}
@media (min-width: 640px) {
.btn {
width: auto;
}
}
/* Modal styles */
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1000;
padding: 1rem;
}
.modal-content {
background-color: white;
max-width: 500px;
margin: 2rem auto;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
position: relative;
padding: 1.5rem;
}
.modal-close {
position: absolute;
top: 0.75rem;
right: 0.75rem;
cursor: pointer;
font-size: 1.5rem;
color: #666;
}
.modal-header {
border-bottom: 1px solid #e5e7eb;
padding-bottom: 1rem;
margin-bottom: 1rem;
}
.modal-body {
color: #374151;
}
.info-grid {
display: grid;
grid-template-columns: auto 1fr;
gap: 0.75rem;
margin-top: 1rem;
}
.info-label {
font-weight: 500;
color: #6b7280;
}
.delete-btn {
background-color: #ef4444;
color: white;
padding: 0.5rem 1rem;
border-radius: 0.375rem;
margin-top: 1rem;
}
.delete-btn:hover {
background-color: #dc2626;
}
/* Reservation form modal styles */
.reservation-modal {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1000;
padding: 2rem;
overflow-y: auto;
}
.reservation-modal .form-container {
background: white;
max-width: 600px;
margin: 0 auto;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
position: relative;
padding: 2rem;
}
.reservation-modal .close-button {
position: absolute;
top: 1rem;
right: 1rem;
font-size: 1.5rem;
color: #666;
cursor: pointer;
background: none;
border: none;
padding: 0.5rem;
}
.reservation-modal .close-button:hover {
color: #333;
}
</style>
</head>
<body class="bg-brand-gray min-h-screen">
<!-- Nav bar copied from existing template -->
<nav class="bg-brand-blue text-white shadow-lg">
<div class="max-w-6xl mx-auto px-4 py-3 flex justify-between items-center">
<div class="flex items-center space-x-2">
<a href="http://webportal/index.html"><img src="http://pp-kunovice.cz/wp-content/uploads/2022/04/logo-retina-white.png" alt="Poppe Potthoff Logo" class="h-10"></a>
<div class="hidden md:block text-xl font-semibold">Poppe + Potthoff</div>
</div>
<!-- Mobile menu button -->
<div class="md:hidden">
<button id="mobile-menu-button" class="text-white focus:outline-none">
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
</button>
</div>
<!-- Desktop menu -->
<div class="hidden md:flex space-x-6">
<a href="http://webportal/index.html" class="hover:text-brand-light-blue">Rozcestník</a>
<a href="http://webportal/evidence-aut" class="hover:text-brand-light-blue">Evidence aut</a>
<a href="http://ppc-app/pwkweb2/" class="hover:text-brand-light-blue">Obědy</a>
<a href="http://osticket/" class="hover:text-brand-light-blue">OSticket</a>
<a href="http://kanboard/" class="hover:text-brand-light-blue">Kanboard</a>
<a href="http://webportal:8080" class="hover:text-brand-light-blue">Kontakt</a>
</div>
</div>
<!-- Mobile menu -->
<div id="mobile-menu" class="hidden md:hidden px-2 pt-2 pb-3 space-y-1">
<a href="webportal/index.html" class="block px-3 py-2 rounded-md text-base font-medium hover:text-brand-light-blue">Rozcestník</a>
<a href="webportal/evidence-aut" class="block px-3 py-2 rounded-md text-base font-medium hover:text-brand-light-blue">Evidence aut</a>
<a href="http://ppc-app/pwkweb2/" class="block px-3 py-2 rounded-md text-base font-medium hover:text-brand-light-blue">Obědy</a>
<a href="http://osticket/" class="block px-3 py-2 rounded-md text-base font-medium hover:text-brand-light-blue">OSticket</a>
<a href="http://kanboard/" class="block px-3 py-2 rounded-md text-base font-medium hover:text-brand-light-blue">Kanboard</a>
<a href="http://webportal:8080" class="block px-3 py-2 rounded-md text-base font-medium hover:text-brand-light-blue">Kontakt</a>
</div>
</nav>
<!-- Page Header -->
<div class="bg-gradient-to-r from-brand-blue to-brand-light-blue text-white py-6 mb-8">
<div class="max-w-6xl mx-auto px-4">
<h1 class="text-3xl font-bold">Poppe + Potthoff Rezervace služebních vozů</h1>
<p class="text-gray-100 mt-2">Systém pro rezervaci služebních vozidel</p>
</div>
</div>
<!-- Main Content -->
<div class="container mx-auto px-4 py-8">
<div class="calendar-container">
<div class="bg-blue-50 border-l-4 border-brand-blue p-4 mb-4 rounded-r-lg shadow-sm">
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-info-circle text-brand-blue"></i>
</div>
<div class="ml-3">
<p class="text-sm text-gray-700">
Pro rychlé vytvoření rezervace dvakrát klikněte na požadovaný čas/den v kalendáři.
</p>
</div>
</div>
</div>
<div id='calendar'></div>
<div class="flex justify-center mt-6">
<button id="newReservationBtn"
class="bg-brand-blue hover:bg-brand-light-blue text-white font-bold py-3 px-6 rounded-lg shadow-lg transition-all duration-200 transform hover:scale-105 flex items-center gap-2">
<i class="fas fa-plus-circle"></i>
Vytvořit novou rezervaci
</button>
</div>
</div> <!-- Reservation Form Modal -->
<div id="reservationModal" class="reservation-modal">
<div class="form-container">
<button type="button" class="close-button" id="closeReservationModal">&times;</button>
<h2 class="text-2xl font-bold mb-6 text-gray-800">Nová rezervace</h2>
<form id="reservationForm" class="space-y-6">
<!-- Driver Name -->
<div class="form-group">
<label for="driverName">Jméno řidiče</label>
<input type="text" id="driverName" name="driverName" required
class="w-full p-2 border border-gray-300 rounded-md">
</div>
<!-- Vehicle Selection -->
<div class="form-group">
<label for="vehicle">Vozidlo</label>
<div class="select-wrapper">
<i class="fas fa-car select-icon"></i>
<select id="vehicle" name="vehicle" required>
<option value="" disabled selected>Vyberte vozidlo...</option>
<option value="VW Caddy">VW Caddy</option>
<option value="VW Golf">VW Golf</option>
<option value="Škoda Fabia">Škoda Fabia</option>
<option value="BMW 218d">BMW 218d</option>
<option value="Škoda Superb">Škoda Superb</option>
</select>
</div>
</div>
<!-- Date and Time Selection -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- Start Date and Time -->
<div class="form-group">
<label for="startDate">Datum začátku</label>
<input type="date" id="startDate" name="startDate" required class="w-full p-2 border border-gray-300 rounded-lg">
</div>
<div class="form-group">
<label for="startTime">Čas začátku</label>
<div class="time-input-wrapper">
<i class="fas fa-clock"></i>
<input type="time" id="startTime" name="startTime" required min="06:00" max="22:00">
</div>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- End Date and Time -->
<div class="form-group">
<label for="endDate">Datum konce</label>
<input type="date" id="endDate" name="endDate" required class="w-full p-2 border border-gray-300 rounded-lg">
</div>
<div class="form-group">
<label for="endTime">Čas konce</label>
<div class="time-input-wrapper">
<i class="fas fa-clock"></i>
<input type="time" id="endTime" name="endTime" required min="06:00" max="22:00">
</div>
</div>
</div>
<!-- Purpose -->
<div class="space-y-2">
<label for="purpose" class="block text-sm font-medium text-gray-700">Účel jízdy (nepovinné)</label>
<div class="relative">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<i class="fas fa-briefcase text-gray-400"></i>
</div>
<input type="text" id="purpose" name="purpose"
class="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-brand-light-blue focus:border-brand-light-blue">
</div>
</div>
<!-- Submit Button -->
<div class="flex flex-col sm:flex-row gap-4 justify-end">
<button type="button" id="cancelBtn" class="btn bg-gray-500 text-white hover:bg-gray-600">
Zrušit
</button>
<button type="submit" class="btn bg-brand-blue text-white hover:bg-brand-light-blue">
Rezervovat
</button>
</div>
</form>
<!-- Status message container -->
<div class="mt-4 p-4 rounded-md hidden" id="statusMessage">
<div class="flex items-center">
<i id="messageIcon" class="mr-2"></i>
<span id="messageText"></span>
</div>
</div>
</div>
</div>
<!-- Modal HTML -->
<div id="eventModal" class="modal">
<div class="modal-content">
<span class="modal-close">&times;</span>
<div class="modal-header">
<h3 class="text-xl font-semibold text-gray-900">Detail rezervace</h3>
</div>
<div class="modal-body">
<div class="info-grid">
<span class="info-label">Řidič:</span>
<span id="modalDriver"></span>
<span class="info-label">Vozidlo:</span>
<span id="modalVehicle"></span>
<span class="info-label">Začátek:</span>
<span id="modalStart"></span>
<span class="info-label">Konec:</span>
<span id="modalEnd"></span>
<span class="info-label">Účel:</span>
<span id="modalPurpose"></span>
</div>
<button id="deleteReservation" class="delete-btn hidden">
<i class="fas fa-trash mr-2"></i>Zrušit rezervaci
</button>
</div>
</div>
</div>
</div>
<!-- Footer copied from existing template -->
<footer class="bg-gray-800 text-gray-400 py-8 mt-12">
<div class="max-w-6xl mx-auto px-4">
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
<!-- Company Info -->
<div>
<h3 class="text-white text-lg font-semibold mb-4">Poppe + Potthoff CZ</h3>
<p class="mb-2">IČO: 26902214</p>
<p class="mb-2">DIČ: CZ26902214</p>
<p class="mb-2">Schránka: gfrk5qy</p>
<p>Na Záhonech 1086, 686 04 Kunovice</p>
</div>
<!-- Quick Links -->
<div>
<h3 class="text-white text-lg font-semibold mb-4">Rychlé odkazy</h3>
<ul class="space-y-2">
<li><a href="http://webportal/" class="hover:text-white">Rozcestník</a></li>
<li><a href="http://webportal/evidence-aut" class="hover:text-white">Evidence aut</a></li>
<li><a href="http://ppc-app/pwkweb2/" class="hover:text-white">Objednávka obědů</a></li>
<li><a href="http://osticket/" class="hover:text-white">Technická podpora</a></li>
<li><a href="http://webportal:8080" class="hover:text-white">Kontakty</a></li>
</ul>
</div>
<!-- Copyright -->
<div class="md:text-right">
<img src="http://pp-kunovice.cz/wp-content/uploads/2022/04/logo-retina-white.png" alt="Poppe Potthoff Logo" class="h-10 mb-4 inline-block">
<p class="text-sm"> 2025 Poppe + Potthoff CZ</p>
<p class="text-xs mt-2">Všechna práva vyhrazena</p>
</div>
</div>
<div class="border-t border-gray-700 mt-8 pt-6 text-center text-sm">
<p>Created by <a href="https://tdvorak.dev" class="text-blue-400 hover:text-blue-300">TDvorak</a></p>
</div>
</div>
</footer>
<script>
document.addEventListener('DOMContentLoaded', function() {
let calendar;
const reservationForm = document.getElementById('reservationForm');
const statusMessage = document.getElementById('statusMessage');
const modal = document.getElementById('eventModal');
let currentEventId = null;
// Initialize FullCalendar
const calendarEl = document.getElementById('calendar'); calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'timeGridWeek',
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay'
},
locale: 'cs',
slotMinTime: '06:00:00',
slotMaxTime: '22:00:00',
slotDuration: '01:00:00',
snapDuration: '01:00:00',
allDaySlot: false,
events: '/api/reservations',
eventDisplay: 'block',
eventTimeFormat: {
hour12: false
},
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: `
<div class="p-1">
<div class="font-semibold text-sm">${arg.event.extendedProps.vehicle}</div>
<div class="text-xs">${arg.event.extendedProps.driverName}</div>
${arg.event.extendedProps.purpose ? `<div class="text-xs text-gray-600">${arg.event.extendedProps.purpose}</div>` : ''}
</div>
`
};
},
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.render();
// Reservation modal functions
const reservationModal = document.getElementById('reservationModal');
const closeReservationModal = document.getElementById('closeReservationModal'); function showReservationForm(date) {
// Format the date for the form inputs using local timezone
const formattedDate = date.getFullYear() + '-' +
String(date.getMonth() + 1).padStart(2, '0') + '-' +
String(date.getDate()).padStart(2, '0');
const formattedTime = String(date.getHours()).padStart(2, '0') + ':' +
String(date.getMinutes()).padStart(2, '0');
// Set the form values
document.getElementById('startDate').value = formattedDate;
document.getElementById('startTime').value = formattedTime;
// Set end time to 1 hour after start time by default
const endDate = new Date(date);
endDate.setHours(endDate.getHours() + 1);
document.getElementById('endDate').value = formattedDate;
document.getElementById('endTime').value = endDate.toTimeString().substring(0, 5);
// Show the modal
reservationModal.style.display = 'block';
}
// Close modal when clicking the close button
closeReservationModal.onclick = function() {
reservationModal.style.display = 'none';
}
// Close modal when clicking outside
window.onclick = function(event) {
if (event.target == reservationModal) {
reservationModal.style.display = 'none';
} else if (event.target == modal) {
modal.style.display = 'none';
}
}
// Check vehicle availability
async function checkVehicleAvailability(vehicle, startDate, endDate) {
try {
// Format dates for API
const startDateTime = new Date(startDate);
const endDateTime = new Date(endDate);
const params = new URLSearchParams({
vehicle: vehicle,
startDate: startDateTime.toISOString().split('T')[0],
startTime: startDateTime.toTimeString().split(' ')[0].slice(0, 5),
endDate: endDateTime.toISOString().split('T')[0],
endTime: endDateTime.toTimeString().split(' ')[0].slice(0, 5)
});
const response = await fetch(`/api/check-availability?${params}`);
if (!response.ok) {
throw new Error('Failed to check availability');
}
const data = await response.json();
return data.available;
} catch (error) {
console.error('Error checking availability:', error);
throw new Error('Could not verify vehicle availability');
}
}
// Show status message function
function showMessage(text, type) {
const statusContainer = document.getElementById('statusMessage');
if (!statusContainer) {
console.error('Status message container not found');
return;
}
statusContainer.className = 'mt-4 p-4 rounded-md';
statusContainer.classList.remove('hidden');
switch (type) {
case 'success':
statusContainer.classList.add('bg-green-100', 'text-green-700');
break;
case 'error':
statusContainer.classList.add('bg-red-100', 'text-red-700');
break;
case 'info':
statusContainer.classList.add('bg-blue-100', 'text-blue-700');
break;
}
statusContainer.textContent = text;
// Auto hide after 5 seconds
setTimeout(() => {
statusContainer.classList.add('hidden');
}, 5000);
}
// Handle form submission
reservationForm.addEventListener('submit', async function(e) {
e.preventDefault();
const startDate = document.getElementById('startDate').value;
const startTime = document.getElementById('startTime').value;
const endDate = document.getElementById('endDate').value;
const endTime = document.getElementById('endTime').value;
// Create ISO datetime strings
const startDateTime = new Date(`${startDate}T${startTime}`);
const endDateTime = new Date(`${endDate}T${endTime}`);
// Validate dates
if (endDateTime <= startDateTime) {
showMessage('Konec musí být později než začátek', 'error');
return;
}
// Check vehicle availability
const vehicle = document.getElementById('vehicle').value;
const isAvailable = await checkVehicleAvailability(vehicle, startDateTime, endDateTime);
if (!isAvailable) {
showMessage('Vozidlo není v tomto čase dostupné', 'error');
return;
}
// Prepare reservation data
const reservationData = {
driverName: document.getElementById('driverName').value,
vehicle: vehicle,
startDate: startDate,
startTime: startTime,
endDate: endDate,
endTime: endTime,
purpose: document.getElementById('purpose').value
};
try {
const response = await fetch('/api/reservations', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(reservationData)
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message || 'Failed to create reservation');
}
showMessage('Rezervace byla úspěšně vytvořena', 'success');
reservationForm.reset();
calendar.refetchEvents();
} catch (error) {
console.error('Error:', error);
showMessage(error.message || 'Chyba při vytváření rezervace', 'error');
}
});
// Populate time dropdowns with full hours
function populateTimeDropdowns() {
const timeSelects = [document.getElementById('startTime'), document.getElementById('endTime')];
for (let hour = 6; hour <= 22; hour++) { // 6:00 to 22:00
const hourStr = hour.toString().padStart(2, '0');
const timeStr = `${hourStr}:00`;
const option = new Option(timeStr, timeStr);
timeSelects.forEach(select => {
select.appendChild(option.cloneNode(true));
});
}
}
// Event modal functions
function showEventModal(event) {
const startDate = new Date(event.start);
const endDate = new Date(event.end);
document.getElementById('modalDriver').textContent = event.extendedProps.driverName;
document.getElementById('modalVehicle').textContent = event.extendedProps.vehicle;
document.getElementById('modalStart').textContent = formatDateTime(startDate);
document.getElementById('modalEnd').textContent = formatDateTime(endDate);
document.getElementById('modalPurpose').textContent = event.extendedProps.purpose || '(není uvedeno)';
// Show delete button only for user's own reservations
// You might want to add user authentication here
const deleteBtn = document.getElementById('deleteReservation');
deleteBtn.classList.remove('hidden');
modal.style.display = 'block';
}
function formatDateTime(date) {
return date.toLocaleString('cs-CZ', {
day: 'numeric',
month: 'long',
year: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
}
// Close modal when clicking the close button or outside
document.querySelector('.modal-close').onclick = function() {
modal.style.display = 'none';
}
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = 'none';
}
}
// Delete reservation handler
document.getElementById('deleteReservation').onclick = async function() {
if (!currentEventId) return;
if (confirm('Opravdu chcete zrušit tuto rezervaci?')) {
try {
const response = await fetch(`/api/reservations/${currentEventId}`, {
method: 'DELETE'
});
if (!response.ok) throw new Error('Failed to delete reservation');
calendar.getEventById(currentEventId).remove();
modal.style.display = 'none';
showMessage('Rezervace byla úspěšně zrušena', 'success');
} catch (error) {
console.error('Error:', error);
showMessage('Nepodařilo se zrušit rezervaci', 'error');
}
}
}
// 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;
});
// New reservation button handler
document.getElementById('newReservationBtn').addEventListener('click', function() {
// Set default date and time to current time rounded to next hour
const now = new Date();
now.setMinutes(0);
now.setHours(now.getHours() + 1);
const endDate = new Date(now);
endDate.setHours(endDate.getHours() + 1);
// Format dates for the form
const formattedDate = now.getFullYear() + '-' +
String(now.getMonth() + 1).padStart(2, '0') + '-' +
String(now.getDate()).padStart(2, '0');
const formattedTime = String(now.getHours()).padStart(2, '0') + ':00';
const formattedEndTime = String(endDate.getHours()).padStart(2, '0') + ':00';
// Set the form values
document.getElementById('startDate').value = formattedDate;
document.getElementById('startTime').value = formattedTime;
document.getElementById('endDate').value = formattedDate;
document.getElementById('endTime').value = formattedEndTime;
// Show the modal
reservationModal.style.display = 'block';
});
// Rest of the JavaScript code
// ...existing code...
});
</script>
</body>
</html>