From 03f0e472dde873a694f182e96b22bc7944585d49 Mon Sep 17 00:00:00 2001 From: Tomas Dvorak Date: Wed, 11 Jun 2025 14:49:56 +0200 Subject: [PATCH] test rezervace - aut --- admin-dashboard.html | 209 +++++++++--------- index.html | 13 ++ main.go | 119 +++++++++++ rezervace-aut.html | 490 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 731 insertions(+), 100 deletions(-) create mode 100644 rezervace-aut.html diff --git a/admin-dashboard.html b/admin-dashboard.html index fcf32c7..ab4ca3d 100644 --- a/admin-dashboard.html +++ b/admin-dashboard.html @@ -912,9 +912,6 @@ z-index: 1; } - .upload-icon { - } - .upload-box:hover .upload-icon { color: #6c757d; } @@ -1208,6 +1205,51 @@ + + +
+

Správa rezervací vozidel

+ +
+
+ + +
+
+ + +
+
+ +
+ + + + + + + + + + + + + + +
ŘidičVozidloOdDoÚčelAkce
+
+
@@ -1592,37 +1634,6 @@ document.addEventListener('DOMContentLoaded', () => { } // Handle drop - dropArea.addEventListener('drop', handleDrop, false); - - function handleDrop(e) { - const dt = e.dataTransfer; - const files = dt.files; - if (files.length > 0) { - handleFileSelect(files[0]); - } - } - - // Handle drag and drop - ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { - dropArea.addEventListener(eventName, preventDefaults, false); - }); - - function highlight() { - dropArea.classList.add('dragover'); - } - - function unhighlight() { - dropArea.classList.remove('dragover'); - } - - ['dragenter', 'dragover'].forEach(eventName => { - dropArea.addEventListener(eventName, highlight, false); - }); - - ['dragleave', 'drop'].forEach(eventName => { - dropArea.addEventListener(eventName, unhighlight, false); - }); - dropArea.addEventListener('drop', function(e) { const dt = e.dataTransfer; const file = dt.files[0]; @@ -2809,81 +2820,79 @@ async function loadBanner() { const positionButtons = document.querySelectorAll('.position-btn'); if (positionButtons) { positionButtons.forEach(btn => { - if (btn) { - btn.classList.remove('active', 'btn-primary'); - btn.classList.add('btn-outline-secondary'); - if (btn.dataset.position === currentImagePosition) { - btn.classList.add('active', 'btn-primary'); - btn.classList.remove('btn-outline-secondary'); - } + btn.classList.remove('active', 'btn-primary'); + btn.classList.add('btn-outline-secondary'); + if (btn.dataset.position === currentImagePosition) { + btn.classList.add('active', 'btn-primary'); + btn.classList.remove('btn-outline-secondary'); } }); } - } + } + + // Update coordinates if they exist + if (data.Style?.ImageX !== undefined && data.Style?.ImageY !== undefined) { + currentImageX = data.Style.ImageX; + currentImageY = data.Style.ImageY; - // Update coordinates if they exist - if (data.Style?.ImageX !== undefined && data.Style?.ImageY !== undefined) { - currentImageX = data.Style.ImageX; - currentImageY = data.Style.ImageY; + // Update image preview position if it exists + if (bannerImgElement) { + bannerImgElement.style.left = `${currentImageX}px`; + bannerImgElement.style.top = `${currentImageY}px`; - // Update image preview position if it exists - if (bannerImgElement) { - bannerImgElement.style.left = `${currentImageX}px`; - bannerImgElement.style.top = `${currentImageY}px`; - - // Activate custom position button if it exists - const customPosBtn = document.getElementById('customPosBtn'); - if (customPosBtn) { - customPosBtn.classList.add('active', 'btn-primary'); - customPosBtn.classList.remove('btn-outline-secondary'); - } + // Activate custom position button if it exists + const customPosBtn = document.getElementById('customPosBtn'); + if (customPosBtn) { + customPosBtn.classList.add('active', 'btn-primary'); + customPosBtn.classList.remove('btn-outline-secondary'); } } - - // Show remove button if it exists - const removeBtn = document.getElementById('removeImageBtn'); - if (removeBtn) { - removeBtn.style.display = 'block'; - } - - // Set remove image input if it exists - const removeImageInput = document.getElementById('removeImage'); - if (removeImageInput) { - removeImageInput.value = 'false'; - } - } else { - // No image in the saved banner - currentImage = null; - - // Hide image preview and show upload prompt - if (imagePreview) { - imagePreview.style.display = 'none'; - } - if (uploadPrompt) { - uploadPrompt.style.display = 'block'; - } - - // Hide remove button - const removeBtn = document.getElementById('removeImageBtn'); - if (removeBtn) { - removeBtn.style.display = 'none'; - } - - // Set remove image input - const removeImageInput = document.getElementById('removeImage'); - if (removeImageInput) { - removeImageInput.value = 'true'; - } } - // Update previews - updateColorPreviews(); - updateBannerPreview(); + // Show remove button if it exists + const removeBtn = document.getElementById('removeImageBtn'); + if (removeBtn) { + removeBtn.style.display = 'block'; + } + + // Set remove image input if it exists + const removeImageInput = document.getElementById('removeImage'); + if (removeImageInput) { + removeImageInput.value = 'false'; + } + } else { + // No image in the saved banner + currentImage = null; + + // Hide image preview and show upload prompt + if (imagePreview) { + imagePreview.style.display = 'none'; + } + if (uploadPrompt) { + uploadPrompt.style.display = 'block'; + } + + // Hide remove button + const removeBtn = document.getElementById('removeImageBtn'); + if (removeBtn) { + removeBtn.style.display = 'none'; + } + + // Set remove image input + const removeImageInput = document.getElementById('removeImage'); + if (removeImageInput) { + removeImageInput.value = 'true'; + } } - } catch (error) { - console.error('Chyba při načítání banneru:', error); - showNotification('Chyba při načítání banneru', 'error'); + + // Update previews + updateColorPreviews(); + updateBannerPreview(); } + } catch (error) { + console.error('Chyba při načítání banneru:', error); + showNotification('Chyba při načítání banneru', 'error'); + } } // Add submission flag at the top of the script @@ -2938,7 +2947,7 @@ async function saveBanner(event) { const fontSize = bannerFontSize?.value || (currentTemplate && templateConfigs[currentTemplate]?.fontSize) || '16'; const padding = bannerPadding?.value || (currentTemplate && templateConfigs[currentTemplate]?.padding) || '20'; const margin = bannerMargin?.value || (currentTemplate && templateConfigs[currentTemplate]?.margin) || '20'; - const borderRadius = bannerBorderRadius?.value || (currentTemplate && templateConfigs[currentTemplate]?.borderRadius) || '8'; + const borderRadius = bannerBorderRadius?.value || (currentTemplate && templateConfigs[currentTemplate]?.borderRadius) || '4'; const buttonBg = (currentTemplate && templateConfigs[currentTemplate]?.buttonBackground) || '#4a6cf7'; const buttonTextColor = (currentTemplate && templateConfigs[currentTemplate]?.buttonTextColor) || '#ffffff'; const buttonBorder = (currentTemplate && templateConfigs[currentTemplate]?.buttonBorder) || 'none'; @@ -3290,7 +3299,7 @@ function updateBannerPreview() { margin: `${bannerMargin}px`, borderRadius: `${bannerBorderRadius}px`, - // Button styles + // Button styles (if template defines them) buttonBackground: bannerButtonBackground, buttonTextColor: bannerButtonTextColor, buttonBorder: bannerButtonBorder diff --git a/index.html b/index.html index 4230990..8edb8f8 100644 --- a/index.html +++ b/index.html @@ -381,6 +381,7 @@ OSticket Kanboard Kontakt + Rezervace aut @@ -392,6 +393,7 @@ OSticket Kanboard Kontakt + Rezervace aut @@ -474,6 +476,17 @@ +
+
+ +
+

Rezervace služebních vozů

+

Kalendář pro rezervaci a plánování služebních jízd

+ + Otevřít aplikaci + +
+ diff --git a/main.go b/main.go index 01eb07d..1c19c2f 100644 --- a/main.go +++ b/main.go @@ -49,6 +49,15 @@ type GeoCoords struct { Lng string `json:"lng"` } +type Reservation struct { + ID string `json:"id"` + DriverName string `json:"driverName"` + Vehicle string `json:"vehicle"` + StartDateTime time.Time `json:"startDateTime"` + EndDateTime time.Time `json:"endDateTime"` + Purpose string `json:"purpose"` +} + func main() { log.SetFlags(log.LstdFlags | log.Lshortfile) @@ -150,6 +159,11 @@ func main() { api.HandleFunc("/apps/{id}", UpdateAppHandler).Methods("PUT") api.HandleFunc("/apps/{id}", DeleteAppHandler).Methods("DELETE") + // Reservation system routes + api.HandleFunc("/reservations", handleGetReservations).Methods("GET") + api.HandleFunc("/reservations", handleCreateReservation).Methods("POST") + api.HandleFunc("/check-availability", handleCheckAvailability).Methods("GET") + // Admin routes - defined before the catch-all static file server r.HandleFunc("/admin", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, "admin.html") @@ -282,6 +296,111 @@ func saveApps(apps []App) error { return nil } +// Reservation Handlers +func handleGetReservations(w http.ResponseWriter, r *http.Request) { + reservations, err := loadReservations() + if err != nil { + http.Error(w, "Failed to load reservations", http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(reservations) +} + +func handleCreateReservation(w http.ResponseWriter, r *http.Request) { + var reservation Reservation + if err := json.NewDecoder(r.Body).Decode(&reservation); err != nil { + http.Error(w, "Invalid reservation data", http.StatusBadRequest) + return + } + + reservation.ID = fmt.Sprintf("res_%d", time.Now().UnixNano()) + + reservations, err := loadReservations() + if err != nil { + http.Error(w, "Failed to load reservations", http.StatusInternalServerError) + return + } + + reservations = append(reservations, reservation) + + if err := saveReservations(reservations); err != nil { + http.Error(w, "Failed to save reservation", http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(reservation) +} + +func handleCheckAvailability(w http.ResponseWriter, r *http.Request) { + vehicle := r.URL.Query().Get("vehicle") + startStr := r.URL.Query().Get("start") + endStr := r.URL.Query().Get("end") + + start, err := time.Parse(time.RFC3339, startStr) + if err != nil { + http.Error(w, "Invalid start time", http.StatusBadRequest) + return + } + + end, err := time.Parse(time.RFC3339, endStr) + if err != nil { + http.Error(w, "Invalid end time", http.StatusBadRequest) + return + } + + reservations, err := loadReservations() + if err != nil { + http.Error(w, "Failed to load reservations", http.StatusInternalServerError) + return + } + + available := true + for _, res := range reservations { + if res.Vehicle == vehicle { + if start.Before(res.EndDateTime) && end.After(res.StartDateTime) { + available = false + break + } + } + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(map[string]bool{"available": available}) +} + +func loadReservations() ([]Reservation, error) { + data, err := os.ReadFile("data/reservations.json") + if err != nil { + if os.IsNotExist(err) { + return []Reservation{}, nil + } + return nil, err + } + + var reservations []Reservation + if err := json.Unmarshal(data, &reservations); err != nil { + return nil, err + } + + return reservations, nil +} + +func saveReservations(reservations []Reservation) error { + data, err := json.MarshalIndent(reservations, "", " ") + if err != nil { + return err + } + + if err := os.MkdirAll("data", 0755); err != nil { + return err + } + + return os.WriteFile("data/reservations.json", data, 0644) +} + // App Handlers func GetAppsHandler(w http.ResponseWriter, r *http.Request) { // Set CORS headers diff --git a/rezervace-aut.html b/rezervace-aut.html new file mode 100644 index 0000000..116672b --- /dev/null +++ b/rezervace-aut.html @@ -0,0 +1,490 @@ + + + + + + Poppe Potthoff - Rezervace služebních vozů + + + + + + + + + + + + + + + +
+
+

Poppe + Potthoff – Rezervace služebních vozů

+

Systém pro rezervaci služebních vozidel

+
+
+ + +
+
+
+
+ + +
+

Nová rezervace

+
+ +
+ + +
+ + +
+ + +
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ + +
+ + +
+ + +
+
+
+
+ + + + + + + \ No newline at end of file