// ============ AcademIA8 · Consola — componentes UI compartidos ============ const { useState, useRef, useEffect } = React; // ---------- Iconos (línea, ~1.8px, esquinas redondeadas — estilo de marca) ---------- const PATHS = { courses:'M4 5.5A1.5 1.5 0 0 1 5.5 4H18a2 2 0 0 1 2 2v13.5M4 5.5V18a2 2 0 0 0 2 2h14M4 5.5A1.5 1.5 0 0 0 4 8.5H18', layers:'M12 3 2 8l10 5 10-5-10-5ZM2 12l10 5 10-5M2 16l10 5 10-5', publish:'M12 19V6M5 12l7-7 7 7', plus:'M12 5v14M5 12h14', edit:'M12 20h9M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4Z', trash:'M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6', drag:'M9 5h.01M9 12h.01M9 19h.01M15 5h.01M15 12h.01M15 19h.01', up:'M18 15l-6-6-6 6', down:'M6 9l6 6 6-6', check:'M20 6 9 17l-5-5', x:'M18 6 6 18M6 6l12 12', text:'M4 6h16M4 12h16M4 18h10', video:'M15 10l4.5-2.6v9.2L15 14M3 6h12v12H3z', audio:'M9 18V5l10-2v13M9 18a3 3 0 1 1-6 0 3 3 0 0 1 6 0ZM19 16a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z', image:'M3 5h18v14H3zM3 15l5-5 4 4 3-3 6 6', question:'M9.1 9a3 3 0 1 1 5 2.2c-.9.8-2.1 1.3-2.1 2.8M12 17h.01', search:'M11 4a7 7 0 1 0 0 14 7 7 0 0 0 0-14ZM21 21l-4.3-4.3', clock:'M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18ZM12 7v5l3 2', calendar:'M3 5h18v16H3zM3 10h18M8 3v4M16 3v4', eye:'M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12ZM12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z', alert:'M12 3 2 20h20L12 3ZM12 10v4M12 17h.01', play:'M6 4l14 8-14 8V4Z', upload:'M12 15V3M8 7l4-4 4 4M4 15v4a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-4', refresh:'M4 9a8 8 0 0 1 14-3l2 2M20 15a8 8 0 0 1-14 3l-2-2M18 4v4h-4M6 20v-4h4', chevright:'M9 6l6 6-6 6', settings:'M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM19.4 13.5a1.6 1.6 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.6 1.6 0 0 0-2.7 1.1V21a2 2 0 1 1-4 0v-.1a1.6 1.6 0 0 0-2.7-1.1l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.6 1.6 0 0 0-1.1-2.7H3a2 2 0 1 1 0-4h.1a1.6 1.6 0 0 0 1.1-2.7l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.6 1.6 0 0 0 2.7-1.1V3a2 2 0 1 1 4 0v.1a1.6 1.6 0 0 0 2.7 1.1l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.6 1.6 0 0 0-.3 1.8Z', send:'M22 2 11 13M22 2l-7 20-4-9-9-4 20-7Z', copy:'M9 9h11v11H9zM5 15H4V4h11v1', help:'M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18ZM9.6 9a2.4 2.4 0 1 1 3.4 2.2c-.8.4-1 1-1 1.7M12 17h.01', doc:'M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8ZM14 3v5h5M9 13h6M9 17h4', chat:'M21 12a8 8 0 0 1-8 8 8.5 8.5 0 0 1-3.6-.8L3 20l1-4.4A8 8 0 1 1 21 12ZM8 11h.01M12 11h.01M16 11h.01', infinity:'M6 8a4 4 0 1 0 0 8c2 0 3.2-1.5 4-3 1.2-2.3 2.2-5 6-5a4 4 0 0 1 0 8c-3.8 0-4.8-2.7-6-5-.8-1.5-2-3-4-3Z', sort:'M4 7h11M4 12h7M4 17h4M18 5v14M18 19l-3.5-3.5M18 19l3.5-3.5', logout:'M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4M10 17l-5-5 5-5M5 12h11', sidebar:'M4 4h16v16H4zM9 4v16', panelclose:'M4 4h16v16H4zM9 4v16M15 9l-2 3 2 3', panelopen:'M4 4h16v16H4zM9 4v16M13 9l2 3-2 3', money:'M12 1v22M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6', }; function Icon({ name, style }){ const d = PATHS[name] || ''; return ( {d.split('M').filter(Boolean).map((seg,i)=>)} ); } const FRAG_ICON = { texto:'text', video:'video', audio:'audio', imagen:'image', documento:'doc' }; const FRAG_LABEL = { texto:'Texto', video:'Video', audio:'Audio', imagen:'Imagen', documento:'Documento' }; // ---------- Botón ---------- function Btn({ variant='ghost', size, icon, iconRight, children, ...rest }){ const cls = `btn btn-${variant}${size==='sm'?' btn-sm':''}`; return ( ); } function IconBtn({ icon, danger, title, ...rest }){ return ; } // ---------- Pill de estado del curso ---------- function StatusPill({ status }){ if (status==='draft-only') return Borrador · sin publicar; if (status==='published-dirty') return Cambios sin publicar; return Publicado; } // ---------- Toggle global Borrador / Publicado ---------- function ViewToggle({ value, onChange, disabled }){ return (
Estás viendo
); } // ---------- Modal ---------- function Modal({ title, subtitle, icon, danger, wide, onClose, children, foot }){ useEffect(()=>{ const h = (e)=>{ if(e.key==='Escape') onClose(); }; window.addEventListener('keydown', h); return ()=>window.removeEventListener('keydown', h); },[]); return (
{ if(e.target===e.currentTarget) onClose(); }}>
{icon &&
}
{title}
{subtitle &&
{subtitle}
}
{children}
{foot &&
{foot}
}
); } // ---------- Field ---------- function Field({ label, optional, hint, children }){ return (
{label && } {children} {hint &&
{hint}
}
); } // ---------- Toast ---------- function Toast({ msg }){ return
{msg}
; } // ---------- Confirmar borrado ---------- function ConfirmDelete({ what, detail, onClose, onConfirm }){ return (
CancelarSí, borrar}>

{detail}

); } // ---------- HelpTip: ícono ? + popover con reglas (reutilizable) ---------- function HelpTip({ title, children, align }){ const [open,setOpen]=useState(false); return ( setOpen(true)} onMouseLeave={()=>setOpen(false)}> {open && ( e.stopPropagation()}> {title && {title}} {children} )} ); } // ---------- Indicador de sesión (usuario logueado vía Cognito) ---------- function SessionMenu({ user, onLogout }){ const [open,setOpen]=useState(false); const ref=useRef(null); useEffect(()=>{ if(!open) return; const h=(e)=>{ if(ref.current && !ref.current.contains(e.target)) setOpen(false); }; document.addEventListener('mousedown',h); return ()=>document.removeEventListener('mousedown',h); },[open]); return (
{open && (
{user.initials}
{user.name}
{user.email}
)}
); } // ---------- Estado de compresión de video (polling async post-upload) ---------- function CompressionStatusLine({ status, info }){ if (status==='procesando') return ( Comprimiendo video para WhatsApp (hasta 16 MB)… ); if (status==='listo') return ( Comprimido{info && info.tamano_final_bytes ? ` · ${(info.tamano_final_bytes/1024/1024).toFixed(1)} MB` : ''} ); if (status==='error') return ( No se pudo comprimir{info && info.motivo ? `: ${info.motivo}` : ''} ); return null; } Object.assign(window, { Icon, FRAG_ICON, FRAG_LABEL, Btn, IconBtn, StatusPill, ViewToggle, Modal, Field, Toast, ConfirmDelete, HelpTip, SessionMenu, CompressionStatusLine, useState, useRef, useEffect, });