Files
Atlas/app/dashboard/bookings/[id]/page.tsx
Julia Wehden a2c95c70e7 feat: Equipment-System, Buchungsbearbeitung, Kundenadresse, LexOffice-Fix
- Vintage Modell hinzugefuegt
- Equipment Multi-Select (Neue Buchung + Bearbeitung)
- Kundenadresse in Formularen
- Bearbeiten-Seite fuer Buchungen
- Abbau-Zeiten in Formularen und Uebersicht
- Vertrag PDF nur bei Privatkunden
- LexOffice Kontakt-Erstellung Fix (BUSINESS)
- Zurueck-Pfeil auf Touren-Seite
2026-03-19 16:21:55 +01:00

252 lines
11 KiB
TypeScript

import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth';
import { prisma } from '@/lib/prisma';
import { redirect } from 'next/navigation';
import DashboardSidebar from '@/components/DashboardSidebar';
import BookingAutomationPanel from '@/components/BookingAutomationPanel';
import { formatDate, formatDateTime } from '@/lib/date-utils';
import Link from 'next/link';
export default async function BookingDetailPage({ params }: { params: { id: string } }) {
const session = await getServerSession(authOptions);
if (!session || session.user.role !== 'ADMIN') {
redirect('/auth/signin');
}
const booking = await prisma.booking.findUnique({
where: { id: params.id },
include: {
location: true,
photobox: true,
},
});
if (!booking) {
redirect('/dashboard/bookings');
}
const getStatusColor = (status: string) => {
switch (status) {
case 'RESERVED': return 'bg-yellow-500/20 text-yellow-400 border border-yellow-500/50';
case 'CONFIRMED': return 'bg-green-500/20 text-green-400 border border-green-500/50';
case 'COMPLETED': return 'bg-blue-500/20 text-blue-400 border border-blue-500/50';
case 'CANCELLED': return 'bg-red-500/20 text-red-400 border border-red-500/50';
default: return 'bg-gray-500/20 text-gray-400 border border-gray-500/50';
}
};
const getStatusLabel = (status: string) => {
switch (status) {
case 'RESERVED': return 'Reserviert';
case 'CONFIRMED': return 'Bestätigt';
case 'COMPLETED': return 'Abgeschlossen';
case 'CANCELLED': return 'Storniert';
default: return status;
}
};
return (
<div className="min-h-screen bg-gradient-to-br from-gray-900 via-gray-800 to-gray-900">
<div className="flex">
<DashboardSidebar user={session.user} />
<main className="flex-1 p-8">
<div className="max-w-6xl mx-auto">
{/* Header */}
<div className="mb-8">
<div className="flex items-center justify-between mb-4">
<div>
<h1 className="text-3xl font-bold text-white">{booking.bookingNumber}</h1>
<p className="text-gray-400 mt-1">{booking.customerName}</p>
</div>
<div className="flex items-center gap-3">
<Link
href={`/dashboard/bookings/${booking.id}/edit`}
className="px-4 py-2 bg-gray-700 hover:bg-gray-600 text-white rounded-lg text-sm font-medium transition-colors"
>
Bearbeiten
</Link>
<div className={`px-4 py-2 rounded-lg ${getStatusColor(booking.status)}`}>
{getStatusLabel(booking.status)}
</div>
</div>
</div>
</div>
{/* Automation Panel */}
<div className="mb-8">
<BookingAutomationPanel booking={booking} invoiceType={booking.invoiceType} />
</div>
{/* Booking Details */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{/* Customer Info */}
<div className="bg-gradient-to-br from-gray-800 to-gray-900 border border-gray-700 rounded-xl p-6 shadow-lg">
<h3 className="text-xl font-bold text-white mb-4">Kundendaten</h3>
<div className="space-y-3 text-sm">
<div>
<span className="text-gray-400">Name:</span>
<span className="text-white ml-2 font-medium">{booking.customerName}</span>
</div>
<div>
<span className="text-gray-400">E-Mail:</span>
<span className="text-white ml-2">{booking.customerEmail}</span>
</div>
<div>
<span className="text-gray-400">Telefon:</span>
<span className="text-white ml-2">{booking.customerPhone}</span>
</div>
{booking.customerAddress && (
<div>
<span className="text-gray-400">Adresse:</span>
<span className="text-white ml-2">
{booking.customerAddress}, {booking.customerZip} {booking.customerCity}
</span>
</div>
)}
{booking.companyName && (
<div>
<span className="text-gray-400">Firma:</span>
<span className="text-white ml-2">{booking.companyName}</span>
</div>
)}
</div>
</div>
{/* Event Info */}
<div className="bg-gradient-to-br from-gray-800 to-gray-900 border border-gray-700 rounded-xl p-6 shadow-lg">
<h3 className="text-xl font-bold text-white mb-4">Event-Details</h3>
<div className="space-y-3 text-sm">
<div>
<span className="text-gray-400">Datum:</span>
<span className="text-white ml-2 font-medium">{formatDate(booking.eventDate)}</span>
</div>
<div>
<span className="text-gray-400">Location:</span>
<span className="text-white ml-2">{booking.eventLocation || '-'}</span>
</div>
<div>
<span className="text-gray-400">Adresse:</span>
<span className="text-white ml-2">
{booking.eventAddress}, {booking.eventZip} {booking.eventCity}
</span>
</div>
<div>
<span className="text-gray-400">Aufbau Start:</span>
<span className="text-white ml-2">{formatDateTime(booking.setupTimeStart)}</span>
</div>
<div>
<span className="text-gray-400">Aufbau spätestens:</span>
<span className="text-white ml-2">{formatDateTime(booking.setupTimeLatest)}</span>
</div>
{booking.dismantleTimeEarliest && (
<div>
<span className="text-gray-400">Abbau ab:</span>
<span className="text-white ml-2">{formatDateTime(booking.dismantleTimeEarliest)}</span>
</div>
)}
{booking.dismantleTimeLatest && (
<div>
<span className="text-gray-400">Abbau spätestens:</span>
<span className="text-white ml-2">{formatDateTime(booking.dismantleTimeLatest)}</span>
</div>
)}
{booking.notes && (
<div className="pt-3 border-t border-gray-700">
<span className="text-gray-400">Notizen:</span>
<p className="text-white mt-1 whitespace-pre-wrap">{booking.notes}</p>
</div>
)}
</div>
</div>
{/* Photobox & Pricing */}
<div className="bg-gradient-to-br from-gray-800 to-gray-900 border border-gray-700 rounded-xl p-6 shadow-lg">
<h3 className="text-xl font-bold text-white mb-4">Fotobox & Preis</h3>
<div className="space-y-3 text-sm">
<div>
<span className="text-gray-400">Modell:</span>
<span className="text-white ml-2 font-medium">{booking.photobox?.model || '-'}</span>
</div>
<div>
<span className="text-gray-400">Serial Number:</span>
<span className="text-white ml-2">{booking.photobox?.serialNumber || '-'}</span>
</div>
<div>
<span className="text-gray-400">Druckflatrate:</span>
<span className="text-white ml-2">{booking.withPrintFlat ? 'Ja' : 'Nein'}</span>
</div>
{booking.distance && (
<div>
<span className="text-gray-400">Entfernung:</span>
<span className="text-white ml-2">{booking.distance.toFixed(1)} km</span>
</div>
)}
{booking.calculatedPrice && (
<div className="pt-3 border-t border-gray-700">
<span className="text-gray-400">Gesamtpreis:</span>
<span className="text-2xl text-pink-400 ml-2 font-bold">
{booking.calculatedPrice.toFixed(2)}
</span>
</div>
)}
</div>
</div>
{/* Location Info */}
<div className="bg-gradient-to-br from-gray-800 to-gray-900 border border-gray-700 rounded-xl p-6 shadow-lg">
<h3 className="text-xl font-bold text-white mb-4">Standort</h3>
<div className="space-y-3 text-sm">
<div>
<span className="text-gray-400">Name:</span>
<span className="text-white ml-2 font-medium">{booking.location?.name}</span>
</div>
<div>
<span className="text-gray-400">Stadt:</span>
<span className="text-white ml-2">{booking.location?.city}</span>
</div>
<div>
<span className="text-gray-400">Website:</span>
<span className="text-white ml-2">{booking.location?.websiteUrl}</span>
</div>
<div>
<span className="text-gray-400">Kontakt:</span>
<span className="text-white ml-2">{booking.location?.contactEmail}</span>
</div>
</div>
</div>
</div>
{/* LexOffice IDs (if present) */}
{(booking.lexofficeContactId || booking.lexofficeOfferId || booking.lexofficeConfirmationId) && (
<div className="mt-6 bg-gradient-to-br from-gray-800 to-gray-900 border border-gray-700 rounded-xl p-6 shadow-lg">
<h3 className="text-xl font-bold text-white mb-4">LexOffice Integration</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 text-sm">
{booking.lexofficeContactId && (
<div>
<span className="text-gray-400">Kontakt-ID:</span>
<span className="text-white ml-2 font-mono text-xs">{booking.lexofficeContactId}</span>
</div>
)}
{booking.lexofficeOfferId && (
<div>
<span className="text-gray-400">Angebots-ID:</span>
<span className="text-white ml-2 font-mono text-xs">{booking.lexofficeOfferId}</span>
</div>
)}
{booking.lexofficeConfirmationId && (
<div>
<span className="text-gray-400">Bestätigungs-ID:</span>
<span className="text-white ml-2 font-mono text-xs">{booking.lexofficeConfirmationId}</span>
</div>
)}
</div>
</div>
)}
</div>
</main>
</div>
</div>
);
}