mirror of
https://github.com/Dvorinka/PPve.git
synced 2026-06-05 04:52:58 +00:00
dd
This commit is contained in:
@@ -311,8 +311,36 @@ func handleGetReservations(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert reservations to calendar events
|
||||||
|
type Event struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Start string `json:"start"`
|
||||||
|
End string `json:"end"`
|
||||||
|
DriverName string `json:"driverName"`
|
||||||
|
Vehicle string `json:"vehicle"`
|
||||||
|
Purpose string `json:"purpose"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var events []Event
|
||||||
|
for _, res := range reservations {
|
||||||
|
// Create proper ISO datetime strings
|
||||||
|
start := fmt.Sprintf("%sT%s:00", res.StartDate, res.StartTime)
|
||||||
|
end := fmt.Sprintf("%sT%s:00", res.EndDate, res.EndTime)
|
||||||
|
|
||||||
|
events = append(events, Event{
|
||||||
|
ID: res.ID,
|
||||||
|
Title: fmt.Sprintf("%s - %s", res.Vehicle, res.DriverName),
|
||||||
|
Start: start,
|
||||||
|
End: end,
|
||||||
|
DriverName: res.DriverName,
|
||||||
|
Vehicle: res.Vehicle,
|
||||||
|
Purpose: res.Purpose,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(reservations)
|
json.NewEncoder(w).Encode(events)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleCreateReservation(w http.ResponseWriter, r *http.Request) {
|
func handleCreateReservation(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -322,6 +350,9 @@ func handleCreateReservation(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Log received data for debugging
|
||||||
|
log.Printf("Received reservation data: %+v", reservation)
|
||||||
|
|
||||||
// Validate required fields
|
// Validate required fields
|
||||||
if reservation.DriverName == "" || reservation.Vehicle == "" ||
|
if reservation.DriverName == "" || reservation.Vehicle == "" ||
|
||||||
reservation.StartDate == "" || reservation.StartTime == "" ||
|
reservation.StartDate == "" || reservation.StartTime == "" ||
|
||||||
@@ -330,18 +361,20 @@ func handleCreateReservation(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create combined date-time string
|
// Create combined date-time string for validation
|
||||||
startDateTime, err := time.Parse("2006-01-02 15:04",
|
startDateTime, err := time.Parse("2006-01-02 15:04",
|
||||||
fmt.Sprintf("%s %s", reservation.StartDate, reservation.StartTime))
|
fmt.Sprintf("%s %s", reservation.StartDate, reservation.StartTime))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Invalid start date/time", http.StatusBadRequest)
|
log.Printf("Error parsing start date/time: %v", err)
|
||||||
|
http.Error(w, "Invalid start date/time format", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
endDateTime, err := time.Parse("2006-01-02 15:04",
|
endDateTime, err := time.Parse("2006-01-02 15:04",
|
||||||
fmt.Sprintf("%s %s", reservation.EndDate, reservation.EndTime))
|
fmt.Sprintf("%s %s", reservation.EndDate, reservation.EndTime))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Invalid end date/time", http.StatusBadRequest)
|
log.Printf("Error parsing end date/time: %v", err)
|
||||||
|
http.Error(w, "Invalid end date/time format", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -351,6 +384,17 @@ func handleCreateReservation(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check availability
|
||||||
|
available, err := checkReservationAvailability(reservation.Vehicle, startDateTime, endDateTime)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Failed to check availability", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !available {
|
||||||
|
http.Error(w, "Selected time slot is not available", http.StatusConflict)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Generate unique ID
|
// Generate unique ID
|
||||||
reservation.ID = fmt.Sprintf("res_%d", time.Now().UnixNano())
|
reservation.ID = fmt.Sprintf("res_%d", time.Now().UnixNano())
|
||||||
|
|
||||||
@@ -368,10 +412,40 @@ func handleCreateReservation(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusCreated)
|
w.WriteHeader(http.StatusCreated)
|
||||||
json.NewEncoder(w).Encode(reservation)
|
json.NewEncoder(w).Encode(reservation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add helper function to check availability
|
||||||
|
func checkReservationAvailability(vehicle string, start, end time.Time) (bool, error) {
|
||||||
|
reservations, err := loadReservations()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, res := range reservations {
|
||||||
|
resStart, err := time.Parse("2006-01-02 15:04",
|
||||||
|
fmt.Sprintf("%s %s", res.StartDate, res.StartTime))
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
resEnd, err := time.Parse("2006-01-02 15:04",
|
||||||
|
fmt.Sprintf("%s %s", res.EndDate, res.EndTime))
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.Vehicle == vehicle &&
|
||||||
|
!(end.Before(resStart) || start.After(resEnd)) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
func handleCheckAvailability(w http.ResponseWriter, r *http.Request) {
|
func handleCheckAvailability(w http.ResponseWriter, r *http.Request) {
|
||||||
// Get query parameters
|
// Get query parameters
|
||||||
vehicle := r.URL.Query().Get("vehicle")
|
vehicle := r.URL.Query().Get("vehicle")
|
||||||
@@ -386,7 +460,7 @@ func handleCheckAvailability(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse dates in correct format (YYYY-MM-DD HH:MM)
|
// Parse the dates with specific format
|
||||||
startDateTime, err := time.Parse("2006-01-02 15:04",
|
startDateTime, err := time.Parse("2006-01-02 15:04",
|
||||||
fmt.Sprintf("%s %s", startDate, startTime))
|
fmt.Sprintf("%s %s", startDate, startTime))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -401,23 +475,17 @@ func handleCheckAvailability(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate time order
|
// Load existing reservations
|
||||||
if endDateTime.Before(startDateTime) {
|
|
||||||
http.Error(w, "End time must be after start time", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check availability
|
|
||||||
reservations, err := loadReservations()
|
reservations, err := loadReservations()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Failed to load reservations", http.StatusInternalServerError)
|
http.Error(w, "Failed to load reservations", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for conflicts
|
||||||
available := true
|
available := true
|
||||||
for _, res := range reservations {
|
for _, res := range reservations {
|
||||||
if res.Vehicle == vehicle {
|
if res.Vehicle == vehicle {
|
||||||
// Parse reservation dates
|
|
||||||
resStart, err := time.Parse("2006-01-02 15:04",
|
resStart, err := time.Parse("2006-01-02 15:04",
|
||||||
fmt.Sprintf("%s %s", res.StartDate, res.StartTime))
|
fmt.Sprintf("%s %s", res.StartDate, res.StartTime))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -430,15 +498,14 @@ func handleCheckAvailability(w http.ResponseWriter, r *http.Request) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for overlap
|
// Check if there is any overlap
|
||||||
if startDateTime.Before(resEnd) && endDateTime.After(resStart) {
|
if !(endDateTime.Before(resStart) || startDateTime.After(resEnd)) {
|
||||||
available = false
|
available = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return response
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(map[string]bool{"available": available})
|
json.NewEncoder(w).Encode(map[string]bool{"available": available})
|
||||||
}
|
}
|
||||||
|
|||||||
+37
-24
@@ -454,23 +454,36 @@
|
|||||||
locale: 'cs',
|
locale: 'cs',
|
||||||
slotMinTime: '06:00:00',
|
slotMinTime: '06:00:00',
|
||||||
slotMaxTime: '22:00:00',
|
slotMaxTime: '22:00:00',
|
||||||
slotDuration: '01:00:00', // Set slot duration to 1 hour
|
slotDuration: '01:00:00',
|
||||||
snapDuration: '01:00:00', // Snap to hour intervals
|
snapDuration: '01:00:00',
|
||||||
allDaySlot: false,
|
allDaySlot: false,
|
||||||
businessHours: {
|
events: '/api/reservations',
|
||||||
daysOfWeek: [1, 2, 3, 4, 5],
|
eventDisplay: 'block',
|
||||||
|
eventTimeFormat: {
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
hour12: false
|
||||||
|
},
|
||||||
|
eventContent: function(arg) {
|
||||||
|
return {
|
||||||
|
html: `
|
||||||
|
<div class="event-content">
|
||||||
|
<div class="font-bold">${arg.event.extendedProps.driverName || 'Rezervace'}</div>
|
||||||
|
<div>${arg.event.extendedProps.purpose || ''}</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
};
|
||||||
|
},
|
||||||
|
// Add these properties to ensure proper event rendering
|
||||||
|
eventConstraint: {
|
||||||
startTime: '06:00',
|
startTime: '06:00',
|
||||||
endTime: '22:00',
|
endTime: '22:00',
|
||||||
|
dows: [0,1,2,3,4,5,6]
|
||||||
},
|
},
|
||||||
events: '/api/reservations',
|
selectConstraint: {
|
||||||
eventClick: function(info) {
|
startTime: '06:00',
|
||||||
alert(`
|
endTime: '22:00',
|
||||||
Řidič: ${info.event.title}
|
dows: [0,1,2,3,4,5,6]
|
||||||
Vozidlo: ${info.event.extendedProps.vehicle}
|
|
||||||
Účel: ${info.event.extendedProps.purpose}
|
|
||||||
Od: ${info.event.start.toLocaleString()}
|
|
||||||
Do: ${info.event.end.toLocaleString()}
|
|
||||||
`);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -479,17 +492,16 @@
|
|||||||
// Check vehicle availability
|
// Check vehicle availability
|
||||||
async function checkVehicleAvailability(vehicle, startDate, endDate) {
|
async function checkVehicleAvailability(vehicle, startDate, endDate) {
|
||||||
try {
|
try {
|
||||||
// Format dates correctly
|
// Format dates for API
|
||||||
const formatDateTime = (date) => {
|
const startDateTime = new Date(startDate);
|
||||||
return date.toISOString().split('.')[0]; // Remove milliseconds
|
const endDateTime = new Date(endDate);
|
||||||
};
|
|
||||||
|
|
||||||
const params = new URLSearchParams({
|
const params = new URLSearchParams({
|
||||||
vehicle: vehicle,
|
vehicle: vehicle,
|
||||||
startDate: startDate.toISOString().split('T')[0],
|
startDate: startDateTime.toISOString().split('T')[0],
|
||||||
startTime: startDate.toTimeString().split(' ')[0].slice(0, 5),
|
startTime: startDateTime.toTimeString().split(' ')[0].slice(0, 5),
|
||||||
endDate: endDate.toISOString().split('T')[0],
|
endDate: endDateTime.toISOString().split('T')[0],
|
||||||
endTime: endDate.toTimeString().split(' ')[0].slice(0, 5)
|
endTime: endDateTime.toTimeString().split(' ')[0].slice(0, 5)
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await fetch(`/api/check-availability?${params}`);
|
const response = await fetch(`/api/check-availability?${params}`);
|
||||||
@@ -585,15 +597,16 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error('Chyba při vytváření rezervace');
|
const errorData = await response.json();
|
||||||
|
throw new Error(errorData.message || 'Failed to create reservation');
|
||||||
}
|
}
|
||||||
|
|
||||||
showMessage('Rezervace byla úspěšně vytvořena', 'success');
|
showMessage('Rezervace byla úspěšně vytvořena', 'success');
|
||||||
calendar.refetchEvents();
|
|
||||||
reservationForm.reset();
|
reservationForm.reset();
|
||||||
|
calendar.refetchEvents();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error:', error);
|
console.error('Error:', error);
|
||||||
showMessage(error.message || 'Nepodařilo se vytvořit rezervaci', 'error');
|
showMessage(error.message || 'Chyba při vytváření rezervace', 'error');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user