'use client'; import { useState, useEffect } from 'react'; import { useRouter } from 'next/navigation'; import { formatDate } from '@/lib/date-utils'; import DashboardSidebar from '@/components/DashboardSidebar'; import { useSession } from 'next-auth/react'; export default function ToursPage() { const router = useRouter(); const { data: session } = useSession(); const [tours, setTours] = useState([]); const [drivers, setDrivers] = useState([]); const [bookings, setBookings] = useState([]); const [loading, setLoading] = useState(true); const [showForm, setShowForm] = useState(false); const [formData, setFormData] = useState({ tourDate: '', driverId: '', bookingIds: [] as string[], optimizationType: 'fastest' as 'fastest' | 'schedule', }); useEffect(() => { fetchTours(); fetchDrivers(); fetchUnassignedBookings(); }, []); const fetchTours = async () => { try { const res = await fetch('/api/tours'); const data = await res.json(); setTours(data.tours || []); } catch (error) { console.error('Fetch error:', error); } finally { setLoading(false); } }; const fetchDrivers = async () => { try { const res = await fetch('/api/drivers?available=true'); const data = await res.json(); setDrivers(data.drivers || []); } catch (error) { console.error('Drivers fetch error:', error); } }; const fetchUnassignedBookings = async () => { try { const res = await fetch('/api/bookings'); const data = await res.json(); const unassigned = (data.bookings || []).filter((b: any) => { // Must be confirmed and not assigned to a tour if (!b.tourId && b.status === 'CONFIRMED') { // If booking has setup windows, check if any are already selected if (b.setupWindows && b.setupWindows.length > 0) { const hasSelectedWindow = b.setupWindows.some((w: any) => w.selected); return !hasSelectedWindow; // Exclude if any window is already selected } return true; // No setup windows, just check tourId } return false; }); setBookings(unassigned); } catch (error) { console.error('Bookings fetch error:', error); } }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { const res = await fetch('/api/tours', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(formData), }); if (res.ok) { setShowForm(false); setFormData({ tourDate: '', driverId: '', bookingIds: [], optimizationType: 'fastest', }); fetchTours(); fetchUnassignedBookings(); } else { alert('Fehler beim Erstellen'); } } catch (error) { console.error('Create error:', error); alert('Fehler beim Erstellen'); } }; const toggleBooking = (bookingId: string) => { setFormData(prev => ({ ...prev, bookingIds: prev.bookingIds.includes(bookingId) ? prev.bookingIds.filter(id => id !== bookingId) : [...prev.bookingIds, bookingId], })); }; // Filter bookings by selected tour date const availableBookings = formData.tourDate ? bookings.filter(booking => { const bookingDate = new Date(booking.eventDate).toISOString().split('T')[0]; const tourDate = formData.tourDate; // Check if event date matches if (bookingDate === tourDate) return true; // Check if any setup window date matches if (booking.setupWindows && booking.setupWindows.length > 0) { return booking.setupWindows.some((window: any) => { const windowDate = new Date(window.setupDate).toISOString().split('T')[0]; return windowDate === tourDate && !window.selected; }); } return false; }) : bookings; // Group bookings by date for display const bookingsByDate = bookings.reduce((acc: any, booking: any) => { const date = new Date(booking.eventDate).toISOString().split('T')[0]; if (!acc[date]) acc[date] = []; acc[date].push(booking); return acc; }, {}); const getStatusBadge = (status: string) => { const styles: Record = { PLANNED: 'bg-blue-500/20 text-blue-400 border-blue-500/50', IN_PROGRESS: 'bg-yellow-500/20 text-yellow-400 border-yellow-500/50', COMPLETED: 'bg-green-500/20 text-green-400 border-green-500/50', CANCELLED: 'bg-red-500/20 text-red-400 border-red-500/50', }; return styles[status] || 'bg-gray-500/20 text-gray-400 border-gray-500/50'; }; const getStatusLabel = (status: string) => { const labels: Record = { PLANNED: 'Geplant', IN_PROGRESS: 'In Arbeit', COMPLETED: 'Abgeschlossen', CANCELLED: 'Abgebrochen', }; return labels[status] || status; }; if (loading) { return (

Lädt...

); } return (

Touren

Verwalten Sie Fahrer-Touren

{showForm && (

Neue Tour erstellen

setFormData({ ...formData, tourDate: e.target.value })} className="w-full px-4 py-2 bg-gray-700 border border-gray-600 text-white rounded-lg focus:ring-2 focus:ring-blue-500" required />

{formData.optimizationType === 'fastest' ? 'Optimiert nach kürzester Strecke/Zeit' : 'Berücksichtigt Aufbau-Zeitfenster der Buchungen'}

{!formData.tourDate && (

⚠️ Bitte wähle zuerst ein Tour-Datum aus, um passende Buchungen zu sehen

)} {formData.tourDate && availableBookings.length === 0 && (

ℹ️ Keine bestätigten Buchungen für {new Date(formData.tourDate).toLocaleDateString('de-DE')} gefunden

)}
{availableBookings.length > 0 ? (
{availableBookings.map((booking) => { const bookingDate = new Date(booking.eventDate).toISOString().split('T')[0]; const isEventDate = bookingDate === formData.tourDate; const matchingWindows = booking.setupWindows?.filter((w: any) => { const windowDate = new Date(w.setupDate).toISOString().split('T')[0]; return windowDate === formData.tourDate && !w.selected; }) || []; return ( ); })}
) : (

{formData.tourDate ? 'Keine Buchungen für dieses Datum' : 'Bitte Datum auswählen'}

)}
)}
{tours.map((tour) => (
router.push(`/dashboard/tours/${tour.id}`)} className="bg-gradient-to-br from-gray-800 to-gray-900 rounded-lg shadow-xl p-6 hover:shadow-2xl transition-all cursor-pointer border border-gray-700 hover:border-blue-500" >

{tour.tourNumber}

{formatDate(tour.tourDate)}

{getStatusLabel(tour.status)}

Fahrer:{' '} {tour.driver ? tour.driver.name : 'Nicht zugewiesen'}

Buchungen: {tour.bookings.length}

{tour.totalDistance && (

Strecke: {tour.totalDistance} km

)} {tour.estimatedDuration && (

Dauer: ~{tour.estimatedDuration} Min

)}
))}
{tours.length === 0 && (

Noch keine Touren vorhanden

)}
); }