// Reports page JavaScript let currentPeriod = 30; let categoryFilter = ''; let trendChart = null; let categoryChart = null; let monthlyChart = null; // Load reports data async function loadReportsData() { try { const params = new URLSearchParams({ period: currentPeriod, ...(categoryFilter && { category_id: categoryFilter }) }); const data = await apiCall(`/api/reports-stats?${params}`); displayReportsData(data); } catch (error) { console.error('Failed to load reports data:', error); showToast('Failed to load reports', 'error'); } } // Display reports data function displayReportsData(data) { // Update KPI cards document.getElementById('total-spent').textContent = formatCurrency(data.total_spent, data.currency); // Spending change indicator const spentChange = document.getElementById('spent-change'); const changeValue = data.percent_change; const isIncrease = changeValue > 0; spentChange.className = `flex items-center font-medium px-1.5 py-0.5 rounded ${ isIncrease ? 'text-red-500 dark:text-red-400 bg-red-500/10' : 'text-green-500 dark:text-green-400 bg-green-500/10' }`; spentChange.innerHTML = ` ${isIncrease ? 'trending_up' : 'trending_down'} ${Math.abs(changeValue).toFixed(1)}% `; // Top category document.getElementById('top-category').textContent = data.top_category.name; document.getElementById('top-category-amount').textContent = formatCurrency(data.top_category.amount, data.currency); // Average daily document.getElementById('avg-daily').textContent = formatCurrency(data.avg_daily, data.currency); // Average change indicator const avgChange = document.getElementById('avg-change'); const avgChangeValue = data.avg_daily_change; const isAvgIncrease = avgChangeValue > 0; avgChange.className = `flex items-center font-medium px-1.5 py-0.5 rounded ${ isAvgIncrease ? 'text-red-500 dark:text-red-400 bg-red-500/10' : 'text-green-500 dark:text-green-400 bg-green-500/10' }`; avgChange.innerHTML = ` ${isAvgIncrease ? 'trending_up' : 'trending_down'} ${Math.abs(avgChangeValue).toFixed(1)}% `; // Savings rate document.getElementById('savings-rate').textContent = `${data.savings_rate}%`; // Update charts updateTrendChart(data.daily_trend); updateCategoryChart(data.category_breakdown); updateMonthlyChart(data.monthly_comparison); } // Update trend chart function updateTrendChart(dailyData) { const ctx = document.getElementById('trend-chart'); if (!ctx) return; // Get theme const isDark = document.documentElement.classList.contains('dark'); const textColor = isDark ? '#94a3b8' : '#64748b'; const gridColor = isDark ? '#334155' : '#e2e8f0'; if (trendChart) { trendChart.destroy(); } trendChart = new Chart(ctx, { type: 'line', data: { labels: dailyData.map(d => d.date), datasets: [{ label: 'Daily Spending', data: dailyData.map(d => d.amount), borderColor: '#3b82f6', backgroundColor: 'rgba(59, 130, 246, 0.1)', fill: true, tension: 0.4, pointRadius: 4, pointBackgroundColor: isDark ? '#1e293b' : '#ffffff', pointBorderColor: '#3b82f6', pointBorderWidth: 2, pointHoverRadius: 6 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false }, tooltip: { backgroundColor: isDark ? '#1e293b' : '#ffffff', titleColor: isDark ? '#f8fafc' : '#0f172a', bodyColor: isDark ? '#94a3b8' : '#64748b', borderColor: isDark ? '#334155' : '#e2e8f0', borderWidth: 1, padding: 12, displayColors: false, callbacks: { label: function(context) { return formatCurrency(context.parsed.y, 'USD'); } } } }, scales: { x: { grid: { color: gridColor, drawBorder: false }, ticks: { color: textColor, maxRotation: 45, minRotation: 0 } }, y: { grid: { color: gridColor, drawBorder: false }, ticks: { color: textColor, callback: function(value) { return '$' + value.toFixed(0); } } } } } }); } // Update category pie chart function updateCategoryChart(categories) { const ctx = document.getElementById('category-pie-chart'); if (!ctx) return; const isDark = document.documentElement.classList.contains('dark'); if (categoryChart) { categoryChart.destroy(); } if (categories.length === 0) { categoryChart = null; document.getElementById('category-legend').innerHTML = '
No data available
'; return; } categoryChart = new Chart(ctx, { type: 'doughnut', data: { labels: categories.map(c => c.name), datasets: [{ data: categories.map(c => c.amount), backgroundColor: categories.map(c => c.color), borderWidth: 2, borderColor: isDark ? '#1a2632' : '#ffffff' }] }, options: { responsive: true, maintainAspectRatio: true, plugins: { legend: { display: false }, tooltip: { backgroundColor: isDark ? '#1e293b' : '#ffffff', titleColor: isDark ? '#f8fafc' : '#0f172a', bodyColor: isDark ? '#94a3b8' : '#64748b', borderColor: isDark ? '#334155' : '#e2e8f0', borderWidth: 1, padding: 12, callbacks: { label: function(context) { const label = context.label || ''; const value = formatCurrency(context.parsed, 'USD'); const percentage = categories[context.dataIndex].percentage; return `${label}: ${value} (${percentage}%)`; } } } } } }); // Update legend const legendHTML = categories.slice(0, 6).map(cat => `