import React, { useMemo, useState } from 'react'; import { CheckCircle2, ChevronDown, Circle, Clock, Pause, Play, TrendingUp, X, Zap } from 'lucide-react'; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from '@/components/ui/alert-dialog'; import { Button } from '@/components/ui/button'; import { cn } from '@/lib/utils'; function fmt(v) { return (Number(v) || 0).toLocaleString(undefined, { style: 'currency', currency: 'USD', maximumFractionDigits: 0, }); } function dateLabel(iso) { if (!iso) return '—'; return new Date(iso).toLocaleDateString(undefined, { month: 'short', year: 'numeric' }); } function months(n) { if (!n || n <= 0) return 'just started'; const y = Math.floor(n / 12); const m = n % 12; if (y === 0) return `${m} mo`; if (m === 0) return `${y} yr`; return `${y} yr ${m} mo`; } // ─── On-track indicator ─────────────────────────────────────────────────────── function computeOnTrack(debt, monthsElapsed) { if (!debt.projected_payoff_month || debt.current_balance === null) return null; if (debt.starting_balance <= 0) return null; const remaining = debt.projected_payoff_month - monthsElapsed; if (remaining <= 0) return debt.current_balance <= 0 ? 'done' : 'behind'; const progressExpected = monthsElapsed / debt.projected_payoff_month; const progressActual = debt.starting_balance > 0 ? 1 - (debt.current_balance / debt.starting_balance) : 0; const diff = progressActual - progressExpected; if (diff > 0.05) return 'ahead'; if (diff < -0.05) return 'behind'; return 'on_track'; } function OnTrackPill({ status }) { if (!status) return null; const map = { ahead: { label: '↑ Ahead', cls: 'bg-teal-500/12 text-teal-600 dark:text-teal-400' }, on_track: { label: '→ On track', cls: 'bg-muted/60 text-muted-foreground' }, behind: { label: '↓ Behind', cls: 'bg-amber-500/12 text-amber-600 dark:text-amber-400' }, done: { label: '✓ Paid off', cls: 'bg-emerald-500/12 text-emerald-600 dark:text-emerald-400' }, }; const { label, cls } = map[status] ?? map.on_track; return ( {label} ); } // ─── Per-debt progress row ──────────────────────────────────────────────────── function DebtProgressRow({ debt, snapshotDebt, monthsElapsed }) { const startBal = debt.starting_balance ?? 0; const curBal = debt.current_balance ?? startBal; const pct = debt.progress_pct ?? 0; const trackStatus = computeOnTrack({ ...debt, ...snapshotDebt }, monthsElapsed); return (
{fmt(curBal)}
{startBal > 0 &&{fmt(startBal)} start
} > ) : (removed
)}proj.
{snapshotDebt.projected_payoff_date.slice(0, 7)}
No debt data in this plan.
) : ( currentDebts.map(debt => (