Szenario-Screen mit vier Kacheln, FPT-Assistent, Onboarding auf einen Knopf
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,297 @@
|
||||
"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 } 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 Bestände, noch keine Raten",
|
||||
text: "Wie viel du jährlich sparst oder amortisierst, kommt später – das hängt von deinen Lebensphasen ab. Hier zählt nur der Stand von heute.",
|
||||
},
|
||||
{
|
||||
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:
|
||||
"Jetzt legst du die Zeitachse fest: wie weit du planst und wann welche Rente oder welches Kapital zu fliessen beginnt. Das bestimmt, wo deine Lebensphasen zwingend beginnen müssen.",
|
||||
questions: [
|
||||
"Über wie viele Jahre soll die Planung laufen?",
|
||||
"Wann hörst du auf zu arbeiten?",
|
||||
"Wann beziehst du die AHV – früher, mit 65, oder später?",
|
||||
"Wann beziehst du Pensionskasse und Säule 3a?",
|
||||
],
|
||||
notes: [
|
||||
{
|
||||
title: "Noch keine Beträge",
|
||||
text: "Hier geht es nur um Zeitpunkte. Ob Rente oder Kapital, und wohin das Geld fliesst, entscheidest du in Schritt 5.",
|
||||
},
|
||||
{
|
||||
title: "Jeder Bezug erzeugt eine Phasengrenze",
|
||||
text: "Beziehst du die AHV mit 63 und die Säule 3a mit 65, sind das zwei Fixpunkte. FPT rechnet phasenweise – deshalb muss dort jeweils eine neue Lebensphase beginnen.",
|
||||
},
|
||||
{
|
||||
title: "Früher kostet, später bringt",
|
||||
text: "Ein AHV-Vorbezug kürzt die Rente lebenslang um 6,8 % pro Jahr, ein Aufschub erhöht sie um bis zu 31,5 %. Das Tool rechnet beides für dich aus.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lead:
|
||||
"Deine Planung zerfällt in Abschnitte mit gleichbleibenden Verhältnissen. Die Fixpunkte aus Schritt 2 stehen fest – dazwischen teilst du frei ein.",
|
||||
questions: [
|
||||
"Gibt es Jahre, die sich deutlich voneinander unterscheiden?",
|
||||
"Planst du einen Hauskauf, eine Weiterbildung, ein Sabbatical?",
|
||||
"Wie fein willst du planen – wenige grosse Phasen oder viele kleine?",
|
||||
],
|
||||
notes: [
|
||||
{
|
||||
title: "Eine Phase = gleichbleibende Verhältnisse",
|
||||
text: "Innerhalb einer Lebensphase laufen Einkommen, Ausgaben und Sparraten gleichmässig weiter. Ändert sich etwas grundlegend, beginnt eine neue Phase.",
|
||||
},
|
||||
{
|
||||
title: "Weniger ist oft mehr",
|
||||
text: "Drei bis sechs Phasen reichen für die meisten Planungen. Jede zusätzliche Phase bedeutet mehr Entscheide, die du treffen musst.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lead:
|
||||
"Für die Jahre, in denen du noch arbeitest: Wohin fliesst das Geld, das übrig bleibt – und was passiert an den Übergängen dazwischen?",
|
||||
questions: [
|
||||
"Wie viel sparst du pro Jahr, und wohin?",
|
||||
"Zahlst du in die Säule 3a ein? Amortisierst du die Hypothek?",
|
||||
"Verkaufst du unterwegs etwas, oder kommt Geld herein?",
|
||||
],
|
||||
notes: [
|
||||
{
|
||||
title: "Der Rest bleibt auf dem Konto",
|
||||
text: "Was du nicht zuteilst, sammelt sich als Cash an. Das ist kein Fehler – aber meist nicht die Absicht.",
|
||||
},
|
||||
{
|
||||
title: "Übergänge sind Entscheidungspunkte",
|
||||
text: "Zwischen zwei Lebensphasen entscheidest du, was mit Immobilien, Schulden und einmaligen Ereignissen geschieht.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lead:
|
||||
"Der wichtigste Schritt: Was passiert mit deinem Altersguthaben? Hier entscheidest du über Rente oder Kapital – und darüber, wovon du in der Pension lebst.",
|
||||
questions: [
|
||||
"Rente oder Kapital – oder eine Mischung?",
|
||||
"Wenn Kapital: wohin damit? Hypothek amortisieren, anlegen, liegen lassen?",
|
||||
"Reicht das Renteneinkommen für deine Ausgaben?",
|
||||
],
|
||||
notes: [
|
||||
{
|
||||
title: "Rente ist sicher, Kapital ist flexibel",
|
||||
text: "Eine Rente fliesst lebenslang, unabhängig von den Märkten. Kapital bleibt verfügbar und vererbbar, trägt aber das Anlagerisiko – und muss reichen.",
|
||||
},
|
||||
{
|
||||
title: "Die Rentenlücke ist normal",
|
||||
text: "Fast niemand deckt seine Ausgaben allein aus AHV und Pensionskasse. Entscheidend ist nicht, ob eine Lücke besteht, sondern wie lange dein Vermögen sie trägt.",
|
||||
},
|
||||
{
|
||||
title: "Steuern beim Kapitalbezug",
|
||||
text: "Ein Kapitalbezug wird einmalig und getrennt vom Einkommen besteuert. Alle Bezüge desselben Jahres werden zusammengezählt – gestaffelt über mehrere Jahre zahlst du weniger.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lead:
|
||||
"Die Jahre nach der Pensionierung: Kein Lohn mehr, dafür Renten – und das Vermögen, das du aufgebaut hast. Jetzt legst du fest, wovon du lebst.",
|
||||
questions: [
|
||||
"Wie viel entnimmst du jährlich aus deinem Vermögen?",
|
||||
"Ändern sich deine Ausgaben im Alter – Reisen zuerst, Pflege später?",
|
||||
"Verkaufst du irgendwann die Immobilie?",
|
||||
],
|
||||
notes: [
|
||||
{
|
||||
title: "Verzehr statt Sparen",
|
||||
text: "In diesen Phasen ist die Quote meist negativ: Du gibst mehr aus, als hereinkommt. Die Differenz kommt aus dem Vermögen – das ist der Zweck des Sparens.",
|
||||
},
|
||||
{
|
||||
title: "Achte auf das Ruinalter",
|
||||
text: "Reicht das Vermögen nicht bis zum Planungshorizont, meldet FPT das. Dann helfen: später aufhören, weniger ausgeben, oder anders anlegen.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lead:
|
||||
"Dein Plan steht. Was jetzt noch möglich ist – und wo du es findest.",
|
||||
questions: [],
|
||||
notes: [
|
||||
{
|
||||
title: "Werte je Lebensphase anpassen",
|
||||
text: "Willst du für eine einzelne Phase eine andere Rendite oder Sparrate? Klicke die Zelle in der Matrix an. Leere Felder erben automatisch von der Vorphase – so gilt eine Änderung ab dort weiter.",
|
||||
},
|
||||
{
|
||||
title: "Pensionsplanung zentral ändern",
|
||||
text: "Alle Entscheide zu AHV, Pensionskasse und Säule 3a stehen gebündelt unter «Pensionsplanung» in den Grundeinstellungen – für jede Person einzeln.",
|
||||
},
|
||||
{
|
||||
title: "Varianten vergleichen",
|
||||
text: "Lege ein zweites Szenario an (Schnellaktionen), ändere dort etwa das Pensionsalter, und vergleiche beide. Deine Entscheide werden mitkopiert.",
|
||||
},
|
||||
{
|
||||
title: "Unsicherheiten prüfen",
|
||||
text: "Unter «Analysen» findest du die Einflussfaktoren (welcher Hebel wirkt am stärksten), die Live-Simulation (an Reglern drehen) und die Monte-Carlo-Simulation (wie robust ist der Plan).",
|
||||
},
|
||||
{
|
||||
title: "Nachvollziehen, was gerechnet wird",
|
||||
text: "«Rechenwege» in den Schnellaktionen zeigt zu jeder Zahl den vollständigen Weg – inklusive der Vereinfachungen, die FPT bewusst macht.",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export function AssistantStepDialog({
|
||||
plan,
|
||||
stepIndex,
|
||||
isDone,
|
||||
onToggleDone,
|
||||
onClose,
|
||||
children,
|
||||
}: {
|
||||
plan: PlanInput;
|
||||
stepIndex: number;
|
||||
isDone: boolean;
|
||||
onToggleDone: (done: boolean) => void;
|
||||
onClose: () => void;
|
||||
// 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 canGuide = step.guided && !blocked && !!children;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={`Schritt ${stepIndex + 1}: ${step.title}`}
|
||||
subtitle={showTool ? undefined : step.lead}
|
||||
onClose={onClose}
|
||||
xwide
|
||||
>
|
||||
{showTool ? (
|
||||
<div className="flex flex-col gap-4">
|
||||
{children}
|
||||
<div className="flex items-center justify-between border-t border-border pt-3">
|
||||
<Button variant="ghost" onClick={() => setShowTool(false)}>
|
||||
<ArrowLeft className="h-4 w-4" /> Zurück zur Erklärung
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
onToggleDone(true);
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
<Check className="h-4 w-4" /> Schritt abschliessen
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col gap-4">
|
||||
<p className="text-sm text-fg">{explainer.lead}</p>
|
||||
|
||||
{explainer.questions.length > 0 && (
|
||||
<div className="rounded-xl border border-border bg-surface-2 p-4">
|
||||
<p className="mb-2 text-xs font-semibold uppercase tracking-wide text-faint">
|
||||
Diese Fragen beantwortest du hier
|
||||
</p>
|
||||
<ul className="flex flex-col gap-1.5">
|
||||
{explainer.questions.map((q) => (
|
||||
<li key={q} className="flex items-start gap-2 text-sm text-fg">
|
||||
<ArrowRight className="mt-0.5 h-3.5 w-3.5 shrink-0 text-accent" />
|
||||
{q}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="grid gap-3 sm:grid-cols-2">
|
||||
{explainer.notes.map((n) => (
|
||||
<div key={n.title} className="rounded-xl border border-border p-3">
|
||||
<p className="text-sm font-semibold text-fg">{n.title}</p>
|
||||
<p className="mt-1 text-xs leading-relaxed text-muted">{n.text}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{blocked && (
|
||||
<p className="flex items-start gap-2 rounded-lg border border-attention bg-attention-soft px-3 py-2 text-xs text-attention-soft-fg">
|
||||
<Lock className="mt-0.5 h-3.5 w-3.5 shrink-0" />
|
||||
{blocked}
|
||||
</p>
|
||||
)}
|
||||
|
||||
<div className="flex items-center justify-between border-t border-border pt-3">
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => {
|
||||
onToggleDone(!isDone);
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
{isDone ? "Wieder als offen markieren" : "Selbst erledigen"}
|
||||
</Button>
|
||||
{canGuide ? (
|
||||
<Button onClick={() => setShowTool(true)}>
|
||||
Schritt für Schritt <ArrowRight className="h-4 w-4" />
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
onClick={() => {
|
||||
onToggleDone(true);
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
<Check className="h-4 w-4" /> Verstanden
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user