feat: enhance booking flow with BPF wizard, weekend pricing, and document uploads

- Updated translations for German and English to reflect changes in deposit terminology.
- Modified index.html to implement a new booking flow with a step-by-step wizard for vehicle selection, contact details, and ID verification.
- Added CSS styles for the new booking flow interface, including responsive design and improved input styles.
- Created new database policies and tables for handling customer and lead attachments during the booking process.
- Introduced weekend pricing and daily KM limits for vehicles in the database schema.
- Implemented email-based customer upsert functionality to streamline lead qualification and attachment transfer.

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
LagoESP
2026-04-29 15:01:25 +02:00
parent d17fe0651e
commit d960e37aa8
10 changed files with 880 additions and 86 deletions
+161 -42
View File
@@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>MC Cars · Sportwagenvermietung Steiermark</title>
<meta name="description" content="MC Cars · Premium Sportwagen- und Luxusvermietung in der Steiermark. Kautionsfrei, transparent, sofort startklar." />
<meta name="description" content="MC Cars · Premium Sportwagen- und Luxusvermietung in der Steiermark. Faire Kaution, transparent, sofort startklar." />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Playfair+Display:wght@500;600;700&display=swap" rel="stylesheet" />
@@ -46,7 +46,7 @@
</div>
<div class="hero-stats">
<div><strong>0 €</strong><span data-i18n="statDeposit">Kaution</span></div>
<div><strong data-i18n="statDeposit">Faire Kaution</strong><span>Fair Deposit</span></div>
<div><strong id="statCarsCount"></strong><span data-i18n="statCars">Fahrzeuge</span></div>
<div><strong>24/7</strong><span data-i18n="statSupport">Support</span></div>
</div>
@@ -112,8 +112,8 @@
</article>
<article class="why-card">
<div class="icon"></div>
<h3 data-i18n="whyDeposit">Kautionsfrei</h3>
<p data-i18n="whyDepositText">Sie zahlen nur die Miete.</p>
<h3 data-i18n="whyDeposit">Faire Kaution</h3>
<p data-i18n="whyDepositText">Kein Ueberziehen. Transparente, faire Kaution ohne unnoetige Belastung.</p>
</article>
</div>
</div>
@@ -134,49 +134,168 @@
</div>
</section>
<!-- Booking -->
<!-- Booking BPF -->
<section id="buchen" style="background:var(--bg-elev);">
<div class="shell">
<div class="section-head">
<div>
<p class="eyebrow" data-i18n="bookingEyebrow">Jetzt buchen</p>
<h2 data-i18n="bookingTitle">Traumwagen unverbindlich anfragen.</h2>
</div>
<div class="bpf-header">
<h2 data-i18n="bpfTitle">Jetzt buchen</h2>
<p class="sub" data-i18n="bpfSubtitle">Waehle dein Wunschfahrzeug, den Zeitraum und konfiguriere deine Buchung nach Wunsch.</p>
</div>
<form class="booking-form" id="bookingForm" novalidate>
<label>
<span data-i18n="fieldName">Name</span>
<input type="text" name="name" required />
</label>
<label>
<span data-i18n="fieldEmail">E-Mail</span>
<input type="email" name="email" required />
</label>
<label>
<span data-i18n="fieldPhone">Telefon</span>
<input type="tel" name="phone" />
</label>
<label>
<span data-i18n="fieldCar">Fahrzeug</span>
<select name="vehicle" id="bookingCar"></select>
</label>
<label>
<span data-i18n="fieldFrom">Von</span>
<input type="date" name="from" required />
</label>
<label>
<span data-i18n="fieldTo">Bis</span>
<input type="date" name="to" required />
</label>
<label class="full">
<span data-i18n="fieldMessage">Nachricht</span>
<textarea name="message" rows="4" data-i18n-placeholder="messagePlaceholder" placeholder="Wuensche, Uhrzeit, Anlass..."></textarea>
</label>
<div class="full" style="display:flex;justify-content:flex-end;">
<button type="submit" class="btn" data-i18n="sendRequest">Anfrage senden</button>
<!-- Step indicators -->
<div class="bpf-steps" id="bpfSteps">
<button class="bpf-step active" data-step="1"><span class="bpf-step-num">1</span> <span data-i18n="stepVehicleTime">Fahrzeug & Zeitraum</span></button>
<span class="bpf-step-arrow"></span>
<button class="bpf-step" data-step="2"><span class="bpf-step-num">2</span> <span data-i18n="stepContact">Kontaktdaten</span></button>
<span class="bpf-step-arrow"></span>
<button class="bpf-step" data-step="3"><span class="bpf-step-num">3</span> <span data-i18n="stepVerification">ID-Verifizierung</span></button>
</div>
<div class="bpf-layout">
<!-- Main form area -->
<div class="bpf-main">
<!-- Step 1: Vehicle & Time -->
<div class="bpf-panel" id="bpfStep1">
<h3 class="bpf-panel-title">🚗 <span data-i18n="stepVehicleTime">Fahrzeug & Zeitraum</span></h3>
<div class="bpf-field">
<label data-i18n="bpfVehicle">Fahrzeug</label>
<select id="bpfCar">
<option value="" data-i18n="bpfSelectVehicle">Fahrzeug waehlen</option>
</select>
</div>
<div class="bpf-field">
<label data-i18n="bpfDuration">Mietdauer</label>
<div class="bpf-duration-presets" id="bpfDurationPresets">
<button type="button" class="bpf-preset" data-preset="day">
<span class="bpf-preset-icon">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect><line x1="16" y1="2" x2="16" y2="6"></line><line x1="8" y1="2" x2="8" y2="6"></line><line x1="3" y1="10" x2="21" y2="10"></line><path d="M12 14h.01"></path><path d="M12 16h.01"></path></svg>
</span>
<span data-i18n="bpfPresetDay">1 Tag</span>
</button>
<button type="button" class="bpf-preset" data-preset="weekend">
<span class="bpf-preset-icon">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect><line x1="16" y1="2" x2="16" y2="6"></line><line x1="8" y1="2" x2="8" y2="6"></line><line x1="3" y1="10" x2="21" y2="10"></line><path d="M14 14h4v4h-4z"></path></svg>
</span>
<span data-i18n="bpfPresetWeekend">Wochenende</span>
</button>
<button type="button" class="bpf-preset active" data-preset="custom">
<span class="bpf-preset-icon">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect><line x1="16" y1="2" x2="16" y2="6"></line><line x1="8" y1="2" x2="8" y2="6"></line><line x1="3" y1="10" x2="21" y2="10"></line><path d="M8 14h8"></path><path d="M8 18h8"></path></svg>
</span>
<span data-i18n="bpfPresetCustom">Individuell</span>
</button>
</div>
</div>
<!-- Day mode: single date picker -->
<div class="bpf-field bpf-date-day" id="bpfDateDay" style="display:none;">
<label data-i18n="bpfPickDate">Datum waehlen</label>
<input type="date" id="bpfDayDate" />
</div>
<!-- Weekend mode: pick the Saturday -->
<div class="bpf-field bpf-date-weekend" id="bpfDateWeekend" style="display:none;">
<label data-i18n="bpfPickWeekend">Wochenende waehlen (Samstag)</label>
<input type="date" id="bpfWeekendDate" />
<p class="bpf-weekend-def" data-i18n="bpfWeekendDef">Wochenende: Samstag 9:00 Sonntag 20:00</p>
</div>
<!-- Custom mode: from/to date pickers -->
<div class="bpf-date-custom" id="bpfDateCustom">
<div class="bpf-field-row">
<div class="bpf-field">
<label data-i18n="bpfStartDate">Startdatum</label>
<input type="date" id="bpfFrom" />
</div>
<div class="bpf-field">
<label data-i18n="bpfEndDate">Enddatum</label>
<input type="date" id="bpfTo" />
</div>
</div>
</div>
<div class="bpf-nav">
<div></div>
<button class="btn" type="button" id="bpfNext1" data-i18n="bpfNext">Weiter</button>
</div>
</div>
<!-- Step 2: Contact -->
<div class="bpf-panel" id="bpfStep2" style="display:none;">
<h3 class="bpf-panel-title">📋 <span data-i18n="stepContact">Kontaktdaten</span></h3>
<div class="bpf-field">
<label data-i18n="fieldName">Name</label>
<input type="text" id="bpfName" required />
</div>
<div class="bpf-field-row">
<div class="bpf-field">
<label data-i18n="fieldEmail">E-Mail</label>
<input type="email" id="bpfEmail" required />
</div>
<div class="bpf-field">
<label data-i18n="fieldPhone">Telefon</label>
<input type="tel" id="bpfPhone" />
</div>
</div>
<div class="bpf-field">
<label data-i18n="fieldMessage">Nachricht</label>
<textarea id="bpfMessage" rows="3" data-i18n-placeholder="messagePlaceholder" placeholder="Wuensche, Uhrzeit, Anlass..."></textarea>
</div>
<div class="bpf-nav">
<button class="btn ghost" type="button" id="bpfBack2" data-i18n="bpfBack">Zurueck</button>
<button class="btn" type="button" id="bpfNext2" data-i18n="bpfNext">Weiter</button>
</div>
</div>
<!-- Step 3: ID Verification -->
<div class="bpf-panel" id="bpfStep3" style="display:none;">
<h3 class="bpf-panel-title">🔐 <span data-i18n="stepVerification">ID-Verifizierung</span></h3>
<p class="muted" style="margin-bottom:1.5rem;">Bitte laden Sie einen gueltigen Ausweis sowie einen aktuellen Lohnzettel / Gehaltsnachweis hoch.</p>
<div class="bpf-field">
<label data-i18n="bpfIdUpload">Ausweis / Fuehrerschein *</label>
<div class="bpf-upload-box" id="uploadId">
<span class="bpf-upload-icon"></span>
<span data-i18n="bpfClickUpload">Klicken zum Hochladen</span>
<span class="muted" data-i18n="bpfUploadHint">PDF, JPG, PNG (max. 10 MB)</span>
<input type="file" accept="image/*,.pdf" class="bpf-file-input" id="bpfFileId" />
</div>
<p class="bpf-file-name" id="bpfFileIdName"></p>
</div>
<div class="bpf-field">
<label data-i18n="bpfIncomeUpload">Lohnzettel / Gehaltsnachweis *</label>
<div class="bpf-upload-box" id="uploadIncome">
<span class="bpf-upload-icon"></span>
<span data-i18n="bpfClickUpload">Klicken zum Hochladen</span>
<span class="muted" data-i18n="bpfUploadHint">PDF, JPG, PNG (max. 10 MB)</span>
<input type="file" accept="image/*,.pdf" class="bpf-file-input" id="bpfFileIncome" />
</div>
<p class="bpf-file-name" id="bpfFileIncomeName"></p>
</div>
<div class="bpf-notice">
<span></span>
<p data-i18n="bpfIdNotice">Ihre Dokumente werden vertraulich behandelt und dienen ausschliesslich der Identitaetsverifizierung.</p>
</div>
<div class="bpf-nav">
<button class="btn ghost" type="button" id="bpfBack3" data-i18n="bpfBack">Zurueck</button>
<button class="btn" type="button" id="bpfSubmit" data-i18n="bpfSubmit">Anfrage absenden</button>
</div>
</div>
</div>
</form>
<!-- Price sidebar -->
<aside class="bpf-sidebar" id="bpfSidebar">
<p class="bpf-sidebar-placeholder" data-i18n="bpfSelectForPrice">Waehle Fahrzeug und Datum fuer eine Preisuebersicht</p>
<div class="bpf-sidebar-content" id="bpfSidebarContent" style="display:none;"></div>
</aside>
</div>
<p id="bookingFeedback" class="form-feedback" role="status"></p>
</div>