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
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
import { FiCalendar, FiMapPin } from "react-icons/fi";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
@@ -17,6 +17,21 @@ export default function NewBookingForm({
|
||||
const router = useRouter();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
const [equipmentList, setEquipmentList] = useState<any[]>([]);
|
||||
const [selectedEquipment, setSelectedEquipment] = useState<string[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
fetch("/api/equipment")
|
||||
.then((res) => res.json())
|
||||
.then((data) => setEquipmentList(data.equipment || []))
|
||||
.catch(() => {});
|
||||
}, []);
|
||||
|
||||
const toggleEquipment = (id: string) => {
|
||||
setSelectedEquipment((prev) =>
|
||||
prev.includes(id) ? prev.filter((e) => e !== id) : [...prev, id]
|
||||
);
|
||||
};
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
locationId: "",
|
||||
@@ -51,7 +66,7 @@ export default function NewBookingForm({
|
||||
const res = await fetch("/api/bookings/create", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(formData),
|
||||
body: JSON.stringify({ ...formData, equipmentIds: selectedEquipment }),
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
@@ -125,6 +140,7 @@ export default function NewBookingForm({
|
||||
required
|
||||
className="w-full px-4 py-2 bg-gray-700 border border-gray-600 text-white rounded-lg focus:ring-2 focus:ring-red-500 focus:border-transparent"
|
||||
>
|
||||
<option value="VINTAGE">Vintage</option>
|
||||
<option value="VINTAGE_SMILE">Vintage Smile</option>
|
||||
<option value="VINTAGE_PHOTOS">Vintage Photos</option>
|
||||
<option value="NOSTALGIE">Nostalgie</option>
|
||||
@@ -132,6 +148,34 @@ export default function NewBookingForm({
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{equipmentList.length > 0 && (
|
||||
<div className="mt-4">
|
||||
<label className="block text-sm font-medium text-gray-300 mb-2">
|
||||
Zusatzausstattung
|
||||
</label>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
{equipmentList.map((eq) => (
|
||||
<label
|
||||
key={eq.id}
|
||||
className={`flex items-center gap-2 p-3 rounded-lg border cursor-pointer transition-colors ${
|
||||
selectedEquipment.includes(eq.id)
|
||||
? "bg-red-500/10 border-red-500/50 text-white"
|
||||
: "bg-gray-700/50 border-gray-600 text-gray-300 hover:border-gray-500"
|
||||
}`}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selectedEquipment.includes(eq.id)}
|
||||
onChange={() => toggleEquipment(eq.id)}
|
||||
className="accent-red-500"
|
||||
/>
|
||||
{eq.name}
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -229,6 +273,49 @@ export default function NewBookingForm({
|
||||
className="w-full px-4 py-2 bg-gray-700 border border-gray-600 text-white rounded-lg focus:ring-2 focus:ring-red-500 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col-span-2">
|
||||
<label className="block text-sm font-medium text-gray-300 mb-2">
|
||||
Adresse
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={formData.customerAddress}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, customerAddress: e.target.value })
|
||||
}
|
||||
placeholder="Straße und Hausnummer"
|
||||
className="w-full px-4 py-2 bg-gray-700 border border-gray-600 text-white rounded-lg focus:ring-2 focus:ring-red-500 focus:border-transparent placeholder-gray-500"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-300 mb-2">
|
||||
PLZ
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={formData.customerZip}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, customerZip: 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-red-500 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-300 mb-2">
|
||||
Stadt
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={formData.customerCity}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, customerCity: 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-red-500 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -362,6 +449,34 @@ export default function NewBookingForm({
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-300 mb-2">
|
||||
Abbau ab
|
||||
</label>
|
||||
<input
|
||||
type="datetime-local"
|
||||
value={formData.dismantleTimeEarliest}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, dismantleTimeEarliest: 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-red-500 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-300 mb-2">
|
||||
Abbau spätestens
|
||||
</label>
|
||||
<input
|
||||
type="datetime-local"
|
||||
value={formData.dismantleTimeLatest}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, dismantleTimeLatest: 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-red-500 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col-span-2">
|
||||
<label className="block text-sm font-medium text-gray-300 mb-2">
|
||||
Notizen (optional)
|
||||
|
||||
Reference in New Issue
Block a user