"use client"; import { CalendarCheck, Flag } from "lucide-react"; import type { PhaseComputed } from "@/lib/calculations"; interface PersonAxis { role: "PERSON_A" | "PERSON_B"; label: string; currentAge: number; retirementAge: number; color: string; } // Horizontale Zeitachse: die Lebensphasen als aneinandergereihte Segmente (Breite = Dauer), // darunter Alter und -- sofern ein Planstart gesetzt ist -- die Kalenderjahre. Pensionsalter // je Person und ein allfälliges Ruinalter sind als Marker eingezeichnet. export function Timeline({ phases, persons, ruinAge, startYear, actualYears = [], activePhaseId, onSelectPhase, }: { phases: PhaseComputed[]; persons: PersonAxis[]; ruinAge?: number | null; startYear?: number | null; // Kalenderjahre, für die effektive Werte erfasst sind (aufsteigend). Der jüngste Satz // wird hervorgehoben, ältere bleiben blass -- sie sind überholt, aber nicht bedeutungslos. actualYears?: number[]; // Seit 0.42 ist die Zeitachse nicht mehr nur Anzeige, sondern der NAVIGATOR der // Kartenansicht: Das Segment der offenen Karte ist hervorgehoben, ein Klick springt hin. // Zeit läuft von links nach rechts -- das versteht man ohne Erklärung. activePhaseId?: string | null; onSelectPhase?: (phaseId: string) => void; }) { if (phases.length === 0 || persons.length === 0) return null; const totalYears = phases.reduce((s, p) => s + p.durationYears, 0); const minAge = Math.min(...persons.map((p) => p.currentAge)); const maxAge = minAge + totalYears; const span = Math.max(1, maxAge - minAge); const pct = (age: number) => `${(Math.max(0, Math.min(span, age - minAge)) / span) * 100}%`; const yearOf = (yearsFromStart: number) => (startYear ? startYear + yearsFromStart : null); // Segmente: Start-/Endjahr (relativ zum Planbeginn) je Phase -- ohne Mutation während // des Renderns, deshalb die kumulierte Summe der vorangehenden Dauern. const segments = phases.map((p, i) => { const from = phases.slice(0, i).reduce((s, x) => s + x.durationYears, 0); return { phase: p, from, to: from + p.durationYears }; }); return (

Zeitachse

{persons.map((p) => ( {p.label} (heute {p.currentAge}) ))}
{/* Pensionsmarker je Person */} {persons.map((p, i) => p.retirementAge > minAge && p.retirementAge < maxAge ? (
{p.retirementAge}
) : null )} {/* Ruin-Marker (Person A) */} {ruinAge != null && ruinAge > minAge && ruinAge <= maxAge && (
Ruin {ruinAge}
)} {/* Marker für erfasste effektive Werte. Nur mit bekanntem Planstartjahr platzierbar -- ohne Kalenderbezug gäbe es keine Position auf der Achse. */} {startYear && actualYears.map((y) => { const age = minAge + (y - startYear); if (age < minAge || age > maxAge) return null; const isLatest = y === actualYears[actualYears.length - 1]; return (
{y}
); })} {/* Phasen-Segmente: Breite proportional zur Dauer, Einfärbung nach Phasentyp. */}
{segments.map((s, i) => { const soft = s.phase.type === "PENSION" || s.phase.type === "MIXED"; const active = activePhaseId === s.phase.id; const clickable = !!onSelectPhase; return ( ); })}
{/* Alters- und Jahres-Beschriftung */}
{minAge} J.{yearOf(0) ? ` · ${yearOf(0)}` : ""} {maxAge} J.{yearOf(totalYears) ? ` · ${yearOf(totalYears)}` : ""}
); }