/* ── AIMS Insight – Dashboard JS ── */ let donutChart = null; let barChart = null; /* ─────────────────────────────── FILTER RESET ─────────────────────────────── */ function resetFilters() { document.getElementById('startDate').value = ''; document.getElementById('endDate').value = ''; document.getElementById('filterTopic').value = 'all'; document.getElementById('filterSentiment').value = 'all'; setTimeout(() => { loadData(); }, 50); } /* ─────────────────────────────── LOAD DATA FROM API ─────────────────────────────── */ async function loadData() { const params = new URLSearchParams({ start_date: document.getElementById('startDate').value, end_date: document.getElementById('endDate').value, topic: document.getElementById('filterTopic').value, sentiment: document.getElementById('filterSentiment').value }); try { const res = await fetch(`/api/dashboard-data?${params}`); const data = await res.json(); updateKPIs(data); updateDonut(data.sentiment); updateBar(data.topics); updateTable(data.recent); } catch (e) { console.error('Dashboard load error:', e); } } /* ─────────────────────────────── KPI UPDATE ─────────────────────────────── */ function updateKPIs(data) { document.getElementById('kpiTotal').textContent = data.total; document.getElementById('kpiSatisfaction').textContent = data.satisfaction + '%'; document.getElementById('kpiNeutral').textContent = data.sentiment.Neutral; document.getElementById('kpiNegative').textContent = data.sentiment.Negative; } /* ─────────────────────────────── DONUT CHART ─────────────────────────────── */ function updateDonut(sentiment) { const ctx = document.getElementById('donutChart').getContext('2d'); const dataArr = [ sentiment.Positive, sentiment.Neutral, sentiment.Negative ]; if (donutChart) donutChart.destroy(); donutChart = new Chart(ctx, { type: 'doughnut', data: { labels: ['Positive', 'Neutral', 'Negative'], datasets: [{ data: dataArr, backgroundColor: ['#28a745', '#6c757d', '#dc3545'], borderWidth: 3, borderColor: '#fff', hoverOffset: 6 }] }, options: { responsive: true, maintainAspectRatio: false, cutout: '65%', plugins: { legend: { position: 'bottom', labels: { padding: 14, font: { size: 12 } } } } } }); } /* ─────────────────────────────── BAR CHART ─────────────────────────────── */ function updateBar(topics) { const ctx = document.getElementById('barChart').getContext('2d'); const sorted = Object.entries(topics).sort((a, b) => b[1] - a[1]); const labels = sorted.map(([k]) => k); const values = sorted.map(([, v]) => v); const colors = values.map((_, i) => { const opacity = 1 - (i / Math.max(values.length, 1)) * 0.5; return `rgba(128,0,0,${opacity})`; }); if (barChart) barChart.destroy(); barChart = new Chart(ctx, { type: 'bar', data: { labels, datasets: [{ label: 'Feedbacks', data: values, backgroundColor: colors, borderRadius: 6, borderSkipped: false }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, ticks: { stepSize: 1, font: { size: 11 } }, grid: { color: 'rgba(0,0,0,.04)' } }, x: { ticks: { font: { size: 11 } }, grid: { display: false } } } } }); } /* ─────────────────────────────── TABLE UPDATE ─────────────────────────────── */ function updateTable(rows) { const tbody = document.getElementById('recentTable'); if (!rows || rows.length === 0) { tbody.innerHTML = ` No data available for these filters. `; return; } tbody.innerHTML = rows.map(r => { const label = r.sentiment_label === 'Positive' ? 'badge-positive' : r.sentiment_label === 'Negative' ? 'badge-negative' : 'badge-neutral'; const labelFR = r.sentiment_label === 'Positive' ? 'Positive' : r.sentiment_label === 'Negative' ? 'Negative' : 'Neutral'; const date = r.created_at ? r.created_at.slice(0, 16) : '—'; const comment = (r.comment_text || '').length > 80 ? r.comment_text.slice(0, 80) + '…' : r.comment_text; return ` ${date} ${r.topic} ${comment} ${labelFR} `; }).join(''); } /* ─────────────────────────────── USER DROPDOWN MENU (PROFILE) ─────────────────────────────── */ function toggleUserMenu() { const menu = document.getElementById("userMenu"); if (menu) menu.classList.toggle("show"); } // close dropdown when clicking outside document.addEventListener("click", function (e) { const badge = document.querySelector(".user-badge"); const menu = document.getElementById("userMenu"); if (!badge || !menu) return; if (!badge.contains(e.target)) { menu.classList.remove("show"); } }); /* ─────────────────────────────── INIT ─────────────────────────────── */ document.addEventListener('DOMContentLoaded', loadData);