Ingresar

Crear cuenta

Configuración de tema

Seguidos

Comparación de cursos

'), fetch('./footer.html').then(r=>r.text()).catch(()=>'') ]); document.querySelector('header').innerHTML = h; document.querySelector('footer').innerHTML = f; document.dispatchEvent(new CustomEvent('layout:ready')); } injectLayout(); const key='favorites'; const list = document.getElementById('listaFavs'); const tpl = document.getElementById('tplFav'); const btnCmp = document.getElementById('btnComparar'); const selAll = document.getElementById('selAll'); const toastWrap = document.getElementById('toast_t9x4y'); const cmpDialog = document.getElementById('modalComparar'); const cmpWrap = document.getElementById('cmpWrap'); const cmpDelta = document.getElementById('cmpDelta'); const cmpTimer = document.getElementById('cmpTimer'); let timerInt = null; let data = []; let consent = localStorage.getItem('consent'); function showToast(msg, type='info'){ const id = 't_'+Math.random().toString(36).slice(2,8); const base = document.createElement('div'); base.id=id; const colors = type==='error' ? 'bg-red-600 text-white' : type==='success' ? 'bg-emerald-600 text-white' : 'bg-gray-900 text-white dark:bg-white dark:text-gray-900'; base.className = 'rounded-md px-3 py-2 text-sm shadow '+colors; base.textContent = msg; toastWrap.appendChild(base); setTimeout(()=>{ base.classList.add('opacity-0','transition'); }, 3000); setTimeout(()=>{ base.remove(); }, 3500); return id; } function fmtARS(n){ try{ return n.toLocaleString('es-AR', { style:'currency', currency:'ARS', maximumFractionDigits:0 }); } catch(e){ return 'ARS $ '+Number(n||0).toFixed(0); } } async function load(){ try{ const res = await fetch('./catalog.json', { cache:'no-store' }); if(!res.ok) throw new Error('No se pudo cargar el catálogo'); data = await res.json(); render(); }catch(e){ showToast('Error al cargar datos: '+(e.message||'desconocido'), 'error'); list.innerHTML = ''; const empty = document.createElement('li'); empty.className = 'col-span-full border-2 border-dashed rounded-xl p-8 text-center text-gray-600 dark:text-gray-300'; empty.textContent = 'No se pudo cargar el catálogo. Reintentá en unos minutos.'; list.appendChild(empty); } } function getFavs(){ try{ const arr = JSON.parse(localStorage.getItem(key)||'[]'); return Array.isArray(arr) ? arr : []; }catch(e){ return []; } } function setFavs(setOrArr){ const arr = Array.isArray(setOrArr) ? setOrArr : [...setOrArr]; localStorage.setItem(key, JSON.stringify(arr)); } function render(){ const favs = new Set(getFavs()); const arr = data.filter(d=>favs.has(d.id)); list.innerHTML=''; if(arr.length===0){ const empty = document.createElement('li'); empty.className = 'col-span-full border-2 border-dashed rounded-xl p-8 text-center text-gray-600 dark:text-gray-300'; empty.innerHTML = 'Todavía no seguís ningún curso. Volvé al catálogo y marcá algunos como favoritos ⭐'; list.appendChild(empty); btnCmp.disabled = true; btnCmp.textContent = 'Comparar (0)'; selAll.checked = false; return; } arr.forEach(c=>{ const li = tpl.content.cloneNode(true); const root = li.querySelector('li'); root.dataset.id = c.id; root.dataset.price = c.priceARS || 0; li.querySelector('h3').textContent = c.title; const img = li.querySelector('img'); img.src=c.image; img.alt=c.title; li.querySelector('p').textContent = c.shortDescription || ''; const priceRow = li.querySelector('.priceRow'); priceRow.textContent = c.priceARS ? fmtARS(c.priceARS) : 'Consultar precio'; const meta = li.querySelector('.metaRow'); meta.textContent = [c.level,c.format,(c.durationHours?c.durationHours+' h': '')].filter(Boolean).join(' • '); const rm = li.querySelector('.btnRemove'); rm.addEventListener('click', ()=>{ const ok = confirm('¿Quitar "'+c.title+'"?'); if(!ok) return; favs.delete(c.id); setFavs(favs); showToast('Quitado de Seguidos', 'success'); render(); }); const chk = li.querySelector('.chkComparar'); chk.addEventListener('change', onCheckChange); list.appendChild(li); }); updateCmpState(); } function selectedIds(){ return [...document.querySelectorAll('#listaFavs .chkComparar')] .map((el,idx)=>({el, idx, id: el.closest('li')?.dataset.id})) .filter(x=>x.el.checked) .map(x=>x.id); } function onCheckChange(e){ const checks = [...document.querySelectorAll('.chkComparar')]; const selected = checks.filter(c=>c.checked); if(selected.length>2){ e.target.checked = false; showToast('Solo podés comparar 2 cursos a la vez', 'info'); } updateCmpState(); syncSelAllState(); } function updateCmpState(){ const count = selectedIds().length; btnCmp.disabled = !(count===2); btnCmp.textContent = 'Comparar ('+count+')'; } function syncSelAllState(){ const checks = [...document.querySelectorAll('.chkComparar')]; if(checks.length===0){ selAll.checked=false; return; } selAll.checked = checks.every(c=>c.checked); selAll.indeterminate = !selAll.checked && checks.some(c=>c.checked); } selAll.addEventListener('change', ()=>{ const checks = [...document.querySelectorAll('.chkComparar')]; if(selAll.checked){ let cnt=0; for(const c of checks){ if(cnt>=2){ c.checked=false; continue; } c.checked=true; cnt++; } if(checks.length>2) showToast('Se seleccionaron los 2 primeros para comparar', 'info'); }else{ checks.forEach(c=>c.checked=false); } updateCmpState(); syncSelAllState(); }); document.getElementById('btnComparar').addEventListener('click', ()=>{ const ids = selectedIds(); if(ids.length!==2) return; const selected = data.filter(d=> ids.includes(String(d.id))); buildComparison(selected[0], selected[1]); cmpDialog.showModal(); startCmpTimer(120); }); function buildComparison(a,b){ cmpWrap.innerHTML=''; cmpDelta.innerHTML=''; const card = (c)=>{ const box = document.createElement('div'); box.className = 'border rounded-lg p-4 dark:border-gray-800'; box.innerHTML = '

