Raten ueber Lebensphasen uebernehmen + Rate in der Verlaufsgrafik
Deploy App / deploy (push) Successful in 1m6s
Deploy App / deploy (push) Successful in 1m6s
(1) Beim Aendern eines Ratenfelds fragt das Panel nach der Reichweite: nur diese Phase (Vorgabe), diese + folgende, alle Phasen. Gilt fuer expectedReturn, valueGrowth, interestRate und teuerungsausgleich. Inline statt Modal -- das Zahlenfeld loest je Tastendruck aus. Die Zielphasen behalten ihre uebrigen Werte (der Endpunkt ersetzt den ganzen Satz; ein Kopieren des Entwurfs haette dort Betraege geloescht). (2) ElementYearPoint fuehrt neu `rate` mit -- additiv, nur durchgereicht. Verlaufsgrafik zeigt sie auf zweiter Y-Achse als Stufenlinie. Golden Tests unveraendert. Spezifikation 0.20, 17 Tests (164 -> 181). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -396,6 +396,17 @@ export function ElementDetailDialog({
|
||||
? "Eigenkapital"
|
||||
: "Wert";
|
||||
|
||||
// Zweite Achse nur, wenn dieses Element überhaupt eine Rate trägt (AHV und Schulden nicht).
|
||||
const rateLabel =
|
||||
category === "REAL_ESTATE"
|
||||
? "Wertsteigerung"
|
||||
: isFlow
|
||||
? category === "INCOME"
|
||||
? "Lohnentwicklung"
|
||||
: "Reale Mehrausgaben"
|
||||
: "Erwartete Rendite";
|
||||
const hasRate = points.some((p) => typeof p.rate === "number");
|
||||
|
||||
const verlauf = (
|
||||
<>
|
||||
{points.length === 0 ? (
|
||||
@@ -406,16 +417,49 @@ export function ElementDetailDialog({
|
||||
<LineChart data={points} margin={{ top: 8, right: 16, left: 8, bottom: 8 }}>
|
||||
<CartesianGrid strokeDasharray="3 3" className="stroke-border" />
|
||||
<XAxis dataKey="age" type="number" domain={["dataMin", "dataMax"]} tick={{ fontSize: 11 }} tickFormatter={(v) => `${v} J.`} />
|
||||
<YAxis tick={{ fontSize: 11 }} tickFormatter={(v) => Intl.NumberFormat("de-CH", { notation: "compact" }).format(v)} />
|
||||
<Tooltip formatter={(v, n) => [typeof v === "number" ? formatChf(v) : v, n]} labelFormatter={(v) => `Alter ${v}`} />
|
||||
<YAxis yAxisId="chf" tick={{ fontSize: 11 }} tickFormatter={(v) => Intl.NumberFormat("de-CH", { notation: "compact" }).format(v)} />
|
||||
{hasRate && (
|
||||
<YAxis
|
||||
yAxisId="rate"
|
||||
orientation="right"
|
||||
tick={{ fontSize: 11 }}
|
||||
tickFormatter={(v) => `${v} %`}
|
||||
// Etwas Luft nach oben und unten, damit eine konstante Rate nicht als
|
||||
// Linie direkt auf der Achse klebt.
|
||||
domain={([min, max]: readonly [number, number]) => [Math.min(0, min - 1), max + 1]}
|
||||
/>
|
||||
)}
|
||||
<Tooltip
|
||||
formatter={(v, n) =>
|
||||
typeof v !== "number" ? [v, n] : n === rateLabel ? [`${v} %`, n] : [formatChf(v), n]
|
||||
}
|
||||
labelFormatter={(v) => `Alter ${v}`}
|
||||
/>
|
||||
<Legend wrapperStyle={{ fontSize: 12 }} />
|
||||
<Line dataKey="value" name={valueLabel} stroke="var(--accent)" strokeWidth={2} dot={false} isAnimationActive={false} />
|
||||
<Line yAxisId="chf" dataKey="value" name={valueLabel} stroke="var(--accent)" strokeWidth={2} dot={false} isAnimationActive={false} />
|
||||
{MULTI_SERIES.includes(category) && (
|
||||
<>
|
||||
<Line dataKey="propertyValue" name="Verkehrswert" stroke="#0ea5e9" strokeWidth={1.5} dot={false} isAnimationActive={false} />
|
||||
<Line dataKey="mortgage" name="Restschuld" stroke="#dc2626" strokeWidth={1.5} strokeDasharray="5 3" dot={false} isAnimationActive={false} />
|
||||
<Line yAxisId="chf" dataKey="propertyValue" name="Verkehrswert" stroke="#0ea5e9" strokeWidth={1.5} dot={false} isAnimationActive={false} />
|
||||
<Line yAxisId="chf" dataKey="mortgage" name="Restschuld" stroke="#dc2626" strokeWidth={1.5} strokeDasharray="5 3" dot={false} isAnimationActive={false} />
|
||||
</>
|
||||
)}
|
||||
{hasRate && (
|
||||
// Stufenlinie, nicht interpoliert: Die Rate ist innerhalb einer Phase
|
||||
// konstant und springt an der Phasengrenze. Eine weiche Kurve würde einen
|
||||
// gleitenden Übergang suggerieren, den die Berechnung nicht macht.
|
||||
<Line
|
||||
yAxisId="rate"
|
||||
type="stepAfter"
|
||||
dataKey="rate"
|
||||
name={rateLabel}
|
||||
stroke="#d97706"
|
||||
strokeWidth={1.5}
|
||||
strokeDasharray="4 2"
|
||||
dot={false}
|
||||
connectNulls
|
||||
isAnimationActive={false}
|
||||
/>
|
||||
)}
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user