diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 27418c8..c34ba2e 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -9,6 +9,7 @@ import Budget from './pages/Budget';
import Analytics from './pages/Analytics';
import Salarios from './pages/Salarios';
import Pensions from './pages/Pensions';
+import Proyecciones from './pages/Proyecciones';
import ServiciosMunicipales from './pages/ServiciosMunicipales';
function ProtectedRoute({ children }: { children: React.ReactNode }) {
@@ -35,6 +36,7 @@ function AppRoutes() {
} />
} />
} />
+ } />
} />
} />
} />
diff --git a/frontend/src/components/Layout.tsx b/frontend/src/components/Layout.tsx
index b66db3f..c06cf28 100644
--- a/frontend/src/components/Layout.tsx
+++ b/frontend/src/components/Layout.tsx
@@ -7,6 +7,7 @@ import {
PiggyBank,
Droplets,
LogOut,
+ TrendingUp,
Wallet,
Menu,
Sun,
@@ -51,6 +52,7 @@ const navSections: NavSection[] = [
{ to: '/budget', icon: Calculator, label: 'Presupuesto' },
{ to: '/salarios', icon: Landmark, label: 'Salarios' },
{ to: '/pensions', icon: PiggyBank, label: 'Pensiones' },
+ { to: '/proyecciones', icon: TrendingUp, label: 'Proyecciones' },
{ to: '/analytics', icon: BarChart3, label: 'Analytics' },
],
},
diff --git a/frontend/src/pages/Proyecciones.tsx b/frontend/src/pages/Proyecciones.tsx
new file mode 100644
index 0000000..cc5d504
--- /dev/null
+++ b/frontend/src/pages/Proyecciones.tsx
@@ -0,0 +1,120 @@
+import { ChevronLeft, ChevronRight, Loader2, TrendingUp } from 'lucide-react';
+import { useNavigate } from 'react-router-dom';
+
+import { useBudget } from '@/hooks/useBudget';
+import { formatAmount } from '@/lib/format';
+import { cn } from '@/lib/utils';
+import { Button } from '@/components/ui/button';
+import { Card, CardContent } from '@/components/ui/card';
+import YearlyOverview from '@/components/budget/YearlyOverview';
+
+const MIN_YEAR = 2026;
+const MAX_YEAR = 2030;
+
+export default function Proyecciones() {
+ const currentYear = Math.max(MIN_YEAR, new Date().getFullYear());
+ const {
+ year,
+ setYear,
+ setSelectedMonth,
+ projection,
+ loading,
+ saveBalanceOverride,
+ clearBalanceOverride,
+ } = useBudget(currentYear);
+
+ const navigate = useNavigate();
+
+ return (
+
+ {/* Header */}
+
+
+
+
Proyecciones
+
+
+
+ {year}
+
+
+
+
+ {/* Annual summary cards */}
+ {projection && (
+
+
+
+ Ingresos Anuales
+
+ {formatAmount(projection.annual_income, 'CRC')}
+
+
+
+
+
+ Egresos Anuales
+
+ {formatAmount(projection.annual_expenses, 'CRC')}
+
+
+
+
+
+ Ahorro Anual
+
+ {formatAmount(projection.annual_savings, 'CRC')}
+
+
+
+
+
+ Balance Neto Anual
+ = 0 ? 'text-primary' : 'text-destructive',
+ )}
+ >
+ {projection.annual_net >= 0 ? '+' : ''}
+ {formatAmount(projection.annual_net, 'CRC')}
+
+
+
+
+ )}
+
+ {/* Yearly table */}
+ {loading ? (
+
+
+
+ ) : projection ? (
+
+
+ {
+ setSelectedMonth(m);
+ navigate('/budget');
+ }}
+ onSaveOverride={async (month, value) => {
+ await saveBalanceOverride(year, month, value);
+ }}
+ onClearOverride={async (month) => {
+ await clearBalanceOverride(year, month);
+ }}
+ />
+
+
+ ) : null}
+
+ );
+}