Modul-Review 4: Matrix -- Kapitalverwendung, Phasendauer, Bedienung
Deploy App / deploy (push) Successful in 1m10s
Deploy App / deploy (push) Successful in 1m10s
Kapitalverwendung (Punkt C) am richtigen Ort: - Prozent-Aufteilung des bezogenen Alterskapitals wandert vom Cash-Uebergang zum Bezugs-Entscheid der PK (nur bei Kapitalbezug) bzw. der Saeule 3a -- mit zwei Guthaben liess sie sich vorher gar nicht getrennt beantworten - Dialoge fuehren neu brutto -> Steuersatz -> netto -> Verteilung - BUGFIX: Der zugeteilte Betrag erhoehte still den internen Bestand, deshalb zeigten Ziel-Element und "Kapital verteilen" eine 0. Er laeuft jetzt ueber Carry.capitalIn als Zusatzeinlage der Folgephase und ist ueberall sichtbar - Saeule 3a ist am Pensions-Uebergang neu ein offener Entscheid Phasendauer (gemeldeter Fehler): - Die Folgephase gleicht eine geaenderte Dauer aus; Gesamtdauer bleibt gleich - Vorher kappte das Tool nur die bearbeitete Phase -> Phase 2 ueberspannte danach die Pensionierung und die Invariante aus Punkt 44 kippte - Rueckfrage vorher, Blockade wenn die Folgephase unter 1 Jahr fiele - neue reine Funktion planDurationChange Bedienung: - Element-Zeile und Phasenkopf: Stift (umbenennen, beim Element inkl. Zuordnung), Papierkorb, Expand -- alle immer sichtbar - PATCH /api/elements/<id> nimmt neu auch ownerRole - Hilfetexte via Portal (wurden in scrollenden Dialogen abgeschnitten) - Verteil-Dialoge: Zuordnung je Zeile, nach vom/ins Cash gruppiert, Vorbelegung mit dem EFFEKTIVEN Wert inkl. Vererbung (zeigte vorher 0) - Matrix: gleiche Spaltenbreiten + horizontales Scrollen, "Alle auf-/ zuklappen", Kategorie-Summe in der zugeklappten Zeile - Phasen-Detailansicht nutzt die neue Aufteilungs-Grafik - Uebersicht: "Leer starten" auch im leeren Zustand Nebenbei: dritte verstuemmelte Hex-Farbe (#7c3aed) repariert, Phasen-Panel nutzt den eigenen Bestaetigungs-Dialog statt window.confirm; mehrere veraltete Referenzen und die buildCarryData-Tabelle in der Spez nachgezogen. SPEZIFIKATION 0.33. 278 -> 288 Tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -48,12 +48,26 @@ const ASSET_CATS = ["PENSION_FUND", "PILLAR_3A", "REAL_ESTATE", "OTHER_ASSET"];
|
||||
// Phasengrenzen als feine senkrechte Linien,
|
||||
// * daneben ein RING für ein wählbares Jahr, der die RELATIVE Aufteilung zeigt.
|
||||
// Ein Klick in die Fläche wählt das Jahr des Rings.
|
||||
export function AllocationChart({ computed, height = 300 }: { computed: PlanComputed; height?: number }) {
|
||||
export function AllocationChart({
|
||||
computed,
|
||||
height = 300,
|
||||
// Auf eine einzelne Lebensphase einschraenken (Detailansicht der Phase). Ohne Angabe wird
|
||||
// der ganze Plan gezeigt.
|
||||
onlyPhaseId,
|
||||
}: {
|
||||
computed: PlanComputed;
|
||||
height?: number;
|
||||
onlyPhaseId?: string;
|
||||
}) {
|
||||
const phases = useMemo(
|
||||
() => (onlyPhaseId ? computed.phases.filter((p) => p.id === onlyPhaseId) : computed.phases),
|
||||
[computed, onlyPhaseId]
|
||||
);
|
||||
// Asset-Elemente (nach id, damit gleiche Namen nicht kollidieren), die irgendwann einen
|
||||
// positiven Wert haben -- in Reihenfolge ihres ersten Auftretens.
|
||||
const assetEls = useMemo(() => {
|
||||
const info = new Map<string, { name: string; any: boolean }>();
|
||||
for (const phase of computed.phases) {
|
||||
for (const phase of phases) {
|
||||
for (const el of phase.elements) {
|
||||
if (!ASSET_CATS.includes(el.category)) continue;
|
||||
const cur = info.get(el.elementId) ?? { name: el.name, any: false };
|
||||
@@ -63,14 +77,14 @@ export function AllocationChart({ computed, height = 300 }: { computed: PlanComp
|
||||
}
|
||||
}
|
||||
return [...info.entries()].filter(([, v]) => v.any).map(([id, v]) => ({ id, name: v.name }));
|
||||
}, [computed]);
|
||||
}, [phases]);
|
||||
|
||||
// Je Planjahr eine Zeile mit dem Wert jedes Elements. Die Jahreswerte liegen bereits in
|
||||
// `ElementPhaseComputed.yearly` (seit 0.11) -- hier wird nur umsortiert, nichts gerechnet.
|
||||
const areaData = useMemo(() => {
|
||||
const byYear = new Map<number, Record<string, number>>();
|
||||
const ageOf = new Map<number, number>();
|
||||
for (const phase of computed.phases) {
|
||||
for (const phase of phases) {
|
||||
for (const el of phase.elements) {
|
||||
if (!ASSET_CATS.includes(el.category)) continue;
|
||||
for (const y of el.yearly) {
|
||||
@@ -84,10 +98,11 @@ export function AllocationChart({ computed, height = 300 }: { computed: PlanComp
|
||||
return [...byYear.entries()]
|
||||
.sort(([a], [b]) => a - b)
|
||||
.map(([year, values]) => ({ year, age: ageOf.get(year) ?? 0, ...values }));
|
||||
}, [computed]);
|
||||
}, [phases]);
|
||||
|
||||
// Phasengrenzen (kumulierte Dauer) für die Trennlinien.
|
||||
// Phasengrenzen (kumulierte Dauer) für die Trennlinien. Bei einer einzelnen Phase gibt es keine.
|
||||
const boundaryAges = useMemo(() => {
|
||||
if (onlyPhaseId) return [];
|
||||
const out: number[] = [];
|
||||
let acc = 0;
|
||||
for (let i = 0; i < computed.phases.length - 1; i++) {
|
||||
@@ -96,7 +111,7 @@ export function AllocationChart({ computed, height = 300 }: { computed: PlanComp
|
||||
if (typeof age === "number") out.push(age);
|
||||
}
|
||||
return out;
|
||||
}, [computed, areaData]);
|
||||
}, [computed, areaData, onlyPhaseId]);
|
||||
|
||||
// Gewähltes Jahr für den Ring -- Vorgabe: das letzte (Endzustand).
|
||||
const [pickedYear, setPickedYear] = useState<number | null>(null);
|
||||
@@ -119,7 +134,8 @@ export function AllocationChart({ computed, height = 300 }: { computed: PlanComp
|
||||
{/* Verlauf */}
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="mb-1 text-xs font-medium text-muted">
|
||||
Verlauf über alle Planjahre <span className="text-faint">· Klick wählt das Jahr für den Ring</span>
|
||||
{onlyPhaseId ? "Verlauf in dieser Lebensphase" : "Verlauf über alle Planjahre"}{" "}
|
||||
<span className="text-faint">· Klick wählt das Jahr für den Ring</span>
|
||||
</div>
|
||||
<div style={{ height }}>
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
|
||||
Reference in New Issue
Block a user