UI-Umbau: Analyse-Bereich, Planstart, Zeitachse mit Phasen
Deploy App / deploy (push) Successful in 1m44s
Deploy App / deploy (push) Successful in 1m44s
Sieben Anpassungen aus dem Feedback: - Grafiken liegen neu im eigenen Bereich "Grafiken" (Dialog, Button oben) statt unter der Matrix. Die Matrix bleibt die ruhige Hauptansicht. - Kennzahl "Geschaetzter Nachlass" entfernt -- sie war rechnerisch identisch mit dem nominalen Endvermoegen und suggerierte eine Zusatzinformation, die es nicht gab. - Monte-Carlo-Button nach oben zu den Szenario-Aktionen verschoben. - Neues Profilfeld "Planstart (Jahr)" (Scenario.startYear + Migration). Rein fuer die Darstellung -- die Berechnung rechnet unveraendert in relativen Jahren. Bestehende Szenarien werden auf das laufende Jahr gesetzt. - Zeitachse zeigt die Lebensphasen als Segmente (Breite = Dauer, Einfaerbung nach Phasentyp) inkl. Jahresspanne, plus Jahres-Beschriftung an den Enden. - Lebensphase bearbeiten neu als Popup statt Panel unter der Tabelle -- konsistent zu allen anderen Eingaben; Speichern schliesst. - Vermoegensverlauf ueber ALLE Jahre statt nur ueber die Phasengrenzen. Dafuer fuehrt computePlan das Vermoegen neu pro Jahr mit (YearPoint.wealthNominal/ wealthReal) -- dieselbe Groesse, die schon die Ruin-Erkennung berechnet. Damit werden Verlaeufe INNERHALB einer Phase sichtbar (z. B. Kapitalverzehr). Zwei Tests fuer das Jahres-Vermoegen (58 -> 60). Spezifikation auf v0.9. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+24
-24
@@ -8,7 +8,6 @@ import {
|
||||
ChevronDown,
|
||||
ChevronRight,
|
||||
CreditCard,
|
||||
Dices,
|
||||
Home,
|
||||
Landmark,
|
||||
PiggyBank,
|
||||
@@ -33,7 +32,6 @@ import {
|
||||
type CellContext,
|
||||
} from "@/components/ElementDetail";
|
||||
import { PhaseDetail } from "@/components/PhaseDetail";
|
||||
import { MonteCarloDialog } from "@/components/MonteCarloDialog";
|
||||
import { PlanProfileFields, type ProfileDraft } from "@/components/PlanProfileFields";
|
||||
import { MoneyField } from "@/components/FormField";
|
||||
import { api } from "@/lib/api-client";
|
||||
@@ -123,7 +121,6 @@ export function PlanView({
|
||||
const [editTransition, setEditTransition] = useState<{ elementId: string; fromPhaseId: string } | null>(null);
|
||||
const [editPhaseCell, setEditPhaseCell] = useState<{ elementId: string; phaseId: string } | null>(null);
|
||||
const [showCashInit, setShowCashInit] = useState(false);
|
||||
const [showMonteCarlo, setShowMonteCarlo] = useState(false);
|
||||
// fromPhaseId des Cash-Uebergangs, der gerade bearbeitet wird.
|
||||
const [editCashTransition, setEditCashTransition] = useState<string | null>(null);
|
||||
const [valueMode, setValueMode] = useState<ValueMode>("nominal");
|
||||
@@ -321,7 +318,12 @@ export function PlanView({
|
||||
<span className="text-[11px] text-faint">real = kaufkraftbereinigt (Planbeginn)</span>
|
||||
</div>
|
||||
|
||||
<Timeline phases={computed.phases} persons={personAxes} ruinAge={computed.ruinAge} />
|
||||
<Timeline
|
||||
phases={computed.phases}
|
||||
persons={personAxes}
|
||||
ruinAge={computed.ruinAge}
|
||||
startYear={plan.startYear}
|
||||
/>
|
||||
|
||||
{/* Plan-Profil */}
|
||||
<div
|
||||
@@ -376,13 +378,6 @@ export function PlanView({
|
||||
>
|
||||
<Plus className="h-4 w-4" /> Lebensphase
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowMonteCarlo(true)}
|
||||
className="ml-auto flex items-center gap-1.5 rounded-lg border border-border px-3 py-1.5 text-sm font-medium text-muted hover:bg-surface-2"
|
||||
>
|
||||
<Dices className="h-4 w-4" /> Monte-Carlo-Simulation durchführen
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -590,13 +585,18 @@ export function PlanView({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Detail-Panel. Der key erzwingt beim Wechsel von Zelle/Phase einen Neuaufbau,
|
||||
damit der lokale Formular-Zustand nicht vom vorher geoeffneten Element uebrig bleibt. */}
|
||||
{selected && (
|
||||
<div key={`ph-${selected.phaseId}`} className="rounded-xl border border-accent bg-surface p-4 shadow-sm">
|
||||
{renderDetail()}
|
||||
</div>
|
||||
)}
|
||||
{/* Lebensphase bearbeiten -- als Popup, konsistent zu allen anderen Eingaben.
|
||||
Der key erzwingt beim Wechsel der Phase einen Neuaufbau, damit der lokale
|
||||
Formular-Zustand nicht von der vorher geoeffneten Phase uebrig bleibt. */}
|
||||
{selected && (() => {
|
||||
const phase = computed.phases.find((p) => p.id === selected.phaseId);
|
||||
if (!phase) return null;
|
||||
return (
|
||||
<DialogShell key={`ph-${selected.phaseId}`} title={`Lebensphase: ${phase.name}`} onClose={() => setSelected(null)}>
|
||||
{renderDetail()}
|
||||
</DialogShell>
|
||||
);
|
||||
})()}
|
||||
|
||||
{showAdd && firstPhase && (
|
||||
<AddElementDialog
|
||||
@@ -640,11 +640,7 @@ export function PlanView({
|
||||
/>
|
||||
)}
|
||||
|
||||
{showMonteCarlo && (
|
||||
<MonteCarloDialog plan={plan} computed={computed} onClose={() => setShowMonteCarlo(false)} />
|
||||
)}
|
||||
|
||||
{editCashTransition && (() => {
|
||||
{editCashTransition && (() => {
|
||||
const fromPhase = computed.phases.find((p) => p.id === editCashTransition);
|
||||
if (!fromPhase) return null;
|
||||
const toIndex = computed.phases.findIndex((p) => p.id === fromPhase.id) + 1;
|
||||
@@ -759,7 +755,10 @@ export function PlanView({
|
||||
maxDurationYears={phase.maxDurationYears}
|
||||
isLast={isLast}
|
||||
laterPhaseCount={laterPhaseCount(phase)}
|
||||
onSaved={onChanged}
|
||||
onSaved={() => {
|
||||
setSelected(null);
|
||||
onChanged();
|
||||
}}
|
||||
onDeleted={() => {
|
||||
setSelected(null);
|
||||
onChanged();
|
||||
@@ -1190,6 +1189,7 @@ function PlanSettingsDialog({ plan, onClose, onSaved }: { plan: PlanInput; onClo
|
||||
const [draft, setDraft] = useState<ProfileDraft>({
|
||||
householdType: plan.householdType,
|
||||
inflationRateDefault: plan.inflationRateDefault,
|
||||
startYear: plan.startYear ?? new Date().getFullYear(),
|
||||
persons: plan.persons.map((p) => ({ role: p.role, name: p.name ?? "", age: p.age, retirementAge: p.retirementAge })),
|
||||
});
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
Reference in New Issue
Block a user