window.BriefingCharts = (function () { var charts = {}; function destroyAll() { Object.keys(charts).forEach(function (k) { if (charts[k]) { charts[k].destroy(); charts[k] = null; } }); } function parseContent(content) { var parts = (content || '').split(/\n---\n/); var ai = parts[0] || ''; var summary = ''; var actions = []; var sm = ai.match(/##\s*Samenvatting\s*\n([\s\S]*?)(?=##\s*Actiepunten|$)/i); if (sm) summary = sm[1].trim(); var am = ai.match(/##\s*Actiepunten[^\n]*\n([\s\S]*)/i); if (am) { actions = am[1].split('\n').map(function (l) { return l.replace(/^[-*]\s*/, '').trim(); }).filter(Boolean); } if (!summary && ai.trim()) summary = ai.trim().slice(0, 600); return { summary: summary, actions: actions }; } function chartColors() { return { gold: 'rgba(232, 168, 56, 0.85)', goldDim: 'rgba(232, 168, 56, 0.35)', cyan: 'rgba(56, 189, 248, 0.85)', green: 'rgba(62, 207, 142, 0.85)', red: 'rgba(239, 68, 68, 0.85)', gray: 'rgba(107, 114, 128, 0.85)', grid: 'rgba(148, 163, 184, 0.12)', text: '#94a3b8', }; } function renderPipeline(canvas, stats) { if (!canvas) return; var rows = stats.deals_by_stage || []; var c = chartColors(); charts.pipeline = new Chart(canvas, { type: 'bar', data: { labels: rows.map(function (r) { return r.stage || '?'; }), datasets: [{ label: 'Pipeline EUR', data: rows.map(function (r) { return Number(r.total) || 0; }), backgroundColor: c.gold, borderRadius: 6, }], }, options: { responsive: true, maintainAspectRatio: true, plugins: { legend: { display: false }, title: { display: true, text: 'Pipeline per stage', color: c.text } }, scales: { y: { ticks: { color: c.text, callback: function (v) { return '€' + v.toLocaleString('nl-NL'); } }, grid: { color: c.grid } }, x: { ticks: { color: c.text }, grid: { display: false } }, }, }, }); } function renderSentiment(canvas, stats) { if (!canvas) return; var files = stats.nas_files || []; var counts = { positive: 0, neutral: 0, negative: 0 }; files.forEach(function (f) { var s = (f.sentiment_label || 'neutral').toLowerCase(); if (counts[s] !== undefined) counts[s]++; }); if (!files.length) { counts.neutral = 1; } var c = chartColors(); charts.sentiment = new Chart(canvas, { type: 'doughnut', data: { labels: ['Positief', 'Neutraal', 'Negatief'], datasets: [{ data: [counts.positive, counts.neutral, counts.negative], backgroundColor: [c.green, c.gray, c.red], borderWidth: 0 }], }, options: { responsive: true, maintainAspectRatio: true, plugins: { legend: { position: 'bottom', labels: { color: c.text } }, title: { display: true, text: 'NAS sentiment', color: c.text } }, }, }); } function renderWords(canvas, stats) { if (!canvas) return; var rows = (stats.top_words || []).slice(0, 8); var c = chartColors(); charts.words = new Chart(canvas, { type: 'bar', data: { labels: rows.map(function (r) { return r.lemma; }), datasets: [{ label: 'Count', data: rows.map(function (r) { return Number(r.total) || 0; }), backgroundColor: c.cyan, borderRadius: 6, }], }, options: { indexAxis: 'y', responsive: true, maintainAspectRatio: true, plugins: { legend: { display: false }, title: { display: true, text: 'Top woorden NAS', color: c.text } }, scales: { x: { ticks: { color: c.text }, grid: { color: c.grid } }, y: { ticks: { color: c.text }, grid: { display: false } }, }, }, }); } function renderAgents(canvas, stats) { if (!canvas) return; var events = stats.recent_events || []; var map = {}; events.forEach(function (e) { var a = e.agent_name || 'other'; map[a] = (map[a] || 0) + 1; }); var labels = Object.keys(map); var values = labels.map(function (k) { return map[k]; }); var c = chartColors(); charts.agents = new Chart(canvas, { type: 'polarArea', data: { labels: labels, datasets: [{ data: values, backgroundColor: [c.gold, c.cyan, c.green, c.red, c.gray, c.goldDim] }], }, options: { responsive: true, maintainAspectRatio: true, plugins: { legend: { position: 'bottom', labels: { color: c.text } }, title: { display: true, text: 'Agent activiteit', color: c.text } }, scales: { r: { ticks: { display: false }, grid: { color: c.grid } } }, }, }); } function renderKpis(container, stats) { if (!container) return; var items = [ { label: 'Pipeline', value: '€' + Math.round(stats.pipeline_eur || 0).toLocaleString('nl-NL'), cls: 'green' }, { label: 'Klanten', value: stats.clients || 0, cls: 'purple' }, { label: 'Deals', value: stats.deals || 0, cls: '' }, { label: 'NAS docs', value: stats.nas_docs || 0, cls: 'cyan' }, { label: 'Goedkeuringen', value: stats.pending_approvals || 0, cls: 'amber' }, ]; container.innerHTML = items.map(function (it) { return '
' + it.label + '' + it.value + '
'; }).join(''); } function renderNasList(container, stats) { if (!container) return; var files = stats.nas_files || []; if (!files.length) { container.innerHTML = '

Geen NAS documenten.

'; return; } container.innerHTML = '' + files.map(function (f) { var badge = 'badge-' + (f.sentiment_label || 'neutral'); return ''; }).join('') + '
BestandTypeSentimentWoorden
' + (f.filename || '') + '' + (f.doc_type || '') + '' + (f.sentiment_label || '') + '' + (f.word_count || '—') + '
'; } function renderPending(container, stats) { if (!container) return; var items = stats.pending_items || []; if (!items.length) { container.innerHTML = '

Geen openstaande goedkeuringen 🎉

'; return; } container.innerHTML = items.map(function (it) { return '
' + (it.agent_name || '') + ' ' + (it.title || it.event_type || '') + '
'; }).join(''); } function render(root, stats, content, createdAt) { if (!root || !stats) return; destroyAll(); var parsed = parseContent(content); root.style.display = 'block'; var empty = document.getElementById('briefing-empty'); if (empty) empty.style.display = 'none'; var meta = document.getElementById('briefing-meta'); if (meta) meta.textContent = createdAt ? ('Laatst bijgewerkt: ' + String(createdAt).substring(0, 19).replace('T', ' ')) : ''; var sumEl = document.getElementById('briefing-summary-text'); if (sumEl) sumEl.textContent = parsed.summary || (content ? 'Geen samenvatting.' : 'Klik op «Genereer dagrapport» voor een AI-samenvatting en actiepunten.'); var actEl = document.getElementById('briefing-actions-list'); if (actEl) { actEl.innerHTML = parsed.actions.length ? parsed.actions.map(function (a) { return '
  • ' + a + '
  • '; }).join('') : '
  • Geen actiepunten — genereer opnieuw.
  • '; } renderKpis(document.getElementById('briefing-kpis'), stats); renderPipeline(document.getElementById('chart-pipeline'), stats); renderSentiment(document.getElementById('chart-sentiment'), stats); renderWords(document.getElementById('chart-words'), stats); renderAgents(document.getElementById('chart-agents'), stats); renderNasList(document.getElementById('briefing-nas-list'), stats); renderPending(document.getElementById('briefing-pending-list'), stats); var full = document.getElementById('briefing-full-text'); if (full) full.textContent = content || ''; } return { render: render, destroyAll: destroyAll, parseContent: parseContent }; })();