From 727527e30dab8d5b1797d48e9fcc89e0c818d39c Mon Sep 17 00:00:00 2001 From: Marco Gallegos Date: Wed, 13 Aug 2025 07:21:41 -0600 Subject: [PATCH] fix: Corregir bloqueo del navegador en el dashboard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Se soluciona un error crítico que causaba el bloqueo del navegador al visitar la pestaña del dashboard. El problema era causado por la inicialización de la librería Chart.js en un elemento del DOM que no estaba visible, lo que provocaba un bucle de renderizado infinito. La solución implementada consiste en: - Inicializar el gráfico solo la primera vez que la pestaña del dashboard se hace visible. - En visitas posteriores a la pestaña, solo se actualizan los datos del gráfico ya existente. --- ap-pos/app.js | 63 +++++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/ap-pos/app.js b/ap-pos/app.js index 52006a9..064ff82 100644 --- a/ap-pos/app.js +++ b/ap-pos/app.js @@ -35,33 +35,40 @@ const formCredentials = document.getElementById('formCredentials'); const formAddUser = document.getElementById('formAddUser'); const tblUsersBody = document.getElementById('tblUsers')?.querySelector('tbody'); +let isDashboardLoading = false; + // --- LÓGICA DE NEGOCIO --- async function loadDashboardData() { - // Solo admins pueden cargar esto - if (currentUser.role !== 'admin' || !incomeChart) return; + // Guardia para prevenir ejecuciones múltiples + if (currentUser.role !== 'admin' || !incomeChart || isDashboardLoading) return; + + isDashboardLoading = true; + try { const response = await fetch('/api/dashboard'); if (!response.ok) { if (response.status === 403) { - console.warn('Access to dashboard denied.'); + console.warn('Acceso al dashboard denegado.'); return; } - throw new Error('Failed to fetch dashboard data'); + throw new Error('Falló la carga de datos del dashboard'); } const data = await response.json(); - // Update stat cards + // Actualizar tarjetas de estadísticas document.getElementById('stat-total-income').textContent = `${Number(data.totalIncome || 0).toFixed(2)}`; document.getElementById('stat-total-movements').textContent = data.totalMovements || 0; - // Update chart data instead of recreating it + // Actualizar datos del gráfico incomeChart.data.labels = data.incomeByService.map(item => item.tipo); incomeChart.data.datasets[0].data = data.incomeByService.map(item => item.total); incomeChart.update(); } catch (error) { - console.error('Error loading dashboard:', error); + console.error('Error al cargar el dashboard:', error); + } finally { + isDashboardLoading = false; } } @@ -437,6 +444,27 @@ function activateTab(tabId) { // Cargar datos dinámicos si es la pestaña del dashboard if (tabId === 'tab-dashboard' && currentUser.role === 'admin') { + // Si es la primera vez que se visita la pestaña, inicializar el gráfico + if (!incomeChart) { + const ctx = document.getElementById('incomeChart').getContext('2d'); + incomeChart = new Chart(ctx, { + type: 'pie', + data: { + labels: [], + datasets: [{ + label: 'Ingresos por Servicio', + data: [], + backgroundColor: ['#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF', '#FF9F40'], + }] + }, + options: { + responsive: true, + maintainAspectRatio: false, + animation: false + } + }); + } + // Cargar (o recargar) los datos del dashboard loadDashboardData(); } } @@ -538,25 +566,6 @@ async function initializeApp() { if (currentUser.role === 'admin') { formAddUser?.addEventListener('submit', handleAddUser); tblUsersBody?.addEventListener('click', handleTableClick); - - // Inicializar el gráfico vacío para el admin - const ctx = document.getElementById('incomeChart').getContext('2d'); - incomeChart = new Chart(ctx, { - type: 'pie', - data: { - labels: [], - datasets: [{ - label: 'Ingresos por Servicio', - data: [], - backgroundColor: ['#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF', '#FF9F40'], - }] - }, - options: { - responsive: true, - maintainAspectRatio: false, - animation: false - } - }); } btnLogout?.addEventListener('click', async () => { @@ -602,4 +611,4 @@ async function initializeApp() { } -document.addEventListener('DOMContentLoaded', initializeApp); \ No newline at end of file +document.addEventListener('DOMContentLoaded', initializeApp);