Files
mc_cars_gmbh_infraestructure/frontend/admin.html
T
Lago 8be7d5aad2 feat: implement Marco's customer changes
- Remove 'Flotte ansehen' button from hero section
- Remove '24/7 Support' stat from hero section
- Remove 'Unsere Flotte' eyebrow from fleet section
- Remove ALL 'Warum wir' / 'Why us' references from nav links, i18n keys, and legal pages
- Update reviews: Ferrari references only (removed GT3 mentions)
- Update Impressum with correct company data (MC Cars GmbH)
- Add multi-photo gallery: DB migration (17-vehicle-photos.sql), admin UI for photo management, frontend carousel on cards and dialog
- Update SEO: Ferrari-focused meta tags, title, keywords, JSON-LD
- Clean up dead i18n keys (viewFleet, statSupport, fleetEyebrow, navWhy, why* keys)
- Fix legal page issues: add config.js script, fix logo references to SVG
- Add Playwright E2E tests (26/26 passing)
- Update footer tagline across all pages
2026-05-31 09:53:23 +02:00

322 lines
18 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Admin · MC Cars</title>
<link rel="icon" type="image/svg+xml" href="/images/MC-Cars-Logo.svg" />
<link rel="apple-touch-icon" href="/images/MC-Cars-Logo.svg" />
<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" />
<link rel="stylesheet" href="styles.css" />
<script>document.write('<scr'+'ipt src="config.js?v='+Date.now()+'"><\/scr'+'ipt>')</script>
<meta name="robots" content="noindex, nofollow" />
<meta name="description" content="MC Cars Admin Panel - Not for public access" />
</head>
<body>
<!-- Login -->
<section id="loginView" class="admin-login" style="display:none;">
<div class="logo" style="justify-content:center;margin-bottom:1.5rem;">
<img src="/images/MC-Cars-Logo.svg" alt="MC Cars" class="logo-icon" />
<span>MC Cars Admin</span>
</div>
<form id="loginForm" class="admin-form">
<label>
<span>E-Mail</span>
<input type="email" name="email" required autocomplete="username" />
</label>
<label>
<span>Passwort</span>
<input type="password" name="password" required autocomplete="current-password" />
</label>
<button class="btn" type="submit">Anmelden</button>
<p class="form-feedback error" id="loginError"></p>
<p style="color:var(--muted);font-size:0.82rem;text-align:center;">
Nur für Administratoren. Selbstregistrierung ist deaktiviert.
</p>
</form>
</section>
<!-- Forced password rotation (first login OR user-triggered) -->
<section id="rotateView" class="admin-login" style="display:none;">
<div class="logo" style="justify-content:center;margin-bottom:1rem;">
<img src="/images/MC-Cars-Logo.svg" alt="MC Cars" class="logo-icon" />
<span>Passwort setzen</span>
</div>
<p style="color:var(--muted);font-size:0.9rem;text-align:center;max-width:38ch;margin:0 auto 1rem;">
Das Bootstrap-Passwort muss ersetzt werden. Das neue Passwort muss sich vom
Start-Passwort unterscheiden.
</p>
<form id="rotateForm" class="admin-form">
<label>
<span>Neues Passwort (mind. 10 Zeichen)</span>
<input type="password" name="pw1" minlength="10" required autocomplete="new-password" />
</label>
<label>
<span>Wiederholen</span>
<input type="password" name="pw2" minlength="10" required autocomplete="new-password" />
</label>
<button class="btn" type="submit">Speichern</button>
<p class="form-feedback error" id="rotateError"></p>
</form>
</section>
<!-- Admin -->
<section id="adminView" class="admin-page" style="display:none;">
<div class="admin-bar">
<h1>MC Cars · Admin</h1>
<div style="display:flex;gap:0.6rem;align-items:center;flex-wrap:wrap;">
<a id="websiteLink" href="/index.html" target="_blank" class="btn ghost small" data-i18n="adminNavWebsite">Website</a>
<button class="lang-toggle" type="button" aria-label="Sprache wechseln" style="margin-left:auto;">EN</button>
<span id="adminWho" style="color:var(--muted);font-size:0.85rem;margin-left:1rem;"></span>
<button id="changePwBtn" class="btn ghost small" data-i18n="adminChangePw">Passwort ändern</button>
<button id="logoutBtn" class="btn small" data-i18n="adminLogout">Logout</button>
</div>
</div>
<!-- Tabs -->
<div class="admin-tabs" role="tablist">
<button class="tab active" data-tab="leads" role="tab"><span data-i18n="adminLeads">Leads</span> <span id="leadsBadge" class="tab-badge">0</span></button>
<button class="tab" data-tab="customers" role="tab"><span data-i18n="adminCustomers">Kunden</span> <span id="customersBadge" class="tab-badge">0</span></button>
<button class="tab" data-tab="orders" role="tab"><span data-i18n="adminTabOrderHistory">Bestellungen</span> <span id="ordersBadge" class="tab-badge">0</span></button>
<button class="tab" data-tab="vehicles" role="tab" data-i18n="adminVehicles">Fahrzeuge</button>
<button class="tab" data-tab="settings" role="tab" data-i18n="adminSettings">Einstellungen</button>
</div>
<!-- LEADS -->
<div class="tab-panel" id="tab-leads">
<div class="panel">
<div style="display:flex;justify-content:space-between;align-items:center;gap:1rem;flex-wrap:wrap;margin-bottom:1rem;">
<h2 style="margin:0;">Leads</h2>
<div class="sub-tabs" role="tablist">
<button class="sub-tab active" data-lview="active" data-i18n="adminActiveLeads">Aktive Leads</button>
<button class="sub-tab" data-lview="inactive" data-i18n="adminClosedLeads">Abgeschlossen</button>
</div>
</div>
<table class="admin-table" id="leadsTable">
<thead>
<tr>
<th data-i18n="adminReceived">Eingang</th>
<th data-i18n="adminNameEmail">Name / E-Mail</th>
<th data-i18n="adminVehicleTab">Fahrzeug</th>
<th data-i18n="adminPeriod">Zeitraum</th>
<th data-i18n="adminRentalType">Miettyp</th>
<th data-i18n="adminTotalPrice">Gesamtbetrag</th>
<th data-i18n="adminStatus">Status</th>
<th></th>
</tr>
</thead>
<tbody></tbody>
</table>
<p id="leadsEmpty" class="muted" style="display:none;text-align:center;padding:2rem 0;">Keine Leads in dieser Ansicht.</p>
</div>
</div>
<!-- CUSTOMERS -->
<div class="tab-panel" id="tab-customers" style="display:none;">
<div class="panel">
<h2>Kunden</h2>
<p class="muted" style="margin-top:-0.4rem;">Entstehen automatisch, sobald ein Lead qualifiziert wird. Die Quelle bleibt als <code>lead_id</code> verknüpft.</p>
<table class="admin-table" id="customersTable">
<thead>
<tr>
<th data-i18n="adminFirstContact">Erster Kontakt</th>
<th data-i18n="adminNameEmail">Name / E-Mail</th>
<th data-i18n="adminPhone">Telefon</th>
<th data-i18n="adminSourceLead">Quelle (Lead)</th>
<th data-i18n="adminLifetimeValueCol">Gesamtwert</th>
<th data-i18n="adminStatus">Status</th>
<th></th>
</tr>
</thead>
<tbody></tbody>
</table>
<p id="customersEmpty" class="muted" style="display:none;text-align:center;padding:2rem 0;">Noch keine Kunden.</p>
</div>
</div>
<!-- SALES ORDERS -->
<div class="tab-panel" id="tab-orders" style="display:none;">
<div class="panel">
<h2 data-i18n="adminTabOrderHistory">Bestellungen</h2>
<table class="admin-table" id="ordersTable">
<thead>
<tr>
<th>Nr.</th>
<th data-i18n="adminNameEmail">Name / E-Mail</th>
<th data-i18n="adminVehicleTab">Fahrzeug</th>
<th data-i18n="adminPeriod">Zeitraum</th>
<th data-i18n="adminRentalType">Miettyp</th>
<th data-i18n="adminTotalPrice">Gesamtbetrag</th>
<th>Kaution</th>
<th>Miete</th>
<th data-i18n="adminStatus">Status</th>
<th data-i18n="adminEmailSent">Email</th>
<th></th>
</tr>
</thead>
<tbody></tbody>
</table>
<p id="ordersEmpty" class="muted" style="display:none;text-align:center;padding:2rem 0;">Keine Bestellungen.</p>
</div>
</div>
<!-- VEHICLES -->
<div class="tab-panel" id="tab-vehicles" style="display:none;">
<div class="admin-grid">
<div class="panel">
<h2 id="formTitle" data-i18n="adminNewVehicle">Neues Fahrzeug</h2>
<form class="admin-form" id="vehicleForm">
<input type="hidden" name="vid" />
<div class="admin-photo-preview" id="photoPreview"></div>
<label>
<span data-i18n="adminPhotoUpload">Hauptfoto hochladen (JPG/PNG/WebP, max 50 MB)</span>
<input type="file" id="photoInput" accept="image/*" />
</label>
<input type="hidden" name="photo_url" />
<div style="margin-top:1.2rem;">
<label>
<span>Weitere Fotos hinzufügen</span>
<input type="file" id="extraPhotoInput" accept="image/*" multiple />
</label>
<div id="extraPhotoGallery" style="display:grid;grid-template-columns:repeat(auto-fill,minmax(100px,1fr));gap:0.5rem;margin-top:0.5rem;"></div>
</div>
<div class="row2">
<label><span data-i18n="adminBrand">Marke</span><input name="brand" required /></label>
<label><span data-i18n="adminModel">Modell</span><input name="model" required /></label>
</div>
<div class="row3">
<label><span data-i18n="adminPower">PS</span><input type="number" name="power_hp" min="0" /></label>
<label><span data-i18n="adminSpeed">Top-Speed km/h</span><input type="number" name="top_speed_kmh" min="0" /></label>
<label><span data-i18n="adminAccel">0-100</span><input name="acceleration" placeholder="3.2s" /></label>
</div>
<div class="row3">
<label><span data-i18n="adminSeats">Sitze</span><input type="number" name="seats" min="1" value="2" /></label>
<label><span data-i18n="adminPrice">Preis / Tag (€)</span><input type="number" name="daily_price_eur" min="0" required /></label>
<label><span>Wochenendpreis (€)</span><input type="number" name="weekend_price_eur" min="0" /></label>
</div>
<div class="row3">
<label><span>Inkl. km/Tag</span><input type="number" name="included_km_per_day" min="0" value="150" /></label>
<label><span data-i18n="adminPricePerKm">Preis extra km (€)</span><input type="number" name="price_per_km_eur" step="0.01" min="0" value="1.50" /></label>
<label><span data-i18n="adminKaution">Kaution (€)</span><input type="number" name="kaution_eur" min="1" value="5000" required /></label>
</div>
<div class="row2">
<label><span data-i18n="adminSortOrder">Ordnung</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>
<label>
<span data-i18n="adminDescDe">Beschreibung (Deutsch)</span>
<textarea name="description_de" rows="3"></textarea>
</label>
<label>
<span data-i18n="adminDescEn">Description (English)</span>
<textarea name="description_en" rows="3"></textarea>
</label>
<label style="flex-direction:row;align-items:center;gap:0.8rem;margin-top:0.5rem;cursor:pointer;">
<div class="toggle-switch">
<input type="checkbox" name="is_active" id="isActiveCheck" checked />
<span class="toggle-slider"></span>
</div>
<span data-i18n="adminActiveVisible" style="user-select:none;">Aktiv / auf Website sichtbar</span>
</label>
<div style="display:flex;gap:0.5rem;margin-top:1rem;">
<button class="btn" type="submit" id="saveBtn" data-i18n="adminSave">Speichern</button>
<button class="btn ghost" type="button" id="resetBtn" data-i18n="adminReset">Neu</button>
</div>
<p class="form-feedback" id="formFeedback"></p>
</form>
</div>
<div class="panel">
<h2 data-i18n="adminAllVehicles">Alle Fahrzeuge</h2>
<table class="admin-table" id="adminTable">
<thead>
<tr>
<th data-i18n="adminPhoto">Foto</th>
<th data-i18n="adminBrandTable">Marke / Modell</th>
<th data-i18n="adminPriceTable">€ / Tag</th>
<th data-i18n="adminActive">Aktiv</th>
<th></th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
</div>
<!-- SETTINGS -->
<div class="tab-panel" id="tab-settings" style="display:none;">
<div class="panel" style="max-width:600px;">
<h2 data-i18n="adminSettings">Einstellungen</h2>
<div class="admin-form">
<label>
<span data-i18n="adminHeroImage">Hauptbild (Hero-Bereich)</span>
<div class="admin-photo-preview" id="heroPreview" style="aspect-ratio:21/9;"></div>
<input type="file" id="heroImageInput" accept="image/jpeg,image/png,image/webp" />
</label>
<p class="muted" style="font-size:0.82rem;" data-i18n="adminHeroImageHint">JPG/PNG/WebP. Wird als Hintergrundbild im Hero-Bereich der Website angezeigt.</p>
<p class="form-feedback" id="heroFeedback"></p>
</div>
<hr style="margin:2rem 0;border-color:var(--border);" />
<div class="admin-form">
<label>
<span data-i18n="adminMietvertragTemplate">Mietvertrag-Vorlage (DOCX)</span>
<div id="mietvertragStatus" class="muted" style="font-size:0.9rem;margin:0.5rem 0;"></div>
<input type="file" id="mietvertragInput" accept="application/vnd.openxmlformats-officedocument.wordprocessingml.document,.docx" />
</label>
<p class="muted" style="font-size:0.82rem;" data-i18n="adminMietvertragHint">DOCX-Vorlage mit Platzhaltern. Wird bei Qualifizierung automatisch ausgefüllt und als PDF per E-Mail versendet.</p>
<p class="form-feedback" id="mietvertragFeedback"></p>
</div>
</div>
</div>
</section>
<!-- Order detail dialog -->
<dialog id="orderDialog">
<div class="dialog-head">
<h3 id="orderDialogTitle" style="margin:0;">Bestellung</h3>
<button class="dialog-close" id="orderDialogClose" aria-label="Close">×</button>
</div>
<div class="dialog-tabs" id="orderDialogTabs" role="tablist"></div>
<div class="dialog-body" id="orderDialogBody"></div>
<div class="dialog-footer" id="orderDialogFooter"></div>
</dialog>
<!-- Lead detail / qualify dialog (tabbed) -->
<dialog id="leadDialog">
<div class="dialog-head">
<h3 id="leadDialogTitle" style="margin:0;">Lead</h3>
<button class="dialog-close" id="leadDialogClose" aria-label="Close">×</button>
</div>
<div class="dialog-tabs" id="leadDialogTabs" role="tablist"></div>
<div class="dialog-body" id="leadDialogBody"></div>
<div class="dialog-footer" id="leadDialogFooter"></div>
</dialog>
<!-- Customer detail dialog (tabbed) -->
<dialog id="customerDialog">
<div class="dialog-head">
<h3 id="customerDialogTitle" style="margin:0;">Kunde</h3>
<button class="dialog-close" id="customerDialogClose" aria-label="Close">×</button>
</div>
<div class="dialog-tabs" id="customerDialogTabs" role="tablist"></div>
<div class="dialog-body" id="customerDialogBody"></div>
<div class="dialog-footer" id="customerDialogFooter"></div>
</dialog>
<script type="module" src="admin.js?v=3"></script>
</body>
</html>