"use client"; // Das Popup eines Assistenten-Schritts. // // Immer gleich aufgebaut: SEITE 1 erklärt, worum es geht -- welche Fragen man sich stellt, // welche Möglichkeiten das Tool bietet, worauf es ankommt. Erst danach folgt das Werkzeug. // // Warum die Erklärseite nicht übersprungen wird: Finanzplanung scheitert selten an der // Bedienung und fast immer daran, dass unklar ist, was der Schritt eigentlich bezweckt. Wer // es schon weiss, klickt unten links auf «Selbst erledigen» und ist in zwei Sekunden draussen. import { useState } from "react"; import { ArrowLeft, ArrowRight, Check, Lock } from "lucide-react"; import { Button, Modal, useConfirm } from "@/components/ui"; import { ASSISTANT_STEPS, stepBlockedReason } from "@/lib/assistant"; import type { PlanInput } from "@/lib/types"; export interface StepExplainer { // Kurze Einordnung ganz oben. lead: string; // Die Fragen, die dieser Schritt beantwortet. questions: string[]; // Was man wissen sollte, bevor man loslegt. notes: { title: string; text: string }[]; } export const STEP_EXPLAINERS: StepExplainer[] = [ { lead: "Bevor du planst, hältst du fest, was heute da ist. Alles Weitere baut darauf auf – ohne Bestandsaufnahme rechnet das Tool ins Leere.", questions: [ "Was verdienst du, was gibst du aus?", "Welche Guthaben hast du – Pensionskasse, Säule 3a, Wertschriften, Konto?", "Besitzt du Wohneigentum? Wie hoch ist die Hypothek?", "Hast du Schulden ausserhalb der Hypothek?", ], notes: [ { title: "Nur Tatsachen, noch keine Annahmen", text: "Hier stehen Zahlen, die du nachschlagen kannst: Kontostand, Guthaben, Kaufpreis, Restschuld. Renditen, Lohnentwicklung und Sparraten kommen im nächsten Schritt – sie sind Annahmen und gelten immer nur für einen Zeitraum.", }, { title: "Lieber grob als gar nicht", text: "Ein geschätzter Wert ist besser als ein leeres Feld. Du kannst jede Zahl später überall im Tool korrigieren.", }, { title: "Getrennt nach Person", text: "Pensionskasse und Säule 3a gehören immer einer Person. Wertschriften, Immobilien und Schulden können gemeinsam sein.", }, ], }, { lead: "Eine Lebensphase ist ein Abschnitt, in dem die Verhältnisse ungefähr gleich bleiben: ähnliches Einkommen, ähnliche Ausgaben, dieselben Annahmen. Jetzt legst du die erste an.", questions: [ "Wie lange bleiben deine Verhältnisse ungefähr so wie heute?", "Womit rechnest du in dieser Zeit – Renditen, Lohnentwicklung, Teuerung?", "Wohin fliesst das Geld, das am Ende des Jahres übrig bleibt?", ], notes: [ { title: "Was eine Lebensphase zusammenhält", text: "Nicht ein Kalenderabschnitt, sondern eine Konstellation: Solange du gleich viel verdienst, ähnlich viel ausgibst und dieselben Annahmen gelten, ist es eine Phase. Ändert sich etwas grundlegend – ein Hauskauf, Teilzeit, die Pensionierung – beginnt eine neue.", }, { title: "Annahmen gelten pro Phase", text: "Die Rendite, die du hier einträgst, gilt nur für diese Jahre. In einer späteren Phase kannst du eine andere setzen – etwa vorsichtiger, wenn du im Ruhestand anders anlegst.", }, { title: "Der Rest bleibt auf dem Konto", text: "Am Schluss verteilst du deinen Sparbetrag. Was du nicht zuteilst, sammelt sich als Cash an – rechnerisch richtig, aber meist nicht die Absicht.", }, { title: "Bis zur Pensionierung", text: "Im Basisszenario wird mit Pensionsalter 65 gerechnet. Eine Lebensphase darf diesen Zeitpunkt nicht überspannen – FPT begrenzt die Dauer deshalb automatisch.", }, ], }, ]; export function AssistantStepDialog({ plan, stepIndex, isDone, onToggleDone, onClose, // Gibt es ungespeicherte Eingaben? Der Dialog fragt dann beim Schliessen nach, statt sie // still zu verwerfen -- ohne Speichern-Knopf je Feld wäre das sonst die einzige Stelle, // an der Arbeit verloren gehen kann. dirty = false, // Wird beim Abschliessen aufgerufen und schreibt, was das Werkzeug gesammelt hat. onCommit, children, }: { plan: PlanInput; stepIndex: number; isDone: boolean; onToggleDone: (done: boolean) => void; onClose: () => void; dirty?: boolean; onCommit?: () => Promise; // Das Werkzeug des Schritts. Fehlt es, ist der Schritt reine Information. children?: React.ReactNode; }) { const step = ASSISTANT_STEPS[stepIndex]; const explainer = STEP_EXPLAINERS[stepIndex]; const blocked = stepBlockedReason(plan, stepIndex); const [showTool, setShowTool] = useState(false); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); const confirm = useConfirm(); const canGuide = step.guided && !blocked && !!children; // Schliessen mit ungespeicherten Eingaben: nachfragen statt still verwerfen. async function closeGuarded() { if (!dirty) return onClose(); const ok = await confirm({ title: "Eingaben verwerfen?", message: "Du hast Angaben erfasst, die noch nicht gespeichert sind. Schliesst du jetzt, gehen sie verloren. " + "Mit «Schritt abschliessen» werden sie übernommen.", confirmLabel: "Verwerfen", danger: true, }); if (ok) onClose(); } async function finish() { setSaving(true); setError(null); try { if (onCommit) await onCommit(); onToggleDone(true); onClose(); } catch (e) { setError(e instanceof Error ? e.message : "Speichern fehlgeschlagen."); } finally { setSaving(false); } } return ( {showTool ? (
{children} {error &&

{error}

}
) : (

{explainer.lead}

{explainer.questions.length > 0 && (

Diese Fragen beantwortest du hier

    {explainer.questions.map((q) => (
  • {q}
  • ))}
)}
{explainer.notes.map((n) => (

{n.title}

{n.text}

))}
{blocked && (

{blocked}

)}
{canGuide ? ( ) : ( )}
)}
); }