Files
PPve/rezervace-aut.html
T
Tomas Dvorak 6cc7f2865c g
2025-06-11 14:54:57 +02:00

560 lines
22 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>
.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;
}
.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: 3rem !important;
}
.fc-timegrid-slot-label {
font-size: 0.875rem;
color: #64748b;
}
.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; }
/* Responsive calendar styles */
@media (max-width: 768px) {
.fc .fc-toolbar {
flex-direction: column;
gap: 1rem;
}
.fc .fc-toolbar-title {
font-size: 1.2rem;
}
.fc-header-toolbar {
padding: 0.5rem !important;
}
.fc-view-harness {
height: 500px !important; /* Smaller height on mobile */
}
.fc .fc-button {
padding: 0.4rem 0.8rem;
font-size: 0.875rem;
}
}
/* Adjust calendar size for desktop */
.calendar-container {
max-width: 900px;
margin: 0 auto;
padding: 1rem;
}
.fc-view-harness {
height: 600px !important; /* Default height for desktop */
}
/* 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;
}
/* 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;
}
}
</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 id='calendar'></div>
</div>
<!-- Reservation Form -->
<div class="form-container">
<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>
<select id="vehicle" name="vehicle" required
class="w-full p-2 border border-gray-300 rounded-md">
<option value="">Vyberte vozidlo...</option>
<option value="VW Caddy">VW Caddy - 4Z1 8241</option>
<option value="VW Golf">VW Golf - 5Z5 8694</option>
<option value="Škoda Fabia">Škoda Fabia - 1Z3 5789</option>
<option value="BMW 218d">BMW 218d - 6Z5 4739</option>
<option value="Škoda Superb">Škoda Superb - 2BY 2398</option>
</select>
</div>
<!-- Date and Time Selection -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="form-group">
<label for="startDateTime">Začátek</label>
<input type="datetime-local" id="startDateTime" name="startDateTime" required
class="w-full p-2 border border-gray-300 rounded-md">
</div>
<div class="form-group">
<label for="endDateTime">Konec</label>
<input type="datetime-local" id="endDateTime" name="endDateTime" required
class="w-full p-2 border border-gray-300 rounded-md">
</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>
</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');
// 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',
allDaySlot: false,
slotDuration: '00:30:00',
businessHours: {
daysOfWeek: [1, 2, 3, 4, 5],
startTime: '06:00',
endTime: '22:00',
},
events: '/api/reservations',
eventClick: function(info) {
alert(`
Řidič: ${info.event.title}
Vozidlo: ${info.event.extendedProps.vehicle}
Účel: ${info.event.extendedProps.purpose}
Od: ${info.event.start.toLocaleString()}
Do: ${info.event.end.toLocaleString()}
`);
}
});
calendar.render();
// Form submission
reservationForm.addEventListener('submit', async function(e) {
e.preventDefault();
// Validate dates
const startDate = new Date(document.getElementById('startDateTime').value);
const endDate = new Date(document.getElementById('endDateTime').value);
if (endDate <= startDate) {
showStatus('Čas ukončení musí být později než čas začátku', 'error');
return;
}
// Check vehicle availability
const vehicle = document.getElementById('vehicle').value;
const isAvailable = await checkVehicleAvailability(vehicle, startDate, endDate);
if (!isAvailable) {
showStatus('Vozidlo není v tomto čase dostupné', 'error');
return;
}
// Prepare reservation data
const reservationData = {
driverName: document.getElementById('driverName').value,
vehicle: vehicle,
startDateTime: startDate.toISOString(),
endDateTime: endDate.toISOString(),
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) {
throw new Error('Chyba při vytváření rezervace');
}
showStatus('Rezervace byla úspěšně vytvořena', 'success');
calendar.refetchEvents();
reservationForm.reset();
} catch (error) {
showStatus(error.message, 'error');
}
});
async function checkVehicleAvailability(vehicle, startDate, endDate) {
try {
const response = await fetch(`/api/check-availability?vehicle=${encodeURIComponent(vehicle)}&start=${startDate.toISOString()}&end=${endDate.toISOString()}`);
const data = await response.json();
return data.available;
} catch (error) {
console.error('Error checking availability:', error);
return false;
}
}
function showStatus(message, type) {
statusMessage.textContent = message;
statusMessage.className = 'mt-4 p-4 rounded-md';
statusMessage.classList.remove('hidden');
if (type === 'success') {
statusMessage.classList.add('bg-green-100', 'text-green-700');
} else {
statusMessage.classList.add('bg-red-100', 'text-red-700');
}
setTimeout(() => {
statusMessage.classList.add('hidden');
}, 5000);
}
});
function showMessage(text, type) {
const message = document.getElementById('message');
const messageText = document.getElementById('messageText');
const messageIcon = document.getElementById('messageIcon');
if (!message || !messageText || !messageIcon) {
console.error('Message elements not found');
return;
}
message.classList.remove('hidden', 'bg-green-50', 'bg-red-50', 'bg-blue-50', 'text-green-800', 'text-red-800', 'text-blue-800');
messageText.textContent = text;
switch(type) {
case 'success':
message.classList.add('bg-green-50', 'text-green-800');
messageIcon.className = 'fas fa-check-circle text-green-600 mr-2';
break;
case 'error':
message.classList.add('bg-red-50', 'text-red-800');
messageIcon.className = 'fas fa-exclamation-circle text-red-600 mr-2';
break;
case 'info':
message.classList.add('bg-blue-50', 'text-blue-800');
messageIcon.className = 'fas fa-info-circle text-blue-600 mr-2';
break;
}
message.classList.remove('hidden');
}
// Update form submission to handle API errors better
form.addEventListener('submit', async (e) => {
e.preventDefault();
try {
showMessage('Odesílání rezervace...', 'info');
const response = await fetch('/api/reservations', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
driverName: document.getElementById('driverName').value,
vehicle: document.getElementById('vehicle').value,
startDateTime: new Date(dateStart.value + 'T' + timeStart.value).toISOString(),
endDateTime: new Date(dateEnd.value + 'T' + timeEnd.value).toISOString(),
purpose: document.getElementById('purpose').value || undefined // Make purpose optional
})
});
if (!response.ok) {
throw new Error(response.statusText || 'Došlo k chybě při vytváření rezervace');
}
showMessage('Rezervace byla úspěšně vytvořena', 'success');
form.reset();
dateStart.value = todayStr;
dateEnd.value = todayStr;
} catch (error) {
console.error('Error:', error);
showMessage(error.message || 'Nepodařilo se vytvořit rezervaci', 'error');
}
});
</script>
</body>
</html>