import { useState } from 'react'; import { useQueryClient } from '@tanstack/react-query'; import { toast } from 'sonner'; import api, { type UserSettingsData } from '@/lib/api'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; export interface FundAssumption { monthlyContribution: number; annualRate: number; } export type PensionAssumptions = Partial< Record<'FCL' | 'ROP' | 'VOL', FundAssumption> >; interface Props { current: Record<'FCL' | 'ROP' | 'VOL', FundAssumption>; settingsData: UserSettingsData; onClose: () => void; } const FUND_LABELS: Record<'FCL' | 'ROP' | 'VOL', string> = { FCL: 'FCL — Capitalización Laboral', ROP: 'ROP — Régimen Obligatorio', VOL: 'VOL — Fondo Voluntario', }; /** Per-fund projection assumptions, persisted server-side in UserSettings so * they survive devices and reloads (review UX-12). */ export default function PensionAssumptionsDialog({ current, settingsData, onClose, }: Props) { const queryClient = useQueryClient(); const [form, setForm] = useState(() => ({ FCL: { ...current.FCL }, ROP: { ...current.ROP }, VOL: { ...current.VOL }, })); const [saving, setSaving] = useState(false); const setField = ( fund: 'FCL' | 'ROP' | 'VOL', field: keyof FundAssumption, value: string, ) => { const num = parseFloat(value); setForm((prev) => ({ ...prev, [fund]: { ...prev[fund], [field]: isNaN(num) ? 0 : num }, })); }; const handleSave = async () => { setSaving(true); try { // The settings PATCH replaces the whole blob — merge over what exists. await api.patch('/settings/', { data: { ...settingsData, pension_assumptions: form }, }); toast.success('Supuestos de pensión guardados'); queryClient.invalidateQueries({ queryKey: ['settings'] }); onClose(); } catch { toast.error('No se pudieron guardar los supuestos'); } finally { setSaving(false); } }; return ( { if (!open) onClose(); }}> Supuestos de proyección

Usados para proyectar el crecimiento de cada fondo. El saldo inicial siempre viene del último estado de cuenta.

{(Object.keys(FUND_LABELS) as Array<'FCL' | 'ROP' | 'VOL'>).map( (fund) => (

{FUND_LABELS[fund]}

setField(fund, 'monthlyContribution', e.target.value) } />
setField(fund, 'annualRate', e.target.value) } />
), )}
); }