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);