// 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) { // Store user currency globally window.userCurrency = data.currency || 'RON'; // Update KPI cards document.getElementById('total-spent').textContent = formatCurrency(data.total_spent, window.userCurrency); // 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, window.userCurrency || 'RON'); } } } }, 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 - Beautiful CSS conic-gradient design function updateCategoryChart(categories) { const pieChart = document.getElementById('category-pie-chart'); const pieTotal = document.getElementById('category-pie-total'); const pieLegend = document.getElementById('category-legend'); if (!pieChart || !pieLegend) return; const userCurrency = window.userCurrency || 'RON'; if (categories.length === 0) { pieChart.style.background = 'conic-gradient(#233648 0% 100%)'; if (pieTotal) pieTotal.textContent = formatCurrency(0, userCurrency); pieLegend.innerHTML = '
No data available
'; return; } // Calculate total const total = categories.reduce((sum, cat) => sum + parseFloat(cat.amount || 0), 0); if (pieTotal) pieTotal.textContent = formatCurrency(total, userCurrency); // Generate conic gradient segments let currentPercent = 0; const gradientSegments = categories.map(cat => { const percent = total > 0 ? (parseFloat(cat.amount || 0) / total) * 100 : 0; const segment = `${cat.color} ${currentPercent}% ${currentPercent + percent}%`; currentPercent += percent; return segment; }); // Apply gradient pieChart.style.background = `conic-gradient(${gradientSegments.join(', ')})`; // Generate compact legend const legendHTML = categories.map(cat => { const percent = total > 0 ? ((parseFloat(cat.amount || 0) / total) * 100).toFixed(1) : 0; return `No recommendations at this time
${rec.description}
Failed to load recommendations