1// pages/LegalPages.js 2import { i18n } from "../services/I18nService.js"; 3import { legalService } from "../services/LegalService.js"; 4 5// Helper para traducciones 6const t = (key) => i18n.t(key); 7 8/** 9 * --- 1. PÃGINA DE PREGUNTAS FRECUENTES (FAQ) --- 10 */ 11function renderQuestion(faq) { 12 return ` 13 <div class="bg-slate-50 p-6 rounded-2xl border border-slate-100 hover:shadow-md transition group"> 14 <h3 class="font-bold text-lg text-cdl-blue mb-2 group-hover:text-cdl-gold transition-colors">${faq.question}</h3> 15 <p class="text-slate-600 leading-relaxed">${faq.answer}</p> 16 </div>`; 17} 18 19function renderFAQSection(sec) { 20 const questionsHtml = sec.questions?.map(faq => renderQuestion(faq)).join('') || ''; 21 return ` 22 <section class="space-y-6"> 23 <div class="flex items-center gap-3 mb-6 border-b border-slate-100 pb-4"> 24 <div class="w-10 h-10 bg-amber-50 rounded-full flex items-center justify-center text-cdl-gold"> 25 <i data-lucide="help-circle" class="w-6 h-6"></i> 26 </div> 27 <h2 class="text-2xl font-black text-slate-800 uppercase tracking-tight italic">${sec.title}</h2> 28 </div> 29 <div class="grid grid-cols-1 gap-4"> 30 ${questionsHtml} 31 </div> 32 </section>`; 33} 34 35export function renderFAQPage() { 36 setTimeout(async () => { 37 try { 38 const response = await legalService.getFAQs(); 39 const container = document.getElementById('sections-container'); 40 if (container && response) { 41 container.innerHTML = response.map(section => renderFAQSection(section)).join('<div class="py-1"></div>'); 42 if (window.lucide) lucide.createIcons(); 43 } 44 } catch (e) { 45 console.error("Error cargando FAQs:", e); 46 } 47 }, 0); 48 49 return ` 50 <div class="w-full bg-white min-h-screen"> 51 <div class="pt-32 pb-12 px-6 max-w-7xl mx-auto text-center"> 52 <nav class="flex gap-2 justify-center text-xs text-slate-400 mb-6 uppercase tracking-widest font-bold" aria-label="Breadcrumb"> 53 <a href="/" class="hover:text-cdl-blue transition">${t('actions.home')}</a> 54 <span class="text-cdl-gold">/</span> 55 <span class="text-cdl-blue">${t('legal.faqs.nav') || 'FAQ'}</span> 56 </nav> 57 <h1 class="text-5xl md:text-7xl font-black text-cdl-blue mb-6 uppercase tracking-tighter italic leading-none"> 58 ${t('legal.faqs.title_1') || 'Preguntas'} <span class="text-cdl-gold bg-clip-text bg-gradient-to-r from-cdl-gold to-yellow-600">${t('legal.faqs.title_2') || 'Frecuentes'}</span> 59 </h1> 60 </div> 61 62 <div class="container mx-auto max-w-4xl px-4 pb-24"> 63 <div id="sections-container" class="space-y-12"> 64 <div class="flex flex-col items-center justify-center py-24 space-y-4"> 65 <div class="animate-spin rounded-full h-12 w-12 border-4 border-slate-200 border-t-cdl-gold"></div> 66 <p class="text-slate-400 font-medium animate-pulse">${t('actions.loader')}</p> 67 </div> 68 </div> 69 </div> 70 </div>`; 71} 72 73/** 74 * --- 2. PÃGINA DEL PORTAL DE TRANSPARENCIA --- 75 */ 76function renderTransparencyCard(card) { 77 return ` 78 <div class="group bg-white p-8 rounded-[2rem] border border-slate-100 shadow-lg hover:shadow-2xl hover:-translate-y-1 transition duration-300 flex items-start gap-6 cursor-pointer"> 79 <div class="w-16 h-16 bg-blue-50 rounded-2xl flex items-center justify-center flex-shrink-0 group-hover:bg-cdl-blue transition-colors text-cdl-blue group-hover:text-white"> 80 <i data-lucide="${card.icon || 'file-text'}" class="w-8 h-8"></i> 81 </div> 82 <div> 83 <h3 class="text-xl font-bold text-slate-900 mb-2 group-hover:text-cdl-blue transition">
83${card.title}</h3> 84 <p class="text-slate-500 text-sm mb-4 leading-relaxed">${card.subtitle}</p> 85 <span class="text-[10px] font-black text-cdl-gold uppercase tracking-widest flex items-center gap-1"> 86 ${t('legal.transparency.card_btn') || 'Ver Documento'} <i data-lucide="arrow-right" class="w-3 h-3"></i> 87 </span> 88 </div> 89 </div>`; 90} 91 92export function renderTransparencyPage() { 93 setTimeout(async () => { 94 try { 95 const data = await legalService.getLegalContent('transparency'); 96 const container = document.getElementById('transparency-root'); 97 98 if (data && container) { 99 container.innerHTML = ` 100 <div class="pt-32 pb-12 px-6 max-w-7xl mx-auto text-center"> 101 <nav class="flex justify-center text-[10px] text-slate-400 mb-6 uppercase tracking-[0.2em] font-black items-center gap-2"> 102 <a href="/" class="hover:text-cdl-blue transition">${t('actions.home')}</a> 103 <span class="text-cdl-gold">/</span> 104 <span class="text-cdl-blue">${data.title}</span> 105 </nav> 106 <h1 class="text-5xl md:text-7xl font-black text-cdl-blue mb-6 uppercase tracking-tighter italic leading-none">${data.title}</h1> 107 <p class="text-lg text-slate-500 max-w-3xl mx-auto leading-relaxed">${data.subtitle}</p> 108 </div> 109 110 <div class="container mx-auto max-w-6xl px-4 pb-24"> 111 <div class="grid grid-cols-1 md:grid-cols-2 gap-8"> 112 ${data.sections?.map(c => renderTransparencyCard(c)).join('') || ''} 113 </div> 114 ${data.lastUpdated ? `<p class="mt-16 text-center text-[10px] text-slate-400 font-bold uppercase tracking-widest">Actualizado: ${data.lastUpdated}</p>` : ''} 115 </div>`; 116 if (window.lucide) lucide.createIcons(); 117 } 118 } catch (e) { 119 console.error("Error en Transparencia:", e); 120 } 121 }, 0); 122 123 return `<div id="transparency-root" class="w-full bg-white min-h-screen flex items-center justify-center"> 124 <div class="animate-spin rounded-full h-12 w-12 border-4 border-slate-200 border-t-cdl-gold"></div> 125 </div>`; 126} 127 128/** 129 * --- 3. PÃGINAS LEGALES GENÃRICAS (AVISO / PRIVACIDAD) --- 130 */ 131function renderLegalLayout(data) { 132 const t = (key) => i18n.t(key); 133 if (!data) return `<div class="pt-48 text-center text-slate-400">${t('actions.error_loading') || 'Contenido no disponible'}</div>`; 134 135 return ` 136 <div class="w-full bg-white min-h-screen"> 137 <div class="pt-40 pb-24 px-6 max-w-4xl mx-auto"> 138 <h1 class="text-5xl font-black text-cdl-blue mb-2 uppercase tracking-tighter italic">${data.title}</h1> 139 <p class="text-sm font-bold text-cdl-gold uppercase tracking-[0.3em] mb-12 border-b border-slate-100 pb-6">${data.subtitle}</p> 140 141 <div class="prose prose-slate max-w-none text-slate-600 leading-relaxed space-y-6"> 142 ${data.content || `<p>${t('legal.text_loader')}</p>`} 143 </div> 144 145 ${data.lastUpdated ? ` 146 <div class="mt-20 pt-8 border-t border-slate-100 text-[10px] text-slate-400 font-black uppercase tracking-widest"> 147 ${t('legal.last_update') || 'Ãltima actualización'}: ${data.lastUpdated} 148 </div> 149 ` : ''} 150 </div> 151 </div>`; 152} 153 154export function renderLegalNoticePage() { 155 setTimeout(async () => { 156 const data = await legalService.getLegalContent('legal-notice'); 157 const root = document.getElementById('legal-root'); 158 if (root) root.innerHTML = renderLegalLayout(data); 159 }, 0); 160 return `<div id="legal-root" class="min-h-screen bg-white"></div>`; 161} 162 163export function renderPrivacyPolicyPage() { 164 setTimeout(async () => { 165 const data = await legalService.getLegalContent('privacy-policy'); 166 const root = document.getElementById('legal-root'); 167 if (root) root.innerHTML = renderLegalLayout(data); 168 }, 0); 169 return `<div id="legal-root" class="min-h-screen bg-white"></div>`; 170}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.