// Kostenplaner.jsx — Step-flow für die unverbindliche Kostenorientierung
// Eine ruhige, klare Annäherung — keine Werbesprache, kein Druck.
/* ───────────── data ───────────── */
const ART = [
{ id:'feuer', name:'Feuerbestattung', sub:'Die häufigste Form. Sarg-Aussegnung, Einäscherung, Urnenbeisetzung.',
img:window._r('assets/photos/mourners-coffin.jpg'), from:2400, to:4400 },
{ id:'erde', name:'Erdbestattung', sub:'Klassischer Abschied im Sarg mit fester Grabstätte.',
img:window._r('assets/photos/grave-autumn.jpg'), from:4000, to:7200 },
{ id:'baum', name:'Baumbestattung', sub:'Naturnahe Urnen-Beisetzung im Wurzelbereich eines Baumes.',
img:window._r('assets/photos/cemetery-evening.jpg'), from:3500, to:6200 },
{ id:'see', name:'Seebestattung', sub:'Urnen-Beisetzung auf dem Wasser. Schlicht und würdevoll.',
img:window._r('assets/photos/sea-misty.jpg'), from:3300, to:5800 },
];
const FEIER = [
{ id:'keine', name:'Keine Trauerfeier', sub:'Schlichte Beisetzung im engsten Kreis.', from:0, to:0 },
{ id:'klein', name:'Im kleinen Kreis', sub:'Aussegnung am Sarg / der Urne — Familie & Nahestehende.', from:550, to:1100 },
{ id:'gross', name:'In der Trauerhalle', sub:'Größere Feier mit Musik, Rede und Empfang.', from:1400, to:2600 },
];
const SARG = [
{ id:'std', name:'Standard', sub:'Schlichte, hochwertige Ausführung.', from:0, to:0 },
{ id:'holz', name:'Naturholz', sub:'Eiche, Kiefer, Buche — unbehandelt.', from:400, to:850 },
{ id:'prem', name:'Edelholz', sub:'Edelholz, Innenausstattung, Beschläge.', from:950, to:1800 },
];
const URNE = [
{ id:'std', name:'Standard', sub:'Schlichte Naturholz-Urne.', from:0, to:0 },
{ id:'kera', name:'Keramik', sub:'Handgetöpferte Keramik-Urne.', from:180, to:380 },
{ id:'bio', name:'Bio-Urne', sub:'Naturmaterial, vollständig kompostierbar.', from:120, to:260 },
];
const EXTRAS = [
{ id:'aussegnung', name:'Aussegnung am Sarg / an der Urne', from:200, to:500 },
{ id:'druck', name:'Trauerdrucksachen (Karten, Anzeige)', from:180, to:450 },
{ id:'blumen', name:'Blumenschmuck (Sarg/Urne)', from:200, to:450 },
{ id:'beileid', name:'Beileidsblumen für Gäste', from:150, to:350 },
{ id:'gedenk', name:'Gedenkstein / Grabstein', from:1200, to:3500 },
{ id:'begleit', name:'Persönliche Trauerbegleitung im Nachgang', from:280, to:680 },
];
const eur = n => n.toLocaleString('de-DE', { style:'currency', currency:'EUR', maximumFractionDigits:0 });
function calcRange(state) {
let lo = 0, hi = 0;
const a = ART.find(x => x.id === state.art);
if (a) { lo += a.from; hi += a.to; }
const f = FEIER.find(x => x.id === state.feier);
if (f) { lo += f.from; hi += f.to; }
if (state.art === 'erde') {
const s = SARG.find(x => x.id === state.sarg);
if (s) { lo += s.from; hi += s.to; }
} else {
const u = URNE.find(x => x.id === state.urne);
if (u) { lo += u.from; hi += u.to; }
}
state.extras.forEach(id => {
const e = EXTRAS.find(x => x.id === id);
if (e) { lo += e.from; hi += e.to; }
});
return { lo, hi };
}
/* ───────────── radio card ───────────── */
function RadioCard({ checked, name, sub, right, onClick, img }) {
return (
{ if(!checked) e.currentTarget.style.borderColor = 'var(--ink-200)'; }}
onMouseLeave={e=>{ if(!checked) e.currentTarget.style.borderColor = 'var(--line)'; }}>
{img &&
}
{checked && }
{right &&
{right}
}
);
}
function CheckCard({ checked, name, right, onClick }) {
return (
{ if(!checked) e.currentTarget.style.borderColor = 'var(--ink-200)'; }}
onMouseLeave={e=>{ if(!checked) e.currentTarget.style.borderColor = 'var(--line)'; }}>
{checked && }
{name}
{right}
);
}
/* ───────────── step pages ───────────── */
function StepArt({ value, onChange }) {
return (
Schritt 1 von 4
Welche Bestattungsform haben Sie im Sinn?
Sie können in den nächsten Schritten noch alles anpassen. Falls Sie unsicher sind, beraten wir Sie gern persönlich.
{ART.map(a => (
ab {eur(a.from)}>}
onClick={()=>onChange(a.id)}/>
))}
);
}
function StepFeier({ value, onChange }) {
return (
Schritt 2 von 4
Wie möchten Sie Abschied nehmen?
Eine Trauerfeier kann ganz schlicht im Kreis der Nahestehenden stattfinden — oder größer mit Musik und Rede in unserer Trauerhalle.
{FEIER.map(f => (
+ {eur(f.from)}>}
onClick={()=>onChange(f.id)}/>
))}
);
}
function StepBehältnis({ state, onChange }) {
const isErd = state.art === 'erde';
const opts = isErd ? SARG : URNE;
const key = isErd ? 'sarg' : 'urne';
const title = isErd ? 'Sarg' : 'Urne';
return (
Schritt 3 von 4
{title} nach Ihrem Wunsch.
Wir führen ein ruhiges Sortiment — von schlichten Naturholzausführungen bis hin zu hochwertigen Modellen. Eine Auswahl zur ersten Orientierung.
{opts.map(o => (
+ {eur(o.from)}>}
onClick={()=>onChange(key, o.id)}/>
))}
);
}
function StepExtras({ value, onToggle }) {
return (
Schritt 4 von 4
Begleitende Leistungen.
Wählen Sie aus, was zu Ihrer Vorstellung passt — Sie können jederzeit etwas hinzufügen oder weglassen. Nichts davon ist verpflichtend.
{EXTRAS.map(e => (
+ {eur(e.from)} – {eur(e.to)}>}
onClick={()=>onToggle(e.id)}/>
))}
);
}
function Summary({ state, onAnfrage, onRestart }) {
const { lo, hi } = calcRange(state);
const art = ART.find(x=>x.id===state.art);
const feier= FEIER.find(x=>x.id===state.feier);
const beh = state.art==='erde' ? SARG.find(x=>x.id===state.sarg) : URNE.find(x=>x.id===state.urne);
const extras = EXTRAS.filter(e => state.extras.includes(e.id));
return (
Ihre Auswahl
Eine erste Orientierung.
Dies ist eine Schätzung auf Basis Ihrer Angaben — kein verbindliches Angebot. Das verbindliche Angebot erstellen wir transparent im persönlichen Gespräch.
Geschätzte Gesamtkosten
{eur(lo)} – {eur(hi)}
Inklusive aller von Ihnen ausgewählten Leistungen. Friedhofsgebühren und kommunale Kosten kommen je nach Ort hinzu.
{[
{ k:'Bestattungsform', v: art ? `${art.name}` : '—', range: art && `${eur(art.from)} – ${eur(art.to)}` },
{ k:'Abschied', v: feier ? feier.name : '—', range: feier && (feier.from===0 ? '— inklusive' : `+ ${eur(feier.from)} – ${eur(feier.to)}`) },
{ k: state.art==='erde' ? 'Sarg' : 'Urne', v: beh ? beh.name : '—', range: beh && (beh.from===0 ? '— inklusive' : `+ ${eur(beh.from)} – ${eur(beh.to)}`) },
...extras.map(e => ({ k:'Zusatzleistung', v:e.name, range:`+ ${eur(e.from)} – ${eur(e.to)}` })),
].map((r, i, a) => (
{r.k}
{r.v}
{r.range}
))}
{extras.length === 0 && (
Keine Zusatzleistungen ausgewählt.
)}
Ein verbindliches Angebot im persönlichen Gespräch.
Sie senden uns Ihre Auswahl, wir erstellen Ihr verbindliches Angebot — transparent, ohne Verpflichtung. Erreichbar unter 05361 · 4 22 22.
{e.currentTarget.style.background='var(--accent-vorsorge-ink)';e.currentTarget.style.borderColor='var(--accent-vorsorge-ink)'}}
onMouseLeave={e=>{e.currentTarget.style.background='var(--accent-vorsorge)';e.currentTarget.style.borderColor='var(--accent-vorsorge)'}}>
Beratung anfragen
Auswahl zurücksetzen
);
}
/* ───────────── left rail: progress + live total ───────────── */
function Sidebar({ step, state, totalSteps }) {
const { lo, hi } = calcRange(state);
const stepLabels = ['Bestattungsform', 'Abschied', state.art==='erde' ? 'Sarg' : 'Urne', 'Zusatzleistungen'];
return (
Kostenplaner
In vier Schritten zu einem Kostenrahmen.
{stepLabels.map((l, i) => {
const done = i < step;
const active = i === step;
return (
);
})}
Aktueller Zwischenstand
{lo === 0 ? '—' : <>{eur(lo)} – {eur(hi)}>}
Schätzung. Friedhofsgebühren je nach Ort zusätzlich.
Lieber persönlich besprechen?
05361 · 4 22 22
Tag & Nacht erreichbar
);
}
/* ───────────── main: KostenplanerSection ───────────── */
function KostenplanerSection({ onAnfrage, onBack, embedded = false }) {
const [step, setStep] = React.useState(0);
const [state, setState] = React.useState({
art:'feuer', feier:'klein', sarg:'std', urne:'std', extras:['aussegnung','druck'],
});
const update = (k, v) => setState(s => ({ ...s, [k]:v }));
const toggleExtra = id => setState(s => ({ ...s, extras: s.extras.includes(id) ? s.extras.filter(x=>x!==id) : [...s.extras, id] }));
const reset = () => { setState({ art:'feuer', feier:'klein', sarg:'std', urne:'std', extras:['aussegnung','druck'] }); setStep(0); };
const totalSteps = 4;
const onSummary = step >= totalSteps;
return (
<>
{!embedded && (
<>
{/* Hero — gleiche Höhe wie alle Unterseiten (--hero-page-h) */}
Ihren Kostenrahmen selbst ermitteln.
In vier Schritten wählen Sie Bestattungsform, Abschied und Zusatzleistungen. Sie erhalten eine erste Orientierung — unverbindlich, ohne Anmeldung.
{/* Breadcrumb */}
>
)}
{!onSummary && step===0 && update('art', v)}/>}
{!onSummary && step===1 && update('feier', v)}/>}
{!onSummary && step===2 && }
{!onSummary && step===3 && }
{onSummary && }
{!onSummary && (
setStep(s => Math.max(0, s-1))}
disabled={step===0}
style={{
all:'unset',
cursor: step===0 ? 'default' : 'pointer',
opacity: step===0 ? .35 : 1,
font:'500 11px/1 var(--f-body)', letterSpacing:'var(--ls-caps)', textTransform:'uppercase',
color:'var(--ink-500)', padding:'14px 0',
}}>← Zurück
setStep(s => s+1)} style={{
all:'unset', cursor:'pointer',
font:'500 11px/1 var(--f-body)', letterSpacing:'var(--ls-caps)', textTransform:'uppercase',
padding:'14px 26px', background:'var(--accent-vorsorge)', color:'#fff',
border:'2px solid var(--accent-vorsorge)', transition:'background .18s, border-color .18s',
}}
onMouseEnter={e=>{e.currentTarget.style.background='var(--accent-vorsorge-ink)';e.currentTarget.style.borderColor='var(--accent-vorsorge-ink)'}}
onMouseLeave={e=>{e.currentTarget.style.background='var(--accent-vorsorge)';e.currentTarget.style.borderColor='var(--accent-vorsorge)'}}>
{step === totalSteps - 1 ? 'Zur Übersicht →' : 'Weiter →'}
)}
>
);
}
Object.assign(window, { KostenplanerSection });