'+c.title+'

'+ ''+c.title+''+ ''+ '

'+(c.shortDescription||'')+'

'; return box; }; cmpWrap.appendChild(card(a)); cmpWrap.appendChild(card(b)); const pa = Number(a.priceARS||0), pb = Number(b.priceARS||0); if(pa && pb){ const diff = Math.abs(pa-pb); const cheaper = pa. Más económico: '+cheaper+'.'; } } function startCmpTimer(sec){ clearInterval(timerInt); let t = sec; const tick = ()=>{ const m = String(Math.floor(t/60)).padStart(2,'0'); const s = String(t%60).padStart(2,'0'); cmpTimer.textContent = 'Cierre automático en '+m+':'+s; if(t<=0){ clearInterval(timerInt); cmpDialog.close(); cmpTimer.textContent = ''; } t--; }; tick(); timerInt = setInterval(tick,1000); } document.addEventListener('click', (e)=>{ const closers = e.target.closest('[data-close]'); if(closers){ const sel = closers.getAttribute('data-close'); const el = document.querySelector(sel); if(el && typeof el.close==='function') el.close(); } }); cmpDialog.addEventListener('close', ()=>{ clearInterval(timerInt); cmpTimer.textContent=''; }); const alertEmail = document.getElementById('alertEmail'); const btnAlert = document.getElementById('btnAlert'); (function initEmail(){ const saved = localStorage.getItem('alertsEmail')||''; if(saved) alertEmail.value = saved; })(); function validEmail(v){ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(v).trim()); } btnAlert.addEventListener('click', ()=>{ const v = alertEmail.value.trim(); if(!validEmail(v)){ alertEmail.classList.add('ring-2','ring-red-500'); showToast('Ingresá un email válido', 'error'); setTimeout(()=>alertEmail.classList.remove('ring-2','ring-red-500'),1200); return; } localStorage.setItem('alertsEmail', v); showToast('Alertas activadas para '+v, 'success'); }); const themeBtn = document.getElementById('tToggle_a7vmm'); const themeIcon = document.getElementById('tIcon_a7vmm'); function refreshThemeIcon(){ const dark = document.documentElement.classList.contains('dark'); themeIcon.textContent = dark ? '☀️' : '🌙'; } themeBtn.addEventListener('click', ()=>{ const isDark = document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', isDark ? 'dark' : 'light'); refreshThemeIcon(); }); refreshThemeIcon(); const cookieBar = document.getElementById('cookie_u9z31'); const btnAccept = document.getElementById('cookieAccept_b2k8m'); const btnDecline = document.getElementById('cookieDecline_k0p4d'); function ensureConsent(){ consent = localStorage.getItem('consent'); if(!consent){ cookieBar.classList.remove('hidden'); } } btnAccept.addEventListener('click', ()=>{ localStorage.setItem('consent','yes'); cookieBar.classList.add('hidden'); showToast('Gracias, preferencias guardadas', 'success'); }); btnDecline.addEventListener('click', ()=>{ localStorage.setItem('consent','no'); cookieBar.classList.add('hidden'); showToast('Podés cambiar tus preferencias más tarde', 'info'); }); ensureConsent(); document.addEventListener('keydown', (e)=>{ if(e.key==='Escape' && cmpDialog.open) cmpDialog.close(); }); load();