feat: add deposit and weekend km allowance to vehicles, update migrations and booking flow

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
LagoESP
2026-04-29 16:00:06 +02:00
parent d960e37aa8
commit e85b319c93
10 changed files with 83 additions and 39 deletions
+6 -4
View File
@@ -139,10 +139,7 @@
<span data-i18n="adminPhotoUpload">Foto hochladen (JPG/PNG/WebP, max 50 MB)</span>
<input type="file" id="photoInput" accept="image/*" />
</label>
<label>
<span data-i18n="adminPhotoUrl">Foto-URL (wird automatisch gesetzt nach Upload)</span>
<input type="url" name="photo_url" placeholder="https://..." />
</label>
<input type="hidden" name="photo_url" />
<div class="row2">
<label><span data-i18n="adminBrand">Marke</span><input name="brand" required /></label>
@@ -163,6 +160,11 @@
<div class="row3">
<label><span>Max. km/Tag</span><input type="number" name="max_daily_km" min="0" value="150" /></label>
<label><span data-i18n="adminKaution">Kaution (€)</span><input type="number" name="kaution_eur" min="1" value="5000" required /></label>
<label><span data-i18n="adminMaxKmWeekend">Max. km/Wochenendtag</span><input type="number" name="max_km_weekend" min="0" placeholder="wie km/Tag" /></label>
</div>
<div class="row2">
<label><span data-i18n="adminSort">Reihenfolge</span><input type="number" name="sort_order" value="100" /></label>
<label><span data-i18n="adminLocation">Standort</span><input name="location" value="Steiermark (TBD)" /></label>
</div>
+11 -1
View File
@@ -230,6 +230,8 @@ function loadForEdit(id) {
vehicleForm.daily_price_eur.value = v.daily_price_eur;
vehicleForm.weekend_price_eur.value = v.weekend_price_eur || 0;
vehicleForm.max_daily_km.value = v.max_daily_km || 150;
vehicleForm.kaution_eur.value = v.kaution_eur || 5000;
vehicleForm.max_km_weekend.value = v.max_km_weekend || '';
vehicleForm.sort_order.value = v.sort_order;
vehicleForm.location.value = v.location;
vehicleForm.description_de.value = v.description_de;
@@ -250,6 +252,8 @@ resetBtn.addEventListener("click", () => {
vehicleForm.seats.value = 2;
vehicleForm.max_daily_km.value = 150;
vehicleForm.weekend_price_eur.value = 0;
vehicleForm.kaution_eur.value = 5000;
vehicleForm.max_km_weekend.value = '';
state.currentPhotoPath = null;
updatePreview("");
formTitle.textContent = "Neues Fahrzeug";
@@ -273,6 +277,8 @@ vehicleForm.addEventListener("submit", async (e) => {
daily_price_eur: +fd.get("daily_price_eur") || 0,
weekend_price_eur: +fd.get("weekend_price_eur") || 0,
max_daily_km: +fd.get("max_daily_km") || 150,
kaution_eur: +fd.get("kaution_eur") || 5000,
max_km_weekend: fd.get("max_km_weekend") ? +fd.get("max_km_weekend") : null,
sort_order: +fd.get("sort_order") || 100,
location: fd.get("location") || "Steiermark (TBD)",
description_de: fd.get("description_de") || "",
@@ -316,11 +322,15 @@ photoInput.addEventListener("change", async () => {
formFeedback.className = "form-feedback";
formFeedback.textContent = "Uploading photo...";
try {
// Delete old photo if exists
if (state.currentPhotoPath) {
await supabase.storage.from("vehicle-photos").remove([state.currentPhotoPath]);
}
const ext = (file.name.split(".").pop() || "jpg").toLowerCase();
const path = `${crypto.randomUUID()}.${ext}`;
const { error: upErr } = await supabase.storage
.from("vehicle-photos")
.upload(path, file, { contentType: file.type, upsert: false });
.upload(path, file, { contentType: file.type, upsert: true });
if (upErr) throw upErr;
const { data: pub } = supabase.storage.from("vehicle-photos").getPublicUrl(path);
state.currentPhotoPath = path;
+12 -2
View File
@@ -196,6 +196,14 @@ function openDetails(id) {
<div><strong>${v.top_speed_kmh}</strong><span>${t("kmh")}</span></div>
<div><strong>${escapeHtml(v.acceleration)}</strong><span>${t("accel")}</span></div>
</div>
<div class="spec-row" style="margin:1rem 0;">
<div><strong>${v.seats}</strong><span>${t("seats")}</span></div>
<div><strong>€ ${v.weekend_price_eur || v.daily_price_eur}</strong><span>${t("bpfWeekendRate")}</span></div>
<div><strong>${v.max_daily_km || 150}</strong><span>${t("bpfMaxKm")}</span></div>
</div>
<div class="spec-row" style="margin:1rem 0;grid-template-columns:1fr;">
<div><strong>€ ${(v.kaution_eur || 5000).toLocaleString("de-DE")}</strong><span>${t("bpfDeposit")}</span></div>
</div>
<div style="display:flex;justify-content:space-between;align-items:center;margin-top:1rem;">
<div class="vehicle-price">€ ${v.daily_price_eur}<span> / ${t("perDay")}</span></div>
<button class="btn" id="dialogBook">${t("bookNow")}</button>
@@ -364,8 +372,10 @@ function updateSidebar() {
const subtotal = weekdayCost + weekendCost;
const vat = Math.round(subtotal * 0.20);
const total = subtotal + vat;
const deposit = Math.round(v.daily_price_eur * 2.5);
const includedKm = (v.max_daily_km || 150) * totalDays;
const deposit = v.kaution_eur || 5000;
const kmPerWeekendDay = v.max_km_weekend || v.max_daily_km || 150;
const kmPerWeekday = v.max_daily_km || 150;
const includedKm = (weekdays * kmPerWeekday) + (weekendDays * kmPerWeekendDay);
bpfSidebarPlaceholder.style.display = "none";
bpfSidebarContent.style.display = "block";
+4 -2
View File
@@ -133,7 +133,6 @@ export const translations = {
adminNewVehicle: "Neues Fahrzeug",
adminAllVehicles: "Alle Fahrzeuge",
adminPhotoUpload: "Foto hochladen (JPG/PNG/WebP, max 50 MB)",
adminPhotoUrl: "Foto-URL (wird automatisch gesetzt nach Upload)",
adminBrand: "Marke",
adminModel: "Modell",
adminPower: "PS",
@@ -169,6 +168,8 @@ export const translations = {
adminReceived: "Eingang",
adminVehicleTab: "Fahrzeug",
adminPeriod: "Zeitraum",
adminKaution: "Kaution (€)",
adminMaxKmWeekend: "Max. km/Wochenendtag",
},
en: {
navCars: "Fleet",
@@ -303,7 +304,6 @@ export const translations = {
adminNewVehicle: "New vehicle",
adminAllVehicles: "All vehicles",
adminPhotoUpload: "Upload photo (JPG/PNG/WebP, max 50 MB)",
adminPhotoUrl: "Photo URL (auto-set after upload)",
adminBrand: "Brand",
adminModel: "Model",
adminPower: "HP",
@@ -339,6 +339,8 @@ export const translations = {
adminReceived: "Received",
adminVehicleTab: "Vehicle",
adminPeriod: "Period",
adminKaution: "Deposit (€)",
adminMaxKmWeekend: "Max. km/weekend day",
},
};