/* global React, Icon, chf, SpecPills */
// ACN-Cars · Page: Vehicle Detail
// v2.2.13 — Deal-Badge auf Detail-Seite hinzugefügt, gleiche Max-Rabatt-
// Berechnung wie VehicleCard, damit der Badge zwischen Grid und
// Detail-Seite identisch ist.
// v2.2.16 — Galerie korrekt aus v.gallery (statt 4× Hero-Bild) +
// Aktion-Kontext-Banner: wenn man aus einer Aktion kommt, zeigt die
// Detail-Seite die Aktion (Titel, Countdown, Aktions-Preis,
// „Mit Aktion buchen"-CTA) statt nur den generischen Default.
// v2.2.17 — Tier-Picker (3 Std / 6 Std / 1 Tag / 1 Woche) wie auf der
// VehicleCard: 4 Pills direkt unter dem Hauptpreis, Klick auf eine
// Pille → Hauptpreis + alter Preis + „Jetzt buchen" updaten live,
// Buchen-Flow erhält die gewählte Mietdauer (`activeTier`). Bei
// Aktion-Kontext wird der Picker ausgeblendet (Aktion bestimmt den
// Preis). Vorteils-Bullets unter den CTAs sind jetzt vom Backend
// steuerbar (3 fixe Felder mit Toggle in „Erscheinungsbild").
function DetailPage({ vehicle, deal, contact, onBook, onDealBook, onBack, onCompare, comparing, fav, onFav }) {
// Index für Galerie — Klick auf Thumbnail wechselt das Hauptbild.
const [activeImg, setActiveImg] = React.useState(0);
if (!vehicle) {
return (
Kein Fahrzeug ausgewählt.
);
}
const v = vehicle;
// v2.2.16 — Galerie-Bilder de-duplizieren. Wenn nur 1 Bild da ist,
// Thumbnail-Strip ausblenden.
const galleryImages = (() => {
const arr = [v.image, ...((v.gallery && Array.isArray(v.gallery)) ? v.gallery : [])]
.filter(Boolean);
return Array.from(new Set(arr));
})();
const heroImage = galleryImages[Math.min(activeImg, galleryImages.length - 1)] || v.image;
// v2.2.13 / v2.2.17 — Tier-Picker + identische Max-Rabatt-Berechnung wie in
// VehicleCard (so dass Card-Badge und Detail-Badge synchron bleiben).
const tierOldPrices = v.tierOldPrices || {};
const tp = v.tierPrices || {};
// Volle Tier-Defs inkl. Label/Per für die Pill-UI (s. VehicleCard).
const tierDefs = [
{ hours: 3, label: "3 Std", short: "3h", per: "/3 Std", price: tp["3"] },
{ hours: 6, label: "6 Std", short: "6h", per: "/6 Std", price: tp["6"] },
{ hours: 24, label: "1 Tag", short: "1d", per: "/Tag", price: tp["24"] || v.pricePerDay },
{ hours: 48, label: "2 Tage", short: "2d", per: "/2 Tage", price: tp["48"] }, // v2.2.37
{ hours: 168, label: "1 Woche", short: "1w", per: "/Woche", price: tp["168"] },
].filter(t => t.price && t.price > 0);
// Default-Auswahl: günstigster absoluter Preis (entspricht der Card-Logik
// ab v2.2.11), so dass Kund:innen den niedrigsten Einstiegspreis sehen.
const defaultIdx = tierDefs.length
? tierDefs.reduce((minI, t, i, arr) => (t.price < arr[minI].price ? i : minI), 0)
: 0;
const [tierIdx, setTierIdx] = React.useState(defaultIdx);
const activeTierDef = tierDefs[tierIdx] || null;
const activeTier = activeTierDef ? activeTierDef.hours : null;
const showTierPicker = tierDefs.length > 1;
const displayPrice = activeTierDef ? activeTierDef.price : v.pricePerDay;
const displayPer = activeTierDef ? activeTierDef.per : "/Tag";
// Tier-aware alter Preis (wie in VehicleCard).
const activeOldPrice = activeTier
? (tierOldPrices[String(activeTier)] && tierOldPrices[String(activeTier)] > 0
? Number(tierOldPrices[String(activeTier)])
: (activeTier === 24 ? (v.oldPrice || 0) : 0))
: (v.oldPrice || 0);
const tierHasDeal = activeOldPrice > 0 && activeOldPrice > displayPrice;
const allDealPcts = [];
if (v.oldPrice && v.oldPrice > v.pricePerDay && v.pricePerDay > 0) {
allDealPcts.push(Math.round((1 - v.pricePerDay / v.oldPrice) * 100));
}
if (typeof v.dealPct === "number" && v.dealPct > 0) {
allDealPcts.push(v.dealPct);
}
tierDefs.forEach(td => {
const op = tierOldPrices[String(td.hours)];
if (op && Number(op) > 0 && Number(op) > td.price && td.price > 0) {
allDealPcts.push(Math.round((1 - td.price / Number(op)) * 100));
}
});
const dealPct = allDealPcts.length ? Math.max.apply(null, allDealPcts) : 0;
const hasDeal = dealPct > 0;
// v2.2.16 — Aktion-Kontext: wenn aus einer Aktion gekommen, Aktions-
// spezifische Daten berechnen.
// v2.2.44 — Hint-Modus: wenn der User aus der unteren Flotte (NICHT aus einer
// Aktion-Karte) auf das Auto kommt, übergibt HomePage `{...deal, __hint:true}`.
// Dann zeigen wir die Aktion nur als Hinweis-Streifen, NICHT als Default —
// der User kann frei zwischen normalem Tier-Buchungs-Flow und Aktion wählen.
const isHintMode = !!(deal && typeof deal === "object" && deal.__hint);
const ctx = (deal && typeof deal === "object" && !deal.__hint) ? deal : null;
const hint = isHintMode ? deal : null;
let ctxPrice = null; // Aktions-Preis (Tagespreis oder Wochenend-Pauschale)
let ctxOldPrice = null; // Original-Preis
let ctxPriceLabel = "/Tag";
let ctxBadge = null; // z. B. „−20%" oder „Weekend-Pauschale"
if (ctx) {
if (ctx.isWeekend && ctx.weekend) {
const vp = ctx.weekend.vehiclePrices && typeof ctx.weekend.vehiclePrices === "object"
? ctx.weekend.vehiclePrices : {};
const vehiclePrice = vp[v.id] && Number(vp[v.id]) > 0
? Number(vp[v.id])
: (ctx.weekend.price > 0 ? Number(ctx.weekend.price) : 0);
if (vehiclePrice > 0) {
ctxPrice = vehiclePrice;
ctxPriceLabel = "Pauschale";
ctxBadge = "Weekend-Pauschale";
}
} else if (ctx.discount && Number(ctx.discount) > 0) {
const pct = Number(ctx.discount);
ctxOldPrice = v.pricePerDay;
ctxPrice = Math.round(v.pricePerDay * (1 - pct / 100));
ctxBadge = `−${pct}%`;
}
}
const handleBook = () => {
// v2.2.23 — Bugfix: Wenn der User auf der Detail-Seite einen Kurz-Tier
// (3h / 6h / 24h) gewählt hat, NICHT in den Weekend-Deal-Flow umleiten.
// Weekend-Modus nur via expliziten Weekend-Button oder Weekend-Datum.
// Bei prozentualen %-Aktionen bleibt der bisherige Aktion-Flow erhalten,
// weil dort kein Datum gelockt wird — nur ein Rabatt vorbelegt.
const isWeekendCtx = !!(ctx && ctx.isWeekend);
const pickedShortTier = activeTier && activeTier > 0 && activeTier < 168;
if (ctx && typeof onDealBook === "function" && !(isWeekendCtx && pickedShortTier)) {
onDealBook(ctx);
return;
}
// v2.2.17 — Buchen-Flow erhält die ausgewählte Mietdauer (Stunden), so
// dass das Buchungsformular Standardwerte richtig vorbelegt.
onBook(v, activeTier);
};
// v2.2.17 — Vorteils-Bullets aus Backend (Erscheinungsbild → Detail-Seite
// Bullets). Fallback auf alte Hardcoded-Texte, falls boot-Daten fehlen.
const bootDetailBullets = (typeof window !== "undefined"
&& window.ACN_DATA && window.ACN_DATA.boot && Array.isArray(window.ACN_DATA.boot.detailBullets))
? window.ACN_DATA.boot.detailBullets
: null;
const detailBullets = bootDetailBullets && bootDetailBullets.length
? bootDetailBullets.filter(b => b && b.text && (b.enabled === undefined || b.enabled))
: [
{ text: "Vollkasko ohne Selbstbehalt verfügbar", enabled: 1 },
{ text: "Lieferung nach Zürich Flughafen kostenlos", enabled: 1 },
{ text: "Kostenlose Stornierung bis 24h vorher", enabled: 1 },
];
return (
{hintPrice > 0
? <>Mit dieser Aktion ab CHF {chf(hintPrice)} {hintLabel}.>
: <>Sonderkonditionen für dieses Fahrzeug.>}
{" "}Sonst regulär nach Mietdauer buchen.