PageSourceSearch

https://www.ciudaddelaluz.com/pages/LegalPages.js

js ciudaddelaluz.com collected 2026-10-02 12:56:54 UTC 8,311 bytes, 170 lines download raw bytes

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.