import { db } from '../../js/firebase-config.js'; import { auth } from './admin-auth.js'; // Elementos del DOM const rangeItems = document.querySelectorAll('.range-item'); const currentRange = document.getElementById('currentRange'); // Variables let charts = {}; let currentRangeValue = 7; // Inicializar function initStatsManager() { loadStats(); setupEventListeners(); } // Cargar estadísticas function loadStats() { const endDate = new Date(); const startDate = new Date(); startDate.setDate(startDate.getDate() - currentRangeValue); // Cargar datos de usuarios loadUserRegistrations(startDate, endDate); // Cargar datos financieros loadFinancialData(startDate, endDate); // Cargar datos de anuncios loadAdActivity(startDate, endDate); } // Cargar registros de usuarios function loadUserRegistrations(startDate, endDate) { db.collection("users") .where("createdAt", ">=", startDate) .where("createdAt", "<=", endDate) .get() .then((snapshot) => { const userData = groupDataByDay(snapshot.docs, "createdAt", startDate, endDate); renderUserRegistrationsChart(userData); }); } // Cargar datos financieros function loadFinancialData(startDate, endDate) { Promise.all([ db.collection("adViews") .where("viewedAt", ">=", startDate) .where("viewedAt", "<=", endDate) .get(), db.collection("withdrawals") .where("requestedAt", ">=", startDate) .where("requestedAt", "<=", endDate) .get() ]).then(([adViewsSnapshot, withdrawalsSnapshot]) => { const earningsData = groupDataByDay(adViewsSnapshot.docs, "viewedAt", startDate, endDate, "reward"); const withdrawalsData = groupDataByDay(withdrawalsSnapshot.docs, "requestedAt", startDate, endDate, "amount"); renderFinancialChart(earningsData, withdrawalsData); }); } // Cargar actividad de anuncios function loadAdActivity(startDate, endDate) { db.collection("adViews") .where("viewedAt", ">=", startDate) .where("viewedAt", "<=", endDate) .get() .then((snapshot) => { const adData = groupAdData(snapshot.docs); renderAdActivityChart(adData); }); } // Agrupar datos por día function groupDataByDay(docs, dateField, startDate, endDate, sumField = null) { const data = {}; const currentDate = new Date(startDate); // Inicializar todos los días en el rango while (currentDate <= endDate) { const dateKey = currentDate.toISOString().split('T')[0]; data[dateKey] = sumField ? 0 : []; currentDate.setDate(currentDate.getDate() + 1); } // Procesar documentos docs.forEach(doc => { const docData = doc.data(); const date = docData[dateField].toDate(); const dateKey = date.toISOString().split('T')[0]; if (sumField) { data[dateKey] += docData[sumField] || 0; } else { if (!data[dateKey]) data[dateKey] = []; data[dateKey].push(docData); } }); return data; } // Agrupar datos de anuncios function groupAdData(docs) { const adData = {}; const userSet = new Set(); docs.forEach(doc => { const docData = doc.data(); const adId = docData.adId; if (!adData[adId]) { adData[adId] = { views: 0, earnings: 0, users: new Set() }; } adData[adId].views++; adData[adId].earnings += docData.reward || 0; adData[adId].users.add(docData.userId); userSet.add(docData.userId); }); // Convertir Sets a counts const result = {}; Object.keys(adData).forEach(adId => { result[adId] = { views: adData[adId].views, earnings: adData[adId].earnings, uniqueUsers: adData[adId].users.size }; }); return { adData: result, totalUsers: userSet.size, totalViews: docs.length, totalEarnings: Object.values(result).reduce((sum, ad) => sum + ad.earnings, 0) }; } // Renderizar gráfico de registros de usuarios function renderUserRegistrationsChart(userData) { const ctx = document.getElementById('userRegistrationsChart').getContext('2d'); const labels = Object.keys(userData).sort(); const data = labels.map(date => userData[date].length); if (charts.userRegistrations) { charts.userRegistrations.destroy(); } charts.userRegistrations = new Chart(ctx, { type: 'line', data: { labels: labels, datasets: [{ label: 'Registros diarios', data: data, backgroundColor: 'rgba(75, 192, 192, 0.2)', borderColor: 'rgba(75, 192, 192, 1)', borderWidth: 2, tension: 0.3 }] }, options: { responsive: true, plugins: { legend: { position: 'top', }, tooltip: { callbacks: { label: function(context) { return `${context.dataset.label}: ${context.raw}`; } } } }, scales: { y: { beginAtZero: true, ticks: { precision: 0 } } } } }); } // Renderizar gráfico financiero function renderFinancialChart(earningsData, withdrawalsData) { const ctx = document.getElementById('earningsWithdrawalsChart').getContext('2d'); const labels = Object.keys(earningsData).sort(); const earnings = labels.map(date => earningsData[date] || 0); const withdrawals = labels.map(date => withdrawalsData[date] || 0); if (charts.financial) { charts.financial.destroy(); } charts.financial = new Chart(ctx, { type: 'bar', data: { labels: labels, datasets: [ { label: 'Ingresos ($)', data: earnings, backgroundColor: 'rgba(54, 162, 235, 0.7)', borderColor: 'rgba(54, 162, 235, 1)', borderWidth: 1 }, { label: 'Retiros ($)', data: withdrawals, backgroundColor: 'rgba(255, 99, 132, 0.7)', borderColor: 'rgba(255, 99, 132, 1)', borderWidth: 1 } ] }, options: { responsive: true, plugins: { legend: { position: 'top', }, tooltip: { callbacks: { label: function(context) { return `${context.dataset.label}: $${context.raw.toFixed(2)}`; } } } }, scales: { y: { beginAtZero: true, ticks: { callback: function(value) { return '$' + value.toFixed(2); } } } } } }); } // Renderizar gráfico de actividad de anuncios function renderAdActivityChart(adData) { const ctx = document.getElementById('adActivityChart').getContext('2d'); const adIds = Object.keys(adData.adData); const views = adIds.map(id => adData.adData[id].views); const earnings = adIds.map(id => adData.adData[id].earnings); const uniqueUsers = adIds.map(id => adData.adData[id].uniqueUsers); if (charts.adActivity) { charts.adActivity.destroy(); } charts.adActivity = new Chart(ctx, { type: 'bar', data: { labels: adIds.map(id => `Anuncio ${id.substring(0, 5)}`), datasets: [ { label: 'Visualizaciones', data: views, backgroundColor: 'rgba(153, 102, 255, 0.7)', borderColor: 'rgba(153, 102, 255, 1)', borderWidth: 1, yAxisID: 'y' }, { label: 'Ganancias ($)', data: earnings, backgroundColor: 'rgba(255, 159, 64, 0.7)', borderColor: 'rgba(255, 159, 64, 1)', borderWidth: 1, type: 'line', yAxisID: 'y1' }, { label: 'Usuarios únicos', data: uniqueUsers, backgroundColor: 'rgba(75, 192, 192, 0.7)', borderColor: 'rgba(75, 192, 192, 1)', borderWidth: 1, hidden: true, yAxisID: 'y' } ] }, options: { responsive: true, plugins: { legend: { position: 'top', }, tooltip: { callbacks: { label: function(context) { let label = context.dataset.label || ''; if (label.includes('Ganancias')) { return `${label}: $${context.raw.toFixed(2)}`; } return `${label}: ${context.raw}`; } } }, title: { display: true, text: `Resumen: ${adData.totalViews} visualizaciones | $${adData.totalEarnings.toFixed(2)} ganancias | ${adData.totalUsers} usuarios únicos` } }, scales: { y: { type: 'linear', display: true, position: 'left', title: { display: true, text: 'Visualizaciones/Usuarios' }, ticks: { precision: 0 } }, y1: { type: 'linear', display: true, position: 'right', title: { display: true, text: 'Ganancias ($)' }, grid: { drawOnChartArea: false }, ticks: { callback: function(value) { return '$' + value.toFixed(2); } } } } } }); } // Configurar event listeners function setupEventListeners() { // Rango de fechas rangeItems.forEach(item => { item.addEventListener("click", (e) => { e.preventDefault(); currentRangeValue = parseInt(e.target.dataset.range); currentRange.textContent = e.target.textContent; loadStats(); }); }); } // Inicializar cuando el DOM esté listo document.addEventListener("DOMContentLoaded", initStatsManager);