"use client"; import { useMemo, useState } from "react"; import { Bar, BarChart, CartesianGrid, Legend, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts"; import { WealthChart, type TimelineSeries } from "@/components/WealthChart"; import { api } from "@/lib/api-client"; import type { PlanComputed } from "@/lib/calculations"; import type { PlanInput } from "@/lib/types"; const PALETTE = ["#3f3f46", "#2563eb", "#16a34a", "#d97706", "#dc2626", "#7c3aed"]; interface PlanListItem { id: string; name: string; } export function Dashboard({ plan, computed, allPlans, }: { plan: PlanInput; computed: PlanComputed; allPlans: PlanListItem[]; }) { const [compareIds, setCompareIds] = useState([]); const [compareData, setCompareData] = useState>({}); async function toggleCompare(id: string) { if (compareIds.includes(id)) { setCompareIds((prev) => prev.filter((p) => p !== id)); return; } setCompareIds((prev) => [...prev, id]); if (!compareData[id]) { const data = await api.get<{ computed: PlanComputed }>(`/api/plans/${id}`); setCompareData((prev) => ({ ...prev, [id]: data.computed })); } } const series: TimelineSeries[] = useMemo(() => { const result: TimelineSeries[] = [{ label: plan.name, color: PALETTE[0], computed }]; compareIds.forEach((id, i) => { const c = compareData[id]; const name = allPlans.find((p) => p.id === id)?.name ?? id; if (c) result.push({ label: name, color: PALETTE[(i + 1) % PALETTE.length], computed: c }); }); return result; }, [plan.name, computed, compareIds, compareData, allPlans]); const barKeys = useMemo(() => { const keys = new Set(); for (const phase of computed.phases) { for (const s of phase.securities) keys.add(s.name); for (const re of phase.realEstates) keys.add(re.name); } return Array.from(keys); }, [computed]); const barData = useMemo( () => computed.phases.map((phase) => { const row: Record = { phase: phase.name }; for (const s of phase.securities) row[s.name] = s.endValue; for (const re of phase.realEstates) row[re.name] = re.endContribution; return row; }), [computed] ); const otherPlans = allPlans.filter((p) => p.id !== plan.id); const lastPhase = computed.phases[computed.phases.length - 1]; return (

Vermoegensverlauf

CSV-Export
{otherPlans.length > 0 && (
Vergleichen mit: {otherPlans.map((p) => ( ))}
)}

Vermoegensaufteilung pro Phase (Endvermoegen)

Intl.NumberFormat("de-CH", { notation: "compact" }).format(v)} /> typeof v === "number" ? v.toLocaleString("de-CH", { maximumFractionDigits: 0 }) : v } /> {barKeys.map((key, i) => ( ))}
); } function StatCard({ label, value, help }: { label: string; value: number; help?: string }) { return (
{label}
{value.toLocaleString("de-CH", { maximumFractionDigits: 0 })} CHF
); }