Actualizar plan-tranquilidad.html

This commit is contained in:
2026-04-02 21:45:59 +00:00
parent f6ad94de67
commit 1467724dc2

View File

@@ -3,91 +3,161 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<title>Contratar Plan Tranquilidad</title> <title>Plan Tranquilidad - Protege tu Hogar</title>
<script src="https://cdn.tailwindcss.com"></script> <script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/lucide@latest"></script> <script src="https://unpkg.com/lucide@latest"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
<style> <style>
:root { --primary: #2563eb; --secondary: #f59e0b; --app-bg: #f8fafc; } :root { --primary: #2563eb; --secondary: #f59e0b; --app-bg: #f8fafc; }
body { background-color: var(--app-bg); -webkit-tap-highlight-color: transparent; } body { background-color: var(--app-bg); -webkit-tap-highlight-color: transparent; }
.glass-header { background: linear-gradient(135deg, #1e40af 0%, #2563eb 100%); }
.hero-bg {
background-image: linear-gradient(to bottom, rgba(30, 58, 138, 0.85), rgba(37, 99, 235, 0.95)), url('https://images.unsplash.com/photo-1560518883-ce09059eeffa?auto=format&fit=crop&w=1000&q=80');
background-size: cover;
background-position: center;
}
.plan-card { transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); border: 2px solid transparent; } .plan-card { transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); border: 2px solid transparent; }
.plan-card.active { border-color: var(--primary); background-color: #fff; transform: translateY(-5px); box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); } .plan-card.active { border-color: var(--primary); background-color: #fff; transform: translateY(-5px); box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); }
#signature-pad { background: #fff; touch-action: none; cursor: crosshair; border: 2px solid #e2e8f0; }
.benefit-icon { background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%); } #signature-pad { background: #fff; touch-action: none; cursor: crosshair; border: 2px dashed #cbd5e1; }
@keyframes pulse-soft { 0% { transform: scale(1); } 50% { transform: scale(1.02); } 100% { transform: scale(1); } } @keyframes pulse-soft { 0% { transform: scale(1); } 50% { transform: scale(1.02); } 100% { transform: scale(1); } }
.animate-offer { animation: pulse-soft 2s infinite; } .animate-offer { animation: pulse-soft 2s infinite; }
.fade-in { animation: fadeIn 0.4s ease-out forwards; } .fade-in { animation: fadeIn 0.5s ease-out forwards; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } @keyframes fadeIn { from { opacity: 0; transform: translateY(15px); } to { opacity: 1; transform: translateY(0); } }
.benefit-icon { background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%); }
</style> </style>
</head> </head>
<body class="text-slate-800 font-sans antialiased pb-20 min-h-screen flex flex-col"> <body class="text-slate-800 font-sans antialiased pb-20 min-h-screen flex flex-col max-w-md mx-auto bg-white shadow-2xl relative">
<header class="glass-header text-white px-6 pt-12 pb-24 rounded-b-[3rem] relative shadow-2xl overflow-hidden shrink-0"> <header class="hero-bg text-white px-6 pt-10 pb-28 rounded-b-[2.5rem] relative shadow-lg shrink-0">
<div class="absolute top-0 right-0 -mr-20 -mt-20 w-64 h-64 bg-white/10 rounded-full blur-3xl"></div> <button onclick="goBackToPortal()" class="absolute top-6 left-6 w-10 h-10 bg-white/20 rounded-full flex items-center justify-center backdrop-blur-md active:scale-90 transition-transform z-10 border border-white/30">
<button onclick="goBackToPortal()" class="absolute top-8 left-6 w-10 h-10 bg-white/20 rounded-full flex items-center justify-center backdrop-blur-md active:scale-90 transition-transform z-10">
<i data-lucide="chevron-left" class="w-6 h-6"></i> <i data-lucide="chevron-left" class="w-6 h-6"></i>
</button> </button>
<div class="relative z-10 text-center space-y-2"> <div class="relative z-10 text-center space-y-3 mt-8">
<span id="company-name-badge" class="bg-blue-400/30 text-blue-100 text-[10px] font-black px-3 py-1 rounded-full uppercase tracking-[0.2em] backdrop-blur-sm">Cargando...</span> <span id="company-name-badge" class="bg-blue-400/40 text-blue-50 text-[10px] font-black px-4 py-1.5 rounded-full uppercase tracking-widest backdrop-blur-md border border-blue-300/30 shadow-sm">
<h1 class="text-3xl font-black tracking-tight leading-none">Plan <span class="text-blue-300">Tranquilidad</span></h1> Cargando...
<p class="text-blue-100/80 text-sm font-medium">Asistencia técnica garantizada para tu hogar</p> </span>
<h1 class="text-4xl font-black tracking-tight leading-tight mt-4">
Plan <span class="text-amber-400">Tranquilidad</span>
</h1>
<p class="text-blue-100 text-sm font-medium px-4 leading-relaxed">
El seguro de mantenimiento que evita facturas sorpresa y te da prioridad absoluta.
</p>
</div> </div>
</header> </header>
<main class="px-6 -mt-16 relative z-20 flex-1 flex flex-col"> <main class="px-5 -mt-16 relative z-20 flex-1 flex flex-col space-y-6">
<div id="loader" class="bg-white p-10 rounded-[2.5rem] shadow-xl text-center space-y-4"> <div id="loader" class="bg-white p-10 rounded-[2rem] shadow-xl text-center space-y-4 border border-slate-100">
<i data-lucide="loader-2" class="w-8 h-8 text-blue-600 animate-spin mx-auto"></i> <i data-lucide="loader-2" class="w-8 h-8 text-blue-600 animate-spin mx-auto"></i>
<p class="text-xs font-bold text-slate-500 uppercase tracking-widest">Cargando planes...</p> <p class="text-xs font-bold text-slate-500 uppercase tracking-widest">Cargando ofertas...</p>
</div> </div>
<div id="already-subscribed-container" class="hidden bg-white p-8 rounded-[2.5rem] shadow-xl text-center space-y-6 fade-in flex-1"> <div id="already-subscribed-container" class="hidden bg-white p-8 rounded-[2rem] shadow-xl text-center space-y-6 fade-in flex-1 border border-slate-100">
<div class="w-20 h-20 bg-emerald-100 text-emerald-600 rounded-full flex items-center justify-center mx-auto shadow-inner"> <div class="w-24 h-24 bg-emerald-50 text-emerald-500 rounded-full flex items-center justify-center mx-auto shadow-inner border border-emerald-100">
<i data-lucide="shield-check" class="w-10 h-10"></i> <i data-lucide="shield-check" class="w-12 h-12"></i>
</div> </div>
<div> <div>
<h2 class="text-xl font-black tracking-tight text-slate-800">¡Tu hogar ya está protegido!</h2> <h2 class="text-2xl font-black tracking-tight text-slate-800">¡Ya estás protegido!</h2>
<p class="text-sm text-slate-500 mt-2 font-medium">Actualmente tienes activo el <strong id="active-plan-name" class="text-blue-600">Plan</strong>.</p> <p class="text-sm text-slate-500 mt-2 font-medium">Actualmente tienes activo el <strong id="active-plan-name" class="text-blue-600">Plan</strong>.</p>
<p class="text-xs text-slate-400 mt-4 bg-slate-50 p-4 rounded-2xl border border-slate-100">No es necesario volver a contratar. Puedes consultar el estado de tus coberturas (urgencias y bricos) directamente desde tu portal principal.</p> <div class="text-xs text-slate-500 mt-6 bg-slate-50 p-4 rounded-2xl border border-slate-100 text-left space-y-2">
<p class="flex items-center gap-2"><i data-lucide="check-circle-2" class="w-4 h-4 text-emerald-500"></i> Cobertura de urgencias activa</p>
<p class="flex items-center gap-2"><i data-lucide="check-circle-2" class="w-4 h-4 text-emerald-500"></i> Desplazamientos gratuitos</p>
<p class="flex items-center gap-2"><i data-lucide="check-circle-2" class="w-4 h-4 text-emerald-500"></i> Prioridad en la agenda</p>
</div>
</div> </div>
<button onclick="goBackToPortal()" class="w-full bg-slate-800 text-white font-black py-4 rounded-2xl shadow-lg active:scale-95 transition-all uppercase tracking-widest text-xs mt-4"> <button onclick="goBackToPortal()" class="w-full bg-slate-900 text-white font-black py-4 rounded-2xl shadow-lg active:scale-95 transition-all uppercase tracking-widest text-xs mt-4">
Volver a mi Portal Volver a mi Portal
</button> </button>
</div> </div>
<div id="contract-container" class="hidden space-y-6 fade-in pb-10"> <div id="contract-container" class="hidden space-y-8 fade-in pb-10">
<div class="space-y-4"> <div class="bg-white p-6 rounded-[2rem] shadow-xl border border-slate-100 mt-2">
<h3 class="text-[11px] font-black text-slate-400 uppercase tracking-[0.15em] ml-2">Selecciona tu plan</h3> <h2 class="text-lg font-black text-slate-800 mb-5 text-center tracking-tight">¿Por qué necesitas este plan?</h2>
<div id="plans-wrapper" class="space-y-4"></div>
</div> <div class="space-y-5">
<div class="flex items-start gap-4">
<div class="benefit-icon w-12 h-12 rounded-2xl flex items-center justify-center shrink-0 border border-blue-100">
<i data-lucide="zap" class="text-blue-600 w-5 h-5"></i>
</div>
<div>
<h3 class="font-black text-slate-800 text-sm">Urgencias sin sustos</h3>
<p class="text-xs text-slate-500 mt-1 leading-relaxed">Si te quedas sin luz o hay riesgo de avería grave, acudimos en menos de 3h. <b>Desplazamiento y mano de obra a 0€.</b></p>
</div>
</div>
<div class="bg-white p-6 rounded-[2.5rem] shadow-xl border border-slate-100 space-y-4"> <div class="flex items-start gap-4">
<div class="text-center"> <div class="w-12 h-12 bg-amber-50 rounded-2xl flex items-center justify-center shrink-0 border border-amber-100">
<h3 class="text-[11px] font-black text-slate-400 uppercase tracking-widest">Firma Digital del Contrato</h3> <i data-lucide="hammer" class="text-amber-500 w-5 h-5"></i>
<p class="text-[10px] text-slate-400 mt-1 italic">Usa tu dedo o puntero para firmar dentro del recuadro</p> </div>
</div> <div>
<canvas id="signature-pad" class="w-full h-44 rounded-3xl shadow-inner"></canvas> <h3 class="font-black text-slate-800 text-sm">Tu Manitas Privado</h3>
<div class="flex justify-between items-center px-2"> <p class="text-xs text-slate-500 mt-1 leading-relaxed">¿Necesitas cambiar un enchufe, colgar una lámpara o instalar un ventilador? Tienes servicios de bricolaje incluidos al año.</p>
<button onclick="clearSignature()" class="flex items-center gap-1 text-[10px] font-black text-rose-500 uppercase tracking-tighter"> </div>
<i data-lucide="trash-2" class="w-3.5 h-3.5"></i> Borrar Firma </div>
</button>
<div class="flex items-center gap-1 text-emerald-600"> <div class="flex items-start gap-4">
<i data-lucide="shield-check" class="w-3.5 h-3.5"></i> <div class="w-12 h-12 bg-emerald-50 rounded-2xl flex items-center justify-center shrink-0 border border-emerald-100">
<span class="text-[9px] font-bold uppercase">Validación Biométrica</span> <i data-lucide="check-square" class="text-emerald-600 w-5 h-5"></i>
</div>
<div>
<h3 class="font-black text-slate-800 text-sm">Revisión Preventiva</h3>
<p class="text-xs text-slate-500 mt-1 leading-relaxed">Chequeo anual de tu instalación eléctrica para evitar cortocircuitos e incendios. Duerme tranquilo.</p>
</div>
</div> </div>
</div> </div>
</div> </div>
<div class="py-2"> <div class="rounded-[2rem] overflow-hidden shadow-md relative h-32">
<button onclick="processContract()" id="btnAction" class="w-full bg-blue-600 text-white font-black py-5 rounded-[2rem] shadow-[0_15px_30px_-5px_rgba(37,99,235,0.4)] active:scale-95 transition-all uppercase tracking-[0.15em] text-sm flex justify-center items-center gap-3"> <img src="https://images.unsplash.com/photo-1581141849291-1125c7b692b5?auto=format&fit=crop&w=800&q=80" alt="Técnico" class="w-full h-full object-cover">
<i data-lucide="crown" class="w-5 h-5"></i> Firmar y Pagar <div class="absolute inset-0 bg-gradient-to-r from-blue-900/80 to-transparent flex items-center px-6">
<p class="text-white font-black text-lg w-2/3 leading-tight">Profesionales de confianza en tu hogar.</p>
</div>
</div>
<div class="space-y-4">
<div class="flex items-center justify-between ml-2">
<h3 class="text-[11px] font-black text-slate-400 uppercase tracking-[0.15em]">Elige tu suscripción</h3>
<span class="text-[9px] font-bold text-emerald-500 bg-emerald-50 px-2 py-1 rounded-md">Cancelable cuando quieras</span>
</div>
<div id="plans-wrapper" class="space-y-4">
</div>
</div>
<div class="bg-white p-6 rounded-[2.5rem] shadow-xl border border-slate-100 space-y-5">
<div class="text-center">
<div class="w-10 h-10 bg-slate-50 rounded-full flex items-center justify-center mx-auto mb-2 text-slate-400"><i data-lucide="pen-tool" class="w-5 h-5"></i></div>
<h3 class="text-sm font-black text-slate-800 uppercase tracking-tight">Firma el Contrato</h3>
<p class="text-[11px] text-slate-400 mt-1">Dibuja tu firma en el recuadro gris con tu dedo</p>
</div>
<div class="bg-slate-50 rounded-3xl p-1">
<canvas id="signature-pad" class="w-full h-40 rounded-3xl bg-white"></canvas>
</div>
<div class="flex justify-between items-center px-2">
<button onclick="clearSignature()" class="flex items-center gap-1.5 text-[10px] font-black text-rose-500 uppercase tracking-tighter bg-rose-50 px-3 py-1.5 rounded-lg active:scale-95 transition-transform">
<i data-lucide="eraser" class="w-3.5 h-3.5"></i> Borrar
</button>
<div class="flex items-center gap-1.5 text-blue-600 bg-blue-50 px-3 py-1.5 rounded-lg">
<i data-lucide="lock" class="w-3.5 h-3.5"></i>
<span class="text-[9px] font-black uppercase">Pago Seguro Stripe®</span>
</div>
</div>
</div>
<div class="py-2 sticky bottom-4 z-50">
<button onclick="processContract()" id="btnAction" class="w-full bg-blue-600 text-white font-black py-5 rounded-[2rem] shadow-[0_15px_30px_-5px_rgba(37,99,235,0.4)] active:scale-95 transition-all uppercase tracking-widest text-sm flex justify-center items-center gap-3 border-2 border-blue-500">
<i data-lucide="credit-card" class="w-5 h-5"></i> Confirmar y Pagar
</button> </button>
<p class="text-center text-[9px] text-slate-400 mt-4 px-6 leading-relaxed font-medium"> <p class="text-center text-[9px] text-slate-400 mt-4 px-4 leading-relaxed font-medium">
Al pulsar, confirmas que aceptas las condiciones. Se generará un PDF firmado y serás redirigido a la pasarela de pago segura (Stripe). Al pulsar, aceptas las <a href="#" class="underline text-blue-500">Condiciones Generales</a>. Se generará un PDF vinculante y serás dirigido a la pasarela bancaria.
</p> </p>
</div> </div>
</div> </div>
@@ -105,14 +175,11 @@
<span id="pdf-client-name">Cliente</span><br> <span id="pdf-client-name">Cliente</span><br>
</div> </div>
</div> </div>
<div id="pdf-dynamic-text" style="margin-bottom: 25px; background: #f8fafc; padding: 25px; border-radius: 12px; border: 1px solid #e2e8f0; white-space: pre-wrap;"></div> <div id="pdf-dynamic-text" style="margin-bottom: 25px; background: #f8fafc; padding: 25px; border-radius: 12px; border: 1px solid #e2e8f0; white-space: pre-wrap;"></div>
<div style="margin-top: 15px; border: 1px solid #e2e8f0; padding: 15px; border-radius: 8px; font-size: 10px;"> <div style="margin-top: 15px; border: 1px solid #e2e8f0; padding: 15px; border-radius: 8px; font-size: 10px;">
<p style="margin: 0;"><strong>Modalidad contratada:</strong> <span id="pdf-plan-name" style="color:#2563eb; font-weight:900;">...</span></p> <p style="margin: 0;"><strong>Modalidad contratada:</strong> <span id="pdf-plan-name" style="color:#2563eb; font-weight:900;">...</span></p>
<p id="pdf-timestamp" style="margin: 3px 0 0 0;">Documento firmado digitalmente el ...</p> <p id="pdf-timestamp" style="margin: 3px 0 0 0;">Documento firmado digitalmente el ...</p>
</div> </div>
<div style="margin-top: 50px;"> <div style="margin-top: 50px;">
<div style="display: flex; justify-content: space-between; align-items: flex-end;"> <div style="display: flex; justify-content: space-between; align-items: flex-end;">
<div style="width: 280px; text-align: center;"> <div style="width: 280px; text-align: center;">
@@ -146,7 +213,6 @@
let clientData = {}; let clientData = {};
let selectedPlanId = null; let selectedPlanId = null;
// CANVAS
const canvas = document.getElementById('signature-pad'); const canvas = document.getElementById('signature-pad');
const ctx = canvas.getContext('2d'); const ctx = canvas.getContext('2d');
let drawing = false; let drawing = false;
@@ -169,16 +235,15 @@
} }
function startDrawing(e) { if (e.touches && e.touches.length > 1) return; drawing = true; const pos = getPos(e); ctx.beginPath(); ctx.moveTo(pos.x, pos.y); } function startDrawing(e) { if (e.touches && e.touches.length > 1) return; drawing = true; const pos = getPos(e); ctx.beginPath(); ctx.moveTo(pos.x, pos.y); }
function draw(e) { if (!drawing) return; e.preventDefault(); const pos = getPos(e); ctx.lineTo(pos.x, pos.y); ctx.stroke(); } function draw(e) { if (!drawing) return; e.preventDefault(); const pos = getPos(e); ctx.lineTo(pos.x, pos.y); ctx.stroke(); }
canvas.addEventListener('mousedown', startDrawing); canvas.addEventListener('mousemove', draw); canvas.addEventListener('mouseup', () => drawing = false); canvas.addEventListener('mousedown', startDrawing); canvas.addEventListener('mousemove', draw); canvas.addEventListener('mouseup', () => drawing = false);
canvas.addEventListener('touchstart', startDrawing); canvas.addEventListener('touchmove', draw); canvas.addEventListener('touchend', () => drawing = false); canvas.addEventListener('touchstart', startDrawing); canvas.addEventListener('touchmove', draw); canvas.addEventListener('touchend', () => drawing = false);
function clearSignature() { ctx.clearRect(0, 0, canvas.width, canvas.height); } function clearSignature() { ctx.clearRect(0, 0, canvas.width, canvas.height); }
// REDIRECCIÓN VOLVER
function goBackToPortal() { function goBackToPortal() {
window.location.href = `index.html?token=${token}`; // Ajusta 'index.html' si tu portal principal se llama 'portal.html' window.location.href = `index.html?token=${token}`;
} }
// CARGA INICIAL
async function init() { async function init() {
if(!token) return alert("Enlace inválido. Falta el token de seguridad."); if(!token) return alert("Enlace inválido. Falta el token de seguridad.");
lucide.createIcons(); lucide.createIcons();
@@ -192,14 +257,12 @@
document.getElementById('company-name-badge').innerText = data.company.name; document.getElementById('company-name-badge').innerText = data.company.name;
document.getElementById('loader').classList.add('hidden'); document.getElementById('loader').classList.add('hidden');
// 🛑 ESCUDO: Si el cliente ya tiene seguro, bloqueamos la página
if (data.hasActivePlan && data.activePlanDetails) { if (data.hasActivePlan && data.activePlanDetails) {
document.getElementById('active-plan-name').innerText = data.activePlanDetails.plan_name; document.getElementById('active-plan-name').innerText = data.activePlanDetails.plan_name;
document.getElementById('already-subscribed-container').classList.remove('hidden'); document.getElementById('already-subscribed-container').classList.remove('hidden');
return; // Detenemos la ejecución aquí, no mostramos los planes return;
} }
// Si no tiene seguro, cargamos los datos y mostramos el contrato
loadedPlans = data.plans; loadedPlans = data.plans;
globalConfig = data.config; globalConfig = data.config;
clientData = data.client; clientData = data.client;
@@ -210,11 +273,8 @@
document.getElementById('pdf-dynamic-text').innerText = globalConfig.contract_text || "El mantenimiento y asistencia quedan cubiertos por las condiciones de la empresa proveedora."; document.getElementById('pdf-dynamic-text').innerText = globalConfig.contract_text || "El mantenimiento y asistencia quedan cubiertos por las condiciones de la empresa proveedora.";
renderPlans(); renderPlans();
// Mostrar contenedor
document.getElementById('contract-container').classList.remove('hidden'); document.getElementById('contract-container').classList.remove('hidden');
// Esperar a que el contenedor esté visible para configurar el canvas correctamente
setTimeout(() => { setTimeout(() => {
setupCanvas(); setupCanvas();
window.addEventListener('resize', setupCanvas); window.addEventListener('resize', setupCanvas);
@@ -223,34 +283,34 @@
lucide.createIcons(); lucide.createIcons();
} catch(e) { } catch(e) {
document.getElementById('loader').innerHTML = `<p class="text-rose-500 font-bold uppercase">${e.message}</p>`; document.getElementById('loader').innerHTML = `<p class="text-rose-500 font-bold uppercase text-center">${e.message}</p>`;
} }
} }
function renderPlans() { function renderPlans() {
const wrapper = document.getElementById('plans-wrapper'); const wrapper = document.getElementById('plans-wrapper');
if (loadedPlans.length === 0) { if (loadedPlans.length === 0) {
wrapper.innerHTML = `<p class="text-center text-xs font-bold text-slate-400 bg-white p-6 rounded-3xl">El catálogo de planes se está actualizando. Vuelve pronto.</p>`; wrapper.innerHTML = `<p class="text-center text-xs font-bold text-slate-400 bg-slate-50 p-6 rounded-3xl border border-slate-100">El catálogo de planes se está actualizando. Vuelve pronto.</p>`;
return; return;
} }
wrapper.innerHTML = loadedPlans.map((p, index) => { wrapper.innerHTML = loadedPlans.map((p, index) => {
const isRecommended = p.type === 'anual'; // Marcamos el anual como recomendado visualmente const isRecommended = p.type === 'anual';
return ` return `
<div onclick="selectPlan(${p.id})" id="card-${p.id}" class="plan-card ${index === 0 ? 'active' : 'bg-slate-50 border-slate-200'} p-6 rounded-[2.5rem] shadow-sm flex justify-between items-center cursor-pointer overflow-hidden relative"> <div onclick="selectPlan(${p.id})" id="card-${p.id}" class="plan-card ${index === 0 ? 'active' : 'bg-slate-50 border-slate-200'} p-5 rounded-[2rem] shadow-sm flex justify-between items-center cursor-pointer overflow-hidden relative">
${isRecommended ? `<div class="absolute top-0 right-0 bg-amber-500 text-white text-[9px] font-black px-4 py-1 rounded-bl-2xl uppercase tracking-tighter animate-offer">Recomendado</div>` : ''} ${isRecommended ? `<div class="absolute top-0 right-0 bg-amber-500 text-white text-[9px] font-black px-4 py-1 rounded-bl-2xl uppercase tracking-widest animate-offer shadow-sm">Ahorras dinero</div>` : ''}
<div class="flex items-center gap-4"> <div class="flex items-center gap-3">
<div class="w-6 h-6 rounded-full border-2 ${index === 0 ? 'border-blue-600' : 'border-slate-300'} flex items-center justify-center indicator-circle"> <div class="w-5 h-5 rounded-full border-2 ${index === 0 ? 'border-blue-600' : 'border-slate-300'} flex items-center justify-center indicator-circle shrink-0">
<div class="w-3 h-3 bg-blue-600 rounded-full ${index === 0 ? '' : 'hidden'} indicator-dot"></div> <div class="w-2.5 h-2.5 bg-blue-600 rounded-full ${index === 0 ? '' : 'hidden'} indicator-dot"></div>
</div> </div>
<div> <div>
<p class="font-black text-slate-800 text-base">${p.name}</p> <p class="font-black text-slate-800 text-sm leading-tight">${p.name}</p>
<p class="text-[10px] text-slate-500 font-bold uppercase tracking-widest">${p.urgencies_limit} Urgencias | ${p.bricos_limit} Bricos</p> <p class="text-[9px] text-slate-500 font-bold uppercase tracking-widest mt-0.5">${p.urgencies_limit} Urg | ${p.bricos_limit} Bricos</p>
</div> </div>
</div> </div>
<div class="text-right pl-4 border-l border-slate-100"> <div class="text-right pl-3 border-l border-slate-100 shrink-0">
<p class="text-2xl font-black text-blue-600 leading-none">${p.price}€</p> <p class="text-xl font-black text-blue-600 leading-none">${p.price}€</p>
<p class="text-[9px] font-black text-slate-400 uppercase mt-1">/ ${p.type}</p> <p class="text-[8px] font-black text-slate-400 uppercase mt-1 tracking-widest">/ ${p.type}</p>
</div> </div>
</div> </div>
`; `;
@@ -280,14 +340,13 @@
const blank = document.createElement('canvas'); const blank = document.createElement('canvas');
blank.width = canvas.width; blank.height = canvas.height; blank.width = canvas.width; blank.height = canvas.height;
if (canvas.toDataURL() === blank.toDataURL()) return alert("⚠️ Firma requerida: Por favor, firma el contrato en el recuadro blanco."); if (canvas.toDataURL() === blank.toDataURL()) return alert("⚠️ Firma requerida: Por favor, firma el contrato en el recuadro con rayas.");
const btn = document.getElementById('btnAction'); const btn = document.getElementById('btnAction');
btn.disabled = true; btn.disabled = true;
btn.innerHTML = '<i data-lucide="loader-2" class="w-5 h-5 animate-spin"></i> Generando Contrato...'; btn.innerHTML = '<i data-lucide="loader-2" class="w-5 h-5 animate-spin"></i> Preparando pasarela...';
lucide.createIcons(); lucide.createIcons();
// 1. Inyectar firma y datos en PDF
const planSeleccionado = loadedPlans.find(p => p.id === selectedPlanId); const planSeleccionado = loadedPlans.find(p => p.id === selectedPlanId);
document.getElementById('pdf-signature-img').src = canvas.toDataURL("image/png"); document.getElementById('pdf-signature-img').src = canvas.toDataURL("image/png");
document.getElementById('pdf-plan-name').innerText = `${planSeleccionado.name} (${planSeleccionado.price}€ / ${planSeleccionado.type})`; document.getElementById('pdf-plan-name').innerText = `${planSeleccionado.name} (${planSeleccionado.price}€ / ${planSeleccionado.type})`;
@@ -305,13 +364,8 @@
}; };
try { try {
// 2. Crear PDF (Internamente) y generar Base64
const pdfBase64 = await html2pdf().set(opt).from(element).output('datauristring'); const pdfBase64 = await html2pdf().set(opt).from(element).output('datauristring');
btn.innerHTML = '<i data-lucide="loader-2" class="w-5 h-5 animate-spin"></i> Conectando con pasarela...';
lucide.createIcons();
// 3. Mandar al Servidor (Que crea el alta y genera el link de Stripe)
const payload = { plan_id: selectedPlanId, signature: canvas.toDataURL("image/png"), pdf_document: pdfBase64 }; const payload = { plan_id: selectedPlanId, signature: canvas.toDataURL("image/png"), pdf_document: pdfBase64 };
const res = await fetch(`${API_URL}/public/portal/${token}/protection/subscribe`, { const res = await fetch(`${API_URL}/public/portal/${token}/protection/subscribe`, {
@@ -323,16 +377,15 @@
const apiData = await res.json(); const apiData = await res.json();
if (apiData.ok && apiData.checkout_url) { if (apiData.ok && apiData.checkout_url) {
// 4. Redirigir a Stripe
window.location.href = apiData.checkout_url; window.location.href = apiData.checkout_url;
} else { } else {
throw new Error(apiData.error || "No se pudo conectar con la pasarela de pago."); throw new Error(apiData.error || "No se pudo conectar con la pasarela de pago segura.");
} }
} catch (err) { } catch (err) {
alert("❌ Error: " + err.message); alert("❌ Error: " + err.message);
btn.disabled = false; btn.disabled = false;
btn.innerHTML = '<i data-lucide="crown" class="w-5 h-5"></i> Firmar y Pagar'; btn.innerHTML = '<i data-lucide="credit-card" class="w-5 h-5"></i> Confirmar y Pagar';
lucide.createIcons(); lucide.createIcons();
} finally { } finally {
element.classList.add('hidden'); element.classList.add('hidden');