Files
CATALOGO_INFINITY/frontend/administrativo/index.html
T
2026-06-05 22:06:52 -05:00

470 lines
20 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Infinity — Panel Admin</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=DM+Serif+Display:ital@0;1&family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="admin.css?v=4">
</head>
<body>
<!-- FONDO MESH -->
<div class="mesh-bg" aria-hidden="true">
<div class="mesh-blob mesh-blob-1"></div>
<div class="mesh-blob mesh-blob-2"></div>
<div class="mesh-blob mesh-blob-3"></div>
</div>
<!-- LOGIN VIEW -->
<main class="login-view" id="loginView">
<div class="login-card">
<div class="login-header">
<a href="../" class="logo">
<span class="logo-symbol"></span>
<span class="logo-text">Infinity</span>
</a>
<span class="login-badge">Panel administrativo</span>
</div>
<h1 class="login-title">Bienvenido <em>de nuevo</em></h1>
<p class="login-subtitle">Ingresa tus credenciales para continuar</p>
<form class="login-form" id="loginForm" autocomplete="on">
<div class="form-group">
<label for="usuario">Usuario</label>
<input type="text" id="usuario" name="usuario" placeholder="admin" required autocomplete="username">
</div>
<div class="form-group">
<label for="contraseña">Contraseña</label>
<input type="password" id="contraseña" name="contraseña" placeholder="••••••••" required autocomplete="current-password">
</div>
<div class="form-error" id="formError" role="alert"></div>
<button type="submit" class="btn btn-primary btn-full">Ingresar</button>
</form>
<a href="../" class="back-link">← Volver al catálogo</a>
</div>
</main>
<!-- ADMIN APP (post-login) -->
<div class="admin-app" id="adminApp" style="display:none">
<!-- SALUDO SUPERIOR -->
<header class="admin-greeting">
<h1 class="greeting-title">Hola, <em id="adminName">Admin</em> 👋</h1>
<p class="greeting-subtitle">Bienvenido al panel de Infinity.</p>
</header>
<!-- TOPBAR PILL (sticky) -->
<nav class="admin-topbar" aria-label="Navegación del panel">
<div class="topbar-container">
<button type="button" class="nav-item active" data-view="dashboard">
<span class="nav-icon">🏠</span>
<span class="nav-label">Dashboard</span>
</button>
<button type="button" class="nav-item" data-view="productos">
<span class="nav-icon">📦</span>
<span class="nav-label">Productos</span>
</button>
<button type="button" class="nav-item" data-view="agotados">
<span class="nav-icon">🚫</span>
<span class="nav-label">Agotados</span>
</button>
<button type="button" class="nav-item" data-view="categorias">
<span class="nav-icon">🗂️</span>
<span class="nav-label">Categorías</span>
</button>
<button type="button" class="nav-item" data-view="usuarios">
<span class="nav-icon">👥</span>
<span class="nav-label">Usuarios</span>
</button>
<span class="topbar-divider" aria-hidden="true"></span>
<button type="button" class="nav-item nav-item-logout" id="btnLogout">
<span class="nav-icon"></span>
<span class="nav-label">Cerrar sesión</span>
</button>
</div>
</nav>
<!-- CONTENIDO PRINCIPAL -->
<main class="admin-main">
<!-- DASHBOARD VIEW -->
<section class="view active" data-view="dashboard">
<div class="stats-grid">
<div class="stat-card">
<div class="stat-icon">📦</div>
<div class="stat-info">
<div class="stat-value" id="statProductos"></div>
<div class="stat-label">Productos</div>
</div>
</div>
<div class="stat-card">
<div class="stat-icon">🗂️</div>
<div class="stat-info">
<div class="stat-value" id="statCategorias"></div>
<div class="stat-label">Categorías</div>
</div>
</div>
</div>
</section>
<!-- PRODUCTOS VIEW -->
<section class="view" data-view="productos">
<header class="view-header">
<h1 class="view-title">Productos</h1>
<p class="view-subtitle">Sube fotos masivamente. La descripción y el precio se asignarán después.</p>
</header>
<div class="view-content-card">
<form id="formUploadProductos" class="upload-form" autocomplete="off">
<div class="form-group">
<label for="uploadCategoria">Categoría destino</label>
<select id="uploadCategoria" required>
<option value="">— Selecciona una categoría —</option>
</select>
<span class="form-hint">Todas las fotos subidas se guardarán en esta carpeta.</span>
</div>
<div class="form-group">
<label>Zona de subida</label>
<div class="dropzone" id="dropzone">
<input type="file" id="inputFotos" accept="image/*" multiple hidden>
<div class="dropzone-inner">
<div class="dropzone-icon">📤</div>
<p class="dropzone-title">Arrastra fotos aquí o haz clic para seleccionar</p>
<p class="dropzone-hint">JPG, PNG, WEBP, GIF · Máx 20MB por archivo · 50 archivos por subida</p>
</div>
</div>
</div>
<div class="upload-preview-section" id="previewSection" style="display:none">
<div class="upload-preview-header">
<span class="upload-counter">
<strong id="previewCount">0</strong>/50 fotos
</span>
<button type="button" class="btn btn-ghost btn-sm" id="btnLimpiarPreview">Limpiar todo</button>
</div>
<div class="upload-preview-grid" id="previewGrid"></div>
</div>
<div class="upload-summary" id="uploadSummary" style="display:none"></div>
<div class="form-error" id="uploadError" role="alert"></div>
<div class="form-actions">
<button type="submit" class="btn btn-primary" id="btnSubirProductos" disabled>
<span class="btn-text">Subir fotos</span>
<span class="btn-spinner" style="display:none"></span>
</button>
</div>
</form>
</div>
<!-- Sub-sección: Lista de productos disponibles -->
<div class="view-subsection">
<div class="subsection-header">
<h2 class="subsection-title">📋 Productos disponibles</h2>
<span class="productos-counter" id="productosDisponiblesCount">0</span>
</div>
<div class="view-content-card">
<div class="productos-search">
<span class="productos-search-icon" aria-hidden="true">🔍</span>
<input type="text" id="productosSearch" placeholder="Buscar por referencia..." autocomplete="off" spellcheck="false">
<button type="button" class="productos-search-clear" id="productosSearchClear" style="display:none" aria-label="Limpiar búsqueda"></button>
</div>
<div class="productos-grid" id="productosListGrid">
<!-- Renderizado por JS -->
</div>
</div>
</div>
</section>
<!-- AGOTADOS VIEW -->
<section class="view" data-view="agotados">
<header class="view-header">
<h1 class="view-title">Agotados</h1>
<p class="view-subtitle">Productos que ya no están disponibles. Puedes reactivarlos o eliminarlos definitivamente.</p>
</header>
<div class="view-content-card">
<div class="agotados-grid" id="agotadosGrid">
<!-- Renderizado por JS -->
</div>
</div>
</section>
<!-- CATEGORÍAS VIEW -->
<section class="view" data-view="categorias">
<header class="view-header view-header-with-action">
<div>
<h1 class="view-title">Categorías</h1>
<p class="view-subtitle">Crea, edita o elimina las categorías del catálogo.</p>
</div>
<button type="button" class="btn btn-primary" id="btnCrearCategoria">
<span></span> Crear categoría
</button>
</header>
<div class="view-content-card">
<div class="categorias-grid" id="categoriasGrid">
<!-- Renderizado por JS -->
</div>
</div>
</section>
<!-- USUARIOS VIEW (visible si tiene permiso 'usuarios') -->
<section class="view" data-view="usuarios">
<header class="view-header">
<h1 class="view-title">Usuarios</h1>
<p class="view-subtitle">Gestiona los usuarios del panel.</p>
</header>
<!-- Sub-sección: Mi contraseña (solo admin) -->
<div class="view-subsection" id="miPasswordSubsection">
<h2 class="subsection-title">🔑 Mi contraseña</h2>
<div class="view-content-card">
<form id="formMiPassword" class="password-form" autocomplete="on">
<div class="form-group">
<label for="miPassActual">Contraseña actual</label>
<input type="password" id="miPassActual" required autocomplete="current-password">
</div>
<div class="form-group">
<label for="miPassNueva">Nueva contraseña</label>
<input type="password" id="miPassNueva" required minlength="6" autocomplete="new-password">
<span class="form-hint">Mínimo 6 caracteres</span>
</div>
<div class="form-group">
<label for="miPassConfirmar">Confirmar nueva contraseña</label>
<input type="password" id="miPassConfirmar" required minlength="6" autocomplete="new-password">
</div>
<div class="form-error" id="miPassError" role="alert"></div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">Guardar cambios</button>
</div>
</form>
</div>
</div>
<!-- Sub-sección: Gestión de usuarios (admin o permiso 'usuarios') -->
<div class="view-subsection" id="gestionUsuariosSubsection">
<div class="subsection-header">
<h2 class="subsection-title">👥 Gestión de usuarios</h2>
<button type="button" class="btn btn-primary" id="btnCrearUsuario">
<span></span> Crear usuario
</button>
</div>
<div class="view-content-card">
<div class="users-table-wrap">
<table class="users-table">
<thead>
<tr>
<th>Usuario</th>
<th>Rol</th>
<th class="users-actions-col">Acciones</th>
</tr>
</thead>
<tbody id="usersListBody">
<!-- Renderizado por JS -->
</tbody>
</table>
</div>
</div>
</div>
</section>
</main>
</div>
<!-- MODAL: Crear usuario -->
<div class="modal" id="modalCrearUsuario" style="display:none">
<div class="modal-backdrop" data-close-modal="modalCrearUsuario"></div>
<div class="modal-content">
<div class="modal-header">
<h3>Crear usuario</h3>
<button class="modal-close" data-close-modal="modalCrearUsuario" type="button" aria-label="Cerrar"></button>
</div>
<form id="formCrearUsuario" class="modal-form">
<div class="form-group">
<label for="nuevoUsuario">Usuario</label>
<input type="text" id="nuevoUsuario" required autocomplete="off">
</div>
<div class="form-group">
<label for="nuevoPassword">Contraseña</label>
<input type="password" id="nuevoPassword" required minlength="6" autocomplete="new-password">
<span class="form-hint">Mínimo 6 caracteres</span>
</div>
<div class="form-group">
<label for="nuevoRol">Rol</label>
<select id="nuevoRol" required>
<option value="editor">Editor</option>
<option value="admin">Administrador</option>
</select>
</div>
<div class="form-group" id="permisosGroupCrear">
<label>Permisos de visibilidad</label>
<div class="permissions-grid" id="permisosCrear"></div>
<span class="form-hint">Marca las pestañas que este usuario podrá ver.</span>
</div>
<div class="permission-note" id="permisosNoteCrear" style="display:none">
<span>👑</span>
<span>Los administradores tienen todos los permisos automáticamente.</span>
</div>
<div class="form-error" id="crearUsuarioError" role="alert"></div>
<div class="modal-actions">
<button type="button" class="btn btn-ghost" data-close-modal="modalCrearUsuario">Cancelar</button>
<button type="submit" class="btn btn-primary">Crear</button>
</div>
</form>
</div>
</div>
<!-- MODAL: Editar usuario -->
<div class="modal" id="modalEditarUsuario" style="display:none">
<div class="modal-backdrop" data-close-modal="modalEditarUsuario"></div>
<div class="modal-content">
<div class="modal-header">
<h3>Editar usuario</h3>
<button class="modal-close" data-close-modal="modalEditarUsuario" type="button" aria-label="Cerrar"></button>
</div>
<form id="formEditarUsuario" class="modal-form">
<div class="form-group">
<label>Usuario</label>
<input type="text" id="editarUsuarioNombre" disabled>
</div>
<div class="form-group">
<label for="editarPassword">Nueva contraseña</label>
<input type="password" id="editarPassword" minlength="6" autocomplete="new-password">
<span class="form-hint">Déjala vacía para no cambiar</span>
</div>
<div class="form-group">
<label for="editarRol">Rol</label>
<select id="editarRol" required>
<option value="editor">Editor</option>
<option value="admin">Administrador</option>
</select>
</div>
<div class="form-group" id="permisosGroupEditar">
<label>Permisos de visibilidad</label>
<div class="permissions-grid" id="permisosEditar"></div>
<span class="form-hint">Marca las pestañas que este usuario podrá ver.</span>
</div>
<div class="permission-note" id="permisosNoteEditar" style="display:none">
<span>👑</span>
<span>Los administradores tienen todos los permisos automáticamente.</span>
</div>
<div class="form-error" id="editarUsuarioError" role="alert"></div>
<div class="modal-actions">
<button type="button" class="btn btn-ghost" data-close-modal="modalEditarUsuario">Cancelar</button>
<button type="submit" class="btn btn-primary">Guardar cambios</button>
</div>
</form>
</div>
</div>
<!-- MODAL: Confirmar eliminar -->
<div class="modal modal-sm" id="modalConfirmarEliminar" style="display:none">
<div class="modal-backdrop" data-close-modal="modalConfirmarEliminar"></div>
<div class="modal-content">
<div class="modal-header">
<h3>¿Eliminar usuario?</h3>
<button class="modal-close" data-close-modal="modalConfirmarEliminar" type="button" aria-label="Cerrar"></button>
</div>
<div class="modal-body">
<p>¿Estás seguro de que quieres eliminar al usuario <strong id="eliminarUsuarioNombre"></strong>?</p>
<p class="modal-warning">Esta acción no se puede deshacer.</p>
<div class="form-error" id="eliminarUsuarioError" role="alert"></div>
</div>
<div class="modal-actions">
<button type="button" class="btn btn-ghost" data-close-modal="modalConfirmarEliminar">Cancelar</button>
<button type="button" class="btn btn-danger" id="btnConfirmarEliminar">Sí, eliminar</button>
</div>
</div>
</div>
<!-- MODAL: Crear/Editar categoría -->
<div class="modal" id="modalCategoria" style="display:none">
<div class="modal-backdrop" data-close-modal="modalCategoria"></div>
<div class="modal-content">
<div class="modal-header">
<h3 id="modalCategoriaTitulo">Crear categoría</h3>
<button class="modal-close" data-close-modal="modalCategoria" type="button" aria-label="Cerrar"></button>
</div>
<form id="formCategoria" class="modal-form">
<div class="form-group">
<label for="catNombre">Nombre</label>
<input type="text" id="catNombre" required maxlength="40" autocomplete="off">
<span class="form-hint" id="catIdHint"></span>
</div>
<div class="form-group">
<label>Icono</label>
<div class="icon-picker" id="iconPicker"></div>
<input type="hidden" id="catIcono" value="📦">
</div>
<div class="form-error" id="categoriaError" role="alert"></div>
<div class="modal-actions">
<button type="button" class="btn btn-ghost" data-close-modal="modalCategoria">Cancelar</button>
<button type="submit" class="btn btn-primary" id="btnGuardarCategoria">Crear</button>
</div>
</form>
</div>
</div>
<!-- MODAL: Confirmar eliminar categoría -->
<div class="modal modal-sm" id="modalEliminarCategoria" style="display:none">
<div class="modal-backdrop" data-close-modal="modalEliminarCategoria"></div>
<div class="modal-content">
<div class="modal-header">
<h3>¿Eliminar categoría?</h3>
<button class="modal-close" data-close-modal="modalEliminarCategoria" type="button" aria-label="Cerrar"></button>
</div>
<div class="modal-body">
<p>Vas a eliminar la categoría <strong id="eliminarCatNombre"></strong>.</p>
<div id="eliminarCatItemsMsg" class="alert-warning" style="display:none">
<span>⚠️</span>
<div>
<strong>Esta categoría tiene <span id="eliminarCatCount">0</span> item(s).</strong>
<p>Si continúas, los items se moverán a <strong>"Sin categoría"</strong> (no se borrarán).</p>
</div>
</div>
<p class="modal-warning">Esta acción no se puede deshacer.</p>
<div class="form-error" id="eliminarCatError" role="alert"></div>
</div>
<div class="modal-actions">
<button type="button" class="btn btn-ghost" data-close-modal="modalEliminarCategoria">Cancelar</button>
<button type="button" class="btn btn-danger" id="btnConfirmarEliminarCategoria">Sí, eliminar</button>
</div>
</div>
</div>
<!-- MODAL: Confirmar eliminar producto definitivamente -->
<div class="modal modal-sm" id="modalEliminarProductoDef" style="display:none">
<div class="modal-backdrop" data-close-modal="modalEliminarProductoDef"></div>
<div class="modal-content">
<div class="modal-header">
<h3>¿Eliminar producto definitivamente?</h3>
<button class="modal-close" data-close-modal="modalEliminarProductoDef" type="button" aria-label="Cerrar"></button>
</div>
<div class="modal-body">
<p>Vas a eliminar el producto <strong id="eliminarProdRef"></strong> de forma permanente.</p>
<p>Su imagen y todos sus datos se borrarán. <strong>No se puede deshacer.</strong></p>
<div class="form-error" id="eliminarProdError" role="alert"></div>
</div>
<div class="modal-actions">
<button type="button" class="btn btn-ghost" data-close-modal="modalEliminarProductoDef">Cancelar</button>
<button type="button" class="btn btn-danger" id="btnConfirmarEliminarProdDef">Sí, eliminar</button>
</div>
</div>
</div>
<script src="admin.js?v=4"></script>
</body>
</html>