|
1 | 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ |
2 | 2 | 'use client'; |
3 | 3 |
|
| 4 | +import { useState } from 'react'; |
4 | 5 | import Header from './components/Header'; |
5 | 6 | import PensionSimulator from './components/PensionSimulator'; |
6 | 7 | import PricingSection from './components/PricingSection'; |
7 | 8 | import FAQSection from './components/FAQSection'; |
8 | 9 | import Footer from './components/Footer'; |
9 | 10 |
|
| 11 | +// Valor UF actual (se podría actualizar con una API en producción) |
| 12 | +const UF_VALUE = 39000; |
| 13 | + |
| 14 | +// Result type |
| 15 | +interface Result { |
| 16 | + rentaVitalicia: number; |
| 17 | + seguroSocial: number; |
| 18 | + pgu: number; |
| 19 | + total: number; |
| 20 | +} |
| 21 | + |
| 22 | +// Cálculo de Renta Vitalicia |
| 23 | +const calculateRentaVitalicia = (saldoAFP: number): number => { |
| 24 | + const tasa = 0.0327; // Tasa actual según el ejemplo |
| 25 | + // Para poder optar por una renta vitalicia se debe poder obtener más de 2 UF |
| 26 | + const minimumPension = 2 * UF_VALUE; |
| 27 | + // Verificar si cumple el requisito mínimo |
| 28 | + if ((tasa * 2 * saldoAFP) / 12 < minimumPension) { |
| 29 | + return 0; |
| 30 | + } |
| 31 | + // Cálculo: tasa * 2 * saldo / 12 |
| 32 | + return Math.round((tasa * 2 * saldoAFP) / 12); |
| 33 | +}; |
| 34 | + |
| 35 | +// Cálculo de Seguro Social |
| 36 | +const calculateSeguroSocial = (saldoAFP: number): number => { |
| 37 | + // Para hombres, mínimo 20 años cotizados, máximo 25 |
| 38 | + // Beneficio de 0.1 UF por año cotizado |
| 39 | + let añosCotizados = 0; |
| 40 | + if (saldoAFP >= 100000000) { |
| 41 | + añosCotizados = 25; // Máximo |
| 42 | + } else if (saldoAFP >= 50000000) { |
| 43 | + añosCotizados = 20; // Mínimo |
| 44 | + } else { |
| 45 | + añosCotizados = 0; // No califica |
| 46 | + } |
| 47 | + return Math.round(añosCotizados * 0.1 * UF_VALUE); |
| 48 | +}; |
| 49 | + |
| 50 | +// Cálculo de PGU |
| 51 | +const calculatePGU = (): number => { |
| 52 | + // Valor fijo según la hoja de cálculo |
| 53 | + return 214296; |
| 54 | +}; |
| 55 | + |
| 56 | +// Cálculo total |
| 57 | +const calculateTotalPension = (saldoAFP: number): Result => { |
| 58 | + const rentaVitalicia = calculateRentaVitalicia(saldoAFP); |
| 59 | + const seguroSocial = calculateSeguroSocial(saldoAFP); |
| 60 | + const pgu = calculatePGU(); |
| 61 | + return { |
| 62 | + rentaVitalicia, |
| 63 | + seguroSocial, |
| 64 | + pgu, |
| 65 | + total: rentaVitalicia + seguroSocial + pgu |
| 66 | + }; |
| 67 | +}; |
| 68 | + |
| 69 | +// Componente de pantalla de "Calculando..." |
| 70 | +function CalculandoScreen() { |
| 71 | + return ( |
| 72 | + <div className="flex flex-col items-center justify-center h-96 w-full"> |
| 73 | + <h2 className="text-4xl font-bold mb-4">Calculando....</h2> |
| 74 | + <p className="text-lg mb-2">Esto puede tomar un par de segundos…</p> |
| 75 | + <p className="text-lg mb-4">Ya estamos casi !</p> |
| 76 | + <img src="/calculando-face.jpg" alt="Calculando" className="w-24 h-24 rounded" /> |
| 77 | + </div> |
| 78 | + ); |
| 79 | +} |
| 80 | + |
10 | 81 | export default function Home() { |
| 82 | + const [saldo, setSaldo] = useState(''); |
| 83 | + const [result, setResult] = useState<Result | null>(null); |
| 84 | + const [isCalculating, setIsCalculating] = useState(false); |
| 85 | + |
| 86 | + const handleCalculate = () => { |
| 87 | + if (!saldo || isNaN(Number(saldo))) return; |
| 88 | + setIsCalculating(true); |
| 89 | + setResult(null); // Oculta el resultado anterior mientras calcula |
| 90 | + setTimeout(() => { |
| 91 | + setResult(calculateTotalPension(Number(saldo))); |
| 92 | + setIsCalculating(false); |
| 93 | + }, 3000); |
| 94 | + }; |
| 95 | + |
11 | 96 | return ( |
12 | | - <div className="min-h-screen"> |
13 | | - <Header /> |
14 | | - |
15 | | - {/* Hero Section con imagen de fondo */} |
16 | | - <section className="w-full bg-cover bg-center" style={{ backgroundImage: 'url(/bg-hero.png)' }}> |
17 | | - <main className="container mx-auto px-4 py-16"> |
18 | | - <div className="max-w-4xl mx-auto text-center space-y-8"> |
19 | | - <h1 className="text-7xl font-bold text-yellow-400 mb-4 tracking-tight"> |
20 | | - ¿Ya quieres jubilar? |
21 | | - </h1> |
22 | | - <p className="text-xl text-blue-100 mb-8"> |
23 | | - Descubre cuánto $$ podrías obtener si jubilaras HOY: |
24 | | - </p> |
25 | | - |
26 | | - <PensionSimulator /> |
27 | | - |
28 | | - {/* Features Section */} |
29 | | - <div className="grid grid-cols-1 md:grid-cols-3 gap-8 mt-16"> |
30 | | - <div className="bg-white/10 backdrop-blur-lg rounded-xl p-6 text-white"> |
31 | | - <h3 className="text-xl font-semibold mb-2">Simulación Precisa</h3> |
32 | | - <p className="text-blue-100">Calcula tu pensión estimada con datos reales del mercado</p> |
33 | | - </div> |
34 | | - <div className="bg-white/10 backdrop-blur-lg rounded-xl p-6 text-white"> |
35 | | - <h3 className="text-xl font-semibold mb-2">Compara AFPs</h3> |
36 | | - <p className="text-blue-100">Encuentra la mejor AFP para maximizar tu pensión</p> |
37 | | - </div> |
38 | | - <div className="bg-white/10 backdrop-blur-lg rounded-xl p-6 text-white"> |
39 | | - <h3 className="text-xl font-semibold mb-2">Recomendaciones</h3> |
40 | | - <p className="text-blue-100">Recibe consejos personalizados para mejorar tu jubilación</p> |
41 | | - </div> |
42 | | - </div> |
| 97 | + <div className="min-h-screen w-full bg-cover bg-center flex flex-col items-center justify-center" style={{ backgroundImage: 'url(/bg-hero.png)' }}> |
| 98 | + <div className="mt-8 bg-white rounded-3xl shadow-2xl px-8 py-10 max-w-lg w-full flex flex-col items-center border-2 border-gray-200" style={{ minHeight: 420 }}> |
| 99 | + {/* Header */} |
| 100 | + <div className="mb-6"> |
| 101 | + <span className="text-3xl font-bold text-gray-700 mr-1">Me</span> |
| 102 | + <span className="text-3xl font-bold text-orange-400">Jubilo</span> |
| 103 | + </div> |
| 104 | + {/* Main Title */} |
| 105 | + <h1 className="text-4xl md:text-5xl font-bold text-center text-gray-900 mb-2"> |
| 106 | + Ya quieres <span className="text-orange-400">jubilar</span> ? |
| 107 | + </h1> |
| 108 | + {/* Subtext */} |
| 109 | + <p className="text-lg text-center text-gray-700 mb-6"> |
| 110 | + Descubre con cuánto $$<br />podrías jubilar <span className="font-bold">HOY</span>: |
| 111 | + </p> |
| 112 | + {/* Input and Button */} |
| 113 | + <input |
| 114 | + type="text" |
| 115 | + placeholder="Saldo AFP" |
| 116 | + value={saldo} |
| 117 | + onChange={e => { |
| 118 | + const value = e.target.value.replace(/[^0-9]/g, ''); |
| 119 | + setSaldo(value); |
| 120 | + }} |
| 121 | + className="w-full max-w-xs px-4 py-3 mb-4 border border-gray-400 rounded-lg text-center text-lg focus:outline-none focus:ring-2 focus:ring-blue-400 placeholder:text-gray-700 text-gray-700" |
| 122 | + /> |
| 123 | + <button |
| 124 | + className="w-full max-w-xs bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 rounded-full text-lg shadow-md transition-colors flex items-center justify-center mb-2" |
| 125 | + onClick={handleCalculate} |
| 126 | + > |
| 127 | + Quiero saber <span className="ml-2">👀</span> |
| 128 | + </button> |
| 129 | + {/* Result Box o Calculando */} |
| 130 | + {isCalculating ? ( |
| 131 | + <CalculandoScreen /> |
| 132 | + ) : result && ( |
| 133 | + <div className="mt-6 w-full max-w-xs bg-blue-50 border-2 border-blue-200 rounded-2xl p-5 text-center shadow-lg animate-fade-in"> |
| 134 | + <h2 className="text-xl font-bold text-blue-900 mb-2">¡Tu pensión estimada!</h2> |
| 135 | + <div className="text-lg text-gray-700 mb-1 flex justify-between"><span>Renta Vitalicia:</span> <span className="font-semibold">${result.rentaVitalicia.toLocaleString('es-CL')}</span></div> |
| 136 | + <div className="text-lg text-gray-700 mb-1 flex justify-between"><span>Seguro Social:</span> <span className="font-semibold">${result.seguroSocial.toLocaleString('es-CL')}</span></div> |
| 137 | + <div className="text-lg text-gray-700 mb-1 flex justify-between"><span>PGU:</span> <span className="font-semibold">${result.pgu.toLocaleString('es-CL')}</span></div> |
| 138 | + <hr className="my-2 border-blue-200" /> |
| 139 | + <div className="text-lg font-bold text-blue-800 flex justify-between"><span>Total:</span> <span>${result.total.toLocaleString('es-CL')}</span></div> |
43 | 140 | </div> |
44 | | - </main> |
45 | | - </section> |
46 | | - |
47 | | - <PricingSection /> |
48 | | - <FAQSection /> |
49 | | - <Footer /> |
| 141 | + )} |
| 142 | + </div> |
50 | 143 | </div> |
51 | 144 | ); |
52 | 145 | } |
0 commit comments