/* ════════════════════════════════ INFINITY — ADMIN.JS Sistema escalable de permisos por pestañas ════════════════════════════════ */ // ════════════════════════════════ // TABS — fuente de verdad de permisos // Para agregar una pestaña nueva: agrégala aquí y al HTML con data-view // ════════════════════════════════ const TABS = [ { id: 'productos', label: 'Productos', icon: '📦' }, { id: 'agotados', label: 'Agotados', icon: '🚫' }, { id: 'categorias', label: 'Categorías', icon: '🗂️' }, { id: 'usuarios', label: 'Usuarios', icon: '👥' } ]; const ROLES = { admin: 'Administrador', editor: 'Editor' }; // Iconos disponibles para categorías const CAT_ICONS = [ '💄','👜','☕','🏠','👓','🧴','🕯️','🖼️', '💍','🧣','👒','🪞','🎁','🪴','🍵','📿', '🧸','🛍️','👗','📦','🎀','🕊️','✨','🌸' ]; let currentUser = null; // { usuario, rol, permisos: [] } let editingUser = null; // nombre del usuario que se está editando let deletingUser = null; // nombre del usuario a eliminar let editingCategoria = null; // id de la categoría que se está editando let deletingCategoria = null; // id de la categoría que se va a eliminar let currentView = 'dashboard'; let cachedProductos = []; // cache de productos para contar items por categoría // ════════════════════════════════ // INIT // ════════════════════════════════ document.addEventListener('DOMContentLoaded', async () => { setupLoginForm(); setupLogout(); setupNavigation(); setupModals(); setupPermisosToggles(); setupCategoriasModals(); setupProductosUpload(); setupProductosSearch(); setupExcelUpload(); await checkSession(); }); // ════════════════════════════════ // SESIÓN // ════════════════════════════════ async function checkSession() { try { const res = await fetch('/api/auth/me', { credentials: 'include' }); if (res.ok) { const user = await res.json(); currentUser = user; mostrarDashboard(user); } else { mostrarLogin(); } } catch (err) { console.error('Error verificando sesión:', err); mostrarLogin(); } } // ════════════════════════════════ // VISTAS // ════════════════════════════════ function mostrarLogin() { currentUser = null; document.body.classList.remove('is-admin'); document.getElementById('loginView').style.display = 'flex'; document.getElementById('adminApp').style.display = 'none'; } function mostrarDashboard(user) { currentUser = user; document.getElementById('loginView').style.display = 'none'; document.getElementById('adminApp').style.display = 'block'; // Marcar el body según el rol document.body.classList.toggle('is-admin', user.rol === 'admin'); // Saludo con el nombre del usuario document.getElementById('adminName').textContent = user.usuario; // Aplicar permisos (visibilidad de nav, subsección admin-only, etc.) aplicarPermisos(); // Reset a la vista dashboard cambiarVista('dashboard'); cargarEstadisticas(); } function cambiarVista(view) { // Check defensivo: si el usuario no tiene permiso para esta vista, redirige a dashboard if (currentUser && view !== 'dashboard') { const esAdmin = currentUser.rol === 'admin'; const permisos = currentUser.permisos || []; if (!esAdmin && !permisos.includes(view)) { view = 'dashboard'; } } currentView = view; // Ocultar todas las vistas document.querySelectorAll('.view').forEach(v => v.classList.remove('active')); // Mostrar la vista solicitada (si existe) const target = document.querySelector(`.view[data-view="${view}"]`); if (target) { target.classList.add('active'); } else { document.querySelector('.view[data-view="dashboard"]').classList.add('active'); view = 'dashboard'; } // Actualizar nav items (excluir el de logout que no tiene data-view) document.querySelectorAll('.nav-item[data-view]').forEach(item => { item.classList.toggle('active', item.dataset.view === view); }); // Cargar datos específicos de la vista if (view === 'usuarios') { const esAdmin = currentUser.rol === 'admin'; const puedeGestionar = esAdmin || (currentUser.permisos || []).includes('usuarios'); if (puedeGestionar) { cargarUsuarios(); } } if (view === 'categorias') { cargarCategorias(); } if (view === 'productos') { cargarCategoriasEnUpload(); cargarProductosDisponibles(); } if (view === 'agotados') { cargarAgotados(); } } async function cargarEstadisticas() { try { const [resCats, resProds] = await Promise.all([ fetch('/api/categorias'), fetch('/api/productos') ]); const categorias = await resCats.json(); const productos = await resProds.json(); cachedProductos = productos; document.getElementById('statProductos').textContent = productos.length; document.getElementById('statCategorias').textContent = categorias.length; } catch (err) { console.error('Error cargando estadísticas:', err); } } // ════════════════════════════════ // PERMISOS — visibilidad según rol + permisos[] // ════════════════════════════════ function aplicarPermisos() { if (!currentUser) return; const esAdmin = currentUser.rol === 'admin'; const permisos = currentUser.permisos || []; const puedeGestionarUsuarios = esAdmin || permisos.includes('usuarios'); // Mostrar/ocultar cada nav-item según permisos document.querySelectorAll('.nav-item[data-view]').forEach(item => { const view = item.dataset.view; let visible = false; if (view === 'dashboard') { visible = true; // Dashboard siempre visible } else if (esAdmin) { visible = true; // Admin ve todo } else { visible = permisos.includes(view); // Editor: solo sus permisos } item.style.display = visible ? '' : 'none'; }); // Subsección "Mi contraseña" — SOLO admin const miPassSubsection = document.getElementById('miPasswordSubsection'); if (miPassSubsection) { miPassSubsection.style.display = esAdmin ? '' : 'none'; } // Subsección "Gestión de usuarios" — admin O permiso 'usuarios' const gestionSubsection = document.getElementById('gestionUsuariosSubsection'); if (gestionSubsection) { gestionSubsection.style.display = puedeGestionarUsuarios ? '' : 'none'; } } // ════════════════════════════════ // NAVEGACIÓN // ════════════════════════════════ function setupNavigation() { document.querySelectorAll('.nav-item[data-view]').forEach(item => { item.addEventListener('click', () => { cambiarVista(item.dataset.view); }); }); } // ════════════════════════════════ // PERMISOS EN MODALES — render y lectura // ════════════════════════════════ function renderPermisos(containerId, checkedPerms = []) { const container = document.getElementById(containerId); if (!container) return; container.innerHTML = TABS.map(t => ` `).join(''); } function collectPermisos(containerId) { const container = document.getElementById(containerId); if (!container) return []; return Array.from(container.querySelectorAll('input[type="checkbox"]:checked')) .map(cb => cb.value); } // Mostrar/ocultar la sección de permisos según el rol elegido en el