// Dashboard Charts JavaScript - Mit echten Daten aus der API document.addEventListener('DOMContentLoaded', function() { console.log('Dashboard charts initializing...'); // Prüfe ob Chart.js geladen ist if (typeof Chart === 'undefined') { console.error('Chart.js not loaded!'); return; } console.log('Chart.js loaded, version:', Chart.version); // Dashboard-Daten über API laden fetch('/api/dashboard-data') .then(response => { console.log('API Response status:', response.status); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }) .then(data => { console.log('Dashboard data loaded:', data); initializeCharts(data); }) .catch(error => { console.error('Error loading dashboard data:', error); // Fallback mit Demo-Daten console.log('Using fallback demo data...'); initializeChartsWithDemoData(); }); }); function initializeChartsWithDemoData() { console.log('Initializing charts with demo data...'); const demoData = { monthly_stats: [ { month: '2024-01', income: 3000, expenses: 2200, net_change: 800, balance: 5000 }, { month: '2024-02', income: 3200, expenses: 2400, net_change: 800, balance: 5800 }, { month: '2024-03', income: 2800, expenses: 2100, net_change: 700, balance: 6500 } ], category_stats: [ { category_name: 'Lebensmittel', total_amount: 600, percentage: 27.3 }, { category_name: 'Transport', total_amount: 250, percentage: 11.4 }, { category_name: 'Unterhaltung', total_amount: 180, percentage: 8.2 }, { category_name: 'Sonstiges', total_amount: 170, percentage: 7.7 } ], transaction_trend: [ { date: '2024-03-01T00:00:00Z', income: 100, expense: 50, balance: 5000 }, { date: '2024-03-02T00:00:00Z', income: 0, expense: 80, balance: 4920 }, { date: '2024-03-03T00:00:00Z', income: 200, expense: 120, balance: 5000 }, { date: '2024-03-04T00:00:00Z', income: 50, expense: 90, balance: 4960 }, { date: '2024-03-05T00:00:00Z', income: 0, expense: 70, balance: 4890 } ], asset_overview: { total_bank_balance: 15000, total_depot_value: 25000 } }; initializeCharts(demoData); } function initializeCharts(data) { console.log('Initializing charts with data:', data); // Chart 1: Monatliche Statistiken createMonthlyChart(data); // Chart 2: Einnahmen vs Ausgaben createIncomeExpenseChart(data); // Chart 3: Trend-Chart createTrendChart(data); console.log('All charts initialized'); } function createMonthlyChart(data) { const ctx = document.getElementById('monthlyChart'); if (!ctx) { console.warn('Monthly chart canvas not found'); return; } try { // Echte Datenstruktur aus der API verwenden const monthlyStats = data.monthly_stats || data.monthlyStats || []; console.log('Monthly stats data:', monthlyStats); new Chart(ctx.getContext('2d'), { type: 'bar', data: { labels: monthlyStats.map(d => { // Month aus "2024-01" Format zu "Januar 2024" konvertieren const [year, month] = d.month.split('-'); const monthNames = ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember']; return `${monthNames[parseInt(month) - 1]} ${year}`; }), datasets: [{ label: 'Einnahmen', data: monthlyStats.map(d => parseFloat(d.income || 0)), backgroundColor: 'rgba(34, 197, 94, 0.7)', borderColor: 'rgba(34, 197, 94, 1)', borderWidth: 1 }, { label: 'Ausgaben', data: monthlyStats.map(d => parseFloat(d.expenses || 0)), backgroundColor: 'rgba(239, 68, 68, 0.7)', borderColor: 'rgba(239, 68, 68, 1)', borderWidth: 1 }] }, options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, ticks: { callback: function(value) { return '€' + value.toLocaleString(); } } } }, plugins: { title: { display: true, text: 'Monatliche Ein- und Ausgaben' } } } }); console.log('Monthly chart created'); } catch (error) { console.error('Error creating monthly chart:', error); } } function createIncomeExpenseChart(data) { const ctx = document.getElementById('incomeExpenseChart'); if (!ctx) { console.warn('Income/Expense chart canvas not found'); return; } try { // Echte Datenstruktur verwenden const monthlyStats = data.monthly_stats || data.monthlyStats || []; console.log('Income/Expense stats data:', monthlyStats); const totalIncome = monthlyStats.reduce((sum, d) => sum + parseFloat(d.income || 0), 0); const totalExpenses = monthlyStats.reduce((sum, d) => sum + parseFloat(d.expenses || 0), 0); new Chart(ctx.getContext('2d'), { type: 'pie', data: { labels: ['Einnahmen', 'Ausgaben'], datasets: [{ data: [totalIncome, totalExpenses], backgroundColor: ['#22c55e', '#ef4444'], borderWidth: 2, borderColor: '#ffffff' }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { title: { display: true, text: 'Einnahmen vs. Ausgaben' }, legend: { position: 'bottom' }, tooltip: { callbacks: { label: function(context) { return context.label + ': €' + context.parsed.toLocaleString(); } } } } } }); console.log('Income/Expense chart created'); } catch (error) { console.error('Error creating income/expense chart:', error); } } function createTrendChart(data) { const ctx = document.getElementById('trendChart'); if (!ctx) { console.warn('Trend chart canvas not found'); return; } try { // Echte Datenstruktur verwenden const trendData = data.transaction_trend || data.transactionTrend || []; console.log('Trend data:', trendData); new Chart(ctx.getContext('2d'), { type: 'bar', // Basis-Typ für Balken data: { labels: trendData.map(d => { // Datum als Monat/Jahr formatieren für 12-Monats-Ansicht const date = new Date(d.date); return date.toLocaleDateString('de-DE', { month: 'short', year: 'numeric' }); }), datasets: [{ label: 'Einnahmen', type: 'bar', // Explizit als Bar definieren data: trendData.map(d => parseFloat(d.income || 0)), backgroundColor: 'rgba(34, 197, 94, 0.7)', borderColor: 'rgba(34, 197, 94, 1)', borderWidth: 1, yAxisID: 'y' }, { label: 'Ausgaben', type: 'bar', // Explizit als Bar definieren data: trendData.map(d => parseFloat(d.expense || 0)), backgroundColor: 'rgba(239, 68, 68, 0.7)', borderColor: 'rgba(239, 68, 68, 1)', borderWidth: 1, yAxisID: 'y' }, { label: 'Saldo', type: 'line', // Explizit als Linie definieren data: trendData.map(d => parseFloat(d.balance || 0)), backgroundColor: 'rgba(59, 130, 246, 0.1)', borderColor: 'rgba(59, 130, 246, 1)', borderWidth: 3, fill: false, tension: 0.1, yAxisID: 'y1', pointRadius: 3, pointHoverRadius: 5 }] }, options: { responsive: true, maintainAspectRatio: false, interaction: { mode: 'index', intersect: false, }, scales: { x: { display: true, title: { display: true, text: 'Datum' } }, y: { type: 'linear', display: true, position: 'left', title: { display: true, text: 'Einnahmen/Ausgaben (€)' }, beginAtZero: true, ticks: { callback: function(value) { return '€' + value.toLocaleString(); } } }, y1: { type: 'linear', display: true, position: 'right', title: { display: true, text: 'Saldo (€)' }, grid: { drawOnChartArea: false, }, ticks: { callback: function(value) { return '€' + value.toLocaleString(); } } } }, plugins: { title: { display: true, text: '90-Tage Trend' }, legend: { position: 'top' }, tooltip: { callbacks: { label: function(context) { return context.dataset.label + ': €' + context.parsed.y.toLocaleString(); } } } } } }); console.log('Trend chart created'); } catch (error) { console.error('Error creating trend chart:', error); } }