UI-Gesamtumbau: Du-Form, Inspector-Panel, Onboarding-Assistent, Tour, Palette
Deploy App / deploy (push) Successful in 1m1s
Deploy App / deploy (push) Successful in 1m1s
Rein an der Oberflaeche -- Berechnung, Datenmodell und API-Semantik unveraendert (103 Tests unveraendert gruen). Paket A (Fundament): - durchgehend Du-Form und echte Umlaute in allen sichtbaren Texten, inkl. API-Fehlermeldungen (vorher Mix aus Sie/Du und ae/oe/ue) - neue UI-Primitiven (ui.tsx): Button, Modal mit ESC/Fokus-Falle/Animation, Bestaetigungs-Dialog statt window.confirm, Toasts statt alert, Skeleton-Loader, EmptyState - eigene Attention-Farbe (Amber) fuer offene Entscheide, getrennt vom Akzent - Micro-Interactions mit prefers-reduced-motion-Fallback Paket B (Onboarding, Roadmap Nr. 10): - gefuehrter Plan-Assistent in 5 Schritten; Einkommen bewusst pro Person (raeumt die 9.9-AHV-Falle aus); reine Orchestrierung bestehender Endpunkte - Beispielplan mit einem Klick; Uebergaenge absichtlich offen - interaktive Tour ueber die Planansicht (localStorage, jederzeit neu startbar) - abgeleitete "Naechste Schritte"-Karte (offene Entscheide, fehlende Elemente, fehlende Pensionsphase, Ruin -> Einflussfaktoren) Paket C (Struktur): - Inspector-Panel rechts statt Modals fuer alle Einzel-Bearbeitungen; Matrix bleibt sichtbar, Zellklick wechselt den Inhalt - Phasenkopf auf vier Kern-Infos entschlackt (Rest in der 0.11-Detailansicht) - Matrix mit eigenem Scrollbereich, Koepfe beidachsig fixiert - Sidebar-Gruppen "Meine Plaene" / "Wissen"; "So rechnet FPT" statt SPEZIFIKATION; "Szenario-Profil" statt "Plan-Einstellungen" - Aktions-Icons ohne Hover sichtbar (Touch) Paket D (Extras): - Sparklines je Element-Zeile aus den 0.11-Verlaufswerten - Befehls-Palette (Ctrl/Cmd+K) - Ruin-Banner verlinkt auf die Einflussfaktoren Nebenbei: der ProfileMenu-Lint-Fehler und der Selection-Rest (9.17) sind behoben -- npm run lint laeuft erstmals fehlerfrei. SPEZIFIKATION auf 0.13: neue Kapitel 3.2.8, 3.7.6-3.7.9, 9.23, 9.24; 3.6.3 und 3.7.1 ueberarbeitet, 9.17 bereinigt. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
// Beispielplan mit einem Klick (Teil von Roadmap Nr. 10). Erzeugt einen realistischen,
|
||||
// vollständig ausgefuellten Plan über die BESTEHENDEN API-Endpunkte -- reine Orchestrierung,
|
||||
// kein neuer Endpunkt, keine Änderung an der Berechnung.
|
||||
//
|
||||
// Didaktischer Entscheid: Die Übergangs-Entscheide bleiben absichtlich OFFEN. Der neue
|
||||
// Nutzer sieht dadurch die Ampel ("N offen") in Aktion und lernt das wichtigste Konzept des
|
||||
// Tools am Beispiel, statt es erklärt zu bekommen.
|
||||
//
|
||||
// WICHTIG zur Reihenfolge: erst Phase 1, dann die Elemente samt Phase-1-Werten, dann die
|
||||
// Folgephase. Die Phasen-Route belegt beim Anlegen einer Phase die editierbaren Felder aus
|
||||
// der Vorphase vor -- existieren die Elemente noch nicht, bleibt die Folgephase leer
|
||||
// (Renditen/Beiträge wären dort 0).
|
||||
|
||||
import { api } from "@/lib/api-client";
|
||||
import type { PhaseData } from "@/lib/elements";
|
||||
|
||||
async function addElement(
|
||||
scenarioId: string,
|
||||
firstPhaseId: string,
|
||||
category: string,
|
||||
name: string,
|
||||
ownerRole: string,
|
||||
values?: PhaseData
|
||||
): Promise<void> {
|
||||
const { element } = await api.post<{ element: { id: string } }>(
|
||||
`/api/scenarios/${scenarioId}/elements`,
|
||||
{ category, name, ownerRole }
|
||||
);
|
||||
if (values && Object.keys(values).length > 0) {
|
||||
await api.put(`/api/elements/${element.id}/phase/${firstPhaseId}`, values);
|
||||
}
|
||||
}
|
||||
|
||||
// Liefert die Szenario-Id des angelegten Beispielplans.
|
||||
export async function createDemoPlan(): Promise<string> {
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
const { scenario } = await api.post<{ plan: { id: string }; scenario: { id: string } }>(
|
||||
"/api/plans",
|
||||
{
|
||||
name: "Beispiel: Alex Muster",
|
||||
householdType: "SINGLE",
|
||||
inflationRateDefault: 1.5,
|
||||
startYear: currentYear,
|
||||
persons: [{ role: "PERSON_A", name: "Alex", age: 45, retirementAge: 65 }],
|
||||
}
|
||||
);
|
||||
const sid = scenario.id;
|
||||
|
||||
await api.patch(`/api/scenarios/${sid}`, { initialCash: 40000 });
|
||||
|
||||
// Phase 1: Erwerbsphase bis zur Pension (die Route kappt die Dauer ohnehin am
|
||||
// Pensionsereignis; 20 Jahre = 45 -> 65).
|
||||
const p1 = await api.post<{ phase: { id: string } }>(`/api/scenarios/${sid}/phases`, {
|
||||
name: "Erwerbsphase",
|
||||
durationYears: 20,
|
||||
});
|
||||
const firstPhaseId = p1.phase.id;
|
||||
|
||||
await addElement(sid, firstPhaseId, "INCOME", "Lohn Alex", "PERSON_A", {
|
||||
amount: 110000,
|
||||
teuerungsausgleich: 1,
|
||||
});
|
||||
await addElement(sid, firstPhaseId, "EXPENSE", "Lebenshaltung", "HOUSEHOLD", {
|
||||
amount: 78000,
|
||||
teuerungsausgleich: 0,
|
||||
});
|
||||
await addElement(sid, firstPhaseId, "AHV", "AHV Alex", "PERSON_A", { gapYears: 0 });
|
||||
await addElement(sid, firstPhaseId, "PENSION_FUND", "Pensionskasse", "PERSON_A", {
|
||||
currentValue: 380000,
|
||||
annualContribution: 14000,
|
||||
expectedReturn: 1.5,
|
||||
});
|
||||
await addElement(sid, firstPhaseId, "PILLAR_3A", "Säule 3a", "PERSON_A", {
|
||||
currentValue: 75000,
|
||||
annualContribution: 7000,
|
||||
expectedReturn: 2,
|
||||
});
|
||||
await addElement(sid, firstPhaseId, "OTHER_ASSET", "ETF-Depot", "HOUSEHOLD", {
|
||||
startValue: 120000,
|
||||
annualContribution: 12000,
|
||||
expectedReturn: 5,
|
||||
});
|
||||
await addElement(sid, firstPhaseId, "REAL_ESTATE", "Eigenheim", "HOUSEHOLD", {
|
||||
purchasePrice: 900000,
|
||||
mortgage: 600000,
|
||||
amortization: 12000,
|
||||
interestRate: 1.5,
|
||||
valueGrowth: 1,
|
||||
});
|
||||
|
||||
// Pensionsphase 65 -> 90. Die Route belegt die editierbaren Felder aus Phase 1 vor.
|
||||
await api.post(`/api/scenarios/${sid}/phases`, { name: "Pensionsphase", durationYears: 25 });
|
||||
|
||||
return sid;
|
||||
}
|
||||
Reference in New Issue
Block a user