const ICONOS = [ 'restaurant','home','directions_car','bolt','movie','shopping_bag', 'local_grocery_store','medical_services','school','flight','sports_esports', 'coffee','fitness_center','pets','phone_android','work','savings','credit_card', 'local_gas_station','music_note','sports_soccer','family_restroom', 'local_pharmacy','computer','child_care','celebration','beach_access', 'attach_money','bar_chart','payments' ]; const COLORES = [ '#005050','#4d6357','#264b5c','#3e4948','#006a6a','#2d6a4f', '#c0392b','#e67e22','#8b6914','#2980b9','#6c3483','#555555' ]; let editandoId = null; let iconoSelecto = ICONOS[0]; let colorSelecto = COLORES[0]; // ─── Inicialización ─────────────────────────────────────────────── document.addEventListener('DOMContentLoaded', () => { renderIconGrid(); renderColorGrid(); document.getElementById('drawer-nombre').addEventListener('input', actualizarPreview); document.getElementById('drawer-save').addEventListener('click', guardar); cargarCategorias(); }); // ─── Cargar y renderizar lista ──────────────────────────────────── async function cargarCategorias() { const r = await apiFetch('api/categorias.php'); if (!r) return; const data = await r.json(); document.getElementById('ui-loading').classList.add('hidden'); const lista = document.getElementById('ui-lista'); if (!data.categorias.length) { lista.classList.remove('hidden'); lista.innerHTML = `
category

Sin categorías

`; return; } lista.classList.remove('hidden'); lista.innerHTML = data.categorias.map(c => { const tieneMovs = parseInt(c.total_movimientos) > 0; return `
${c.icono}

${c.nombre}

${c.total_movimientos} movimiento${c.total_movimientos != 1 ? 's' : ''}

`; }).join(''); } // ─── Drawer ─────────────────────────────────────────────────────── function abrirDrawer(cat) { editandoId = cat ? cat.id : null; iconoSelecto = cat ? cat.icono : ICONOS[0]; colorSelecto = cat ? cat.color_hex : COLORES[0]; document.getElementById('drawer-title').textContent = cat ? 'Editar categoría' : 'Nueva categoría'; document.getElementById('drawer-nombre').value = cat ? cat.nombre : ''; actualizarSeleccionIcono(); actualizarSeleccionColor(); actualizarPreview(); document.getElementById('drawer-overlay').classList.remove('hidden'); const drawer = document.getElementById('drawer'); drawer.classList.remove('translate-y-full','md:translate-x-full'); setTimeout(() => document.getElementById('drawer-nombre').focus(), 300); } function cerrarDrawer() { document.getElementById('drawer-overlay').classList.add('hidden'); const drawer = document.getElementById('drawer'); drawer.classList.add('translate-y-full','md:translate-x-full'); } // ─── Íconos ─────────────────────────────────────────────────────── function renderIconGrid() { document.getElementById('icon-grid').innerHTML = ICONOS.map(ic => ` `).join(''); } function seleccionarIcono(ic) { iconoSelecto = ic; actualizarSeleccionIcono(); actualizarPreview(); } function actualizarSeleccionIcono() { document.querySelectorAll('#icon-grid button').forEach(b => { const ic = b.id.replace('ico-', ''); b.classList.toggle('bg-primary/10', ic === iconoSelecto); b.classList.toggle('border-primary', ic === iconoSelecto); b.querySelector('span').style.color = ic === iconoSelecto ? '#005050' : ''; }); } // ─── Colores ────────────────────────────────────────────────────── function renderColorGrid() { document.getElementById('color-grid').innerHTML = COLORES.map(col => ` `).join(''); } function seleccionarColor(col) { colorSelecto = col; actualizarSeleccionColor(); actualizarPreview(); } function actualizarSeleccionColor() { document.querySelectorAll('#color-grid button').forEach(b => { const col = '#' + b.id.replace('col-', ''); b.style.outline = col === colorSelecto ? `3px solid ${col}` : 'none'; b.style.outlineOffset = '2px'; }); } // ─── Preview ────────────────────────────────────────────────────── function actualizarPreview() { const nombre = document.getElementById('drawer-nombre').value.trim() || 'Vista previa'; document.getElementById('preview-nombre').textContent = nombre; document.getElementById('preview-icono').style.background = colorSelecto; document.getElementById('preview-icono-sym').textContent = iconoSelecto; } // ─── Guardar ────────────────────────────────────────────────────── async function guardar() { const nombre = document.getElementById('drawer-nombre').value.trim(); if (!nombre) { rmModal.alert('El nombre de la categoría no puede estar vacío.', 'Campo requerido'); return; } const btn = document.getElementById('drawer-save'); btn.disabled = true; btn.textContent = 'Guardando…'; const payload = { nombre, icono: iconoSelecto, color_hex: colorSelecto }; const method = editandoId ? 'PUT' : 'POST'; if (editandoId) payload.id = editandoId; try { const r = await apiFetch('api/categorias.php', { method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (!r) return; const data = await r.json(); if (data.status === 'success') { cerrarDrawer(); rmModal.toast(editandoId ? 'Categoría actualizada' : 'Categoría creada'); await cargarCategorias(); } else { await rmModal.alert(data.message, 'Error'); } } catch { await rmModal.alert('Error de conexión', 'Error'); } finally { btn.disabled = false; btn.textContent = 'Guardar'; } } // ─── Eliminar ───────────────────────────────────────────────────── async function eliminar(id, nombre) { const ok = await rmModal.confirm(`¿Eliminar la categoría "${nombre}"?`, 'Eliminar categoría'); if (!ok) return; const r = await apiFetch('api/categorias.php', { method: 'DELETE', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id }) }); if (!r) return; const data = await r.json(); if (data.status === 'success') { rmModal.toast('Categoría eliminada'); await cargarCategorias(); } else { rmModal.toast(data.message, 'error'); } }