import apiClient from './apiClient.js'; class ChartLabView { constructor(section) { this.section = section; this.symbolSelect = section.querySelector('[data-chart-symbol]'); this.timeframeButtons = section.querySelectorAll('[data-chart-timeframe]'); this.indicatorInputs = section.querySelectorAll('[data-indicator]'); this.analyzeButton = section.querySelector('[data-run-analysis]'); this.canvas = section.querySelector('#chart-lab-canvas'); this.insightsContainer = section.querySelector('[data-ai-insights]'); this.chart = null; this.symbol = 'BTC'; this.timeframe = '7d'; } async init() { await this.loadChart(); this.bindEvents(); } bindEvents() { if (this.symbolSelect) { this.symbolSelect.addEventListener('change', async () => { this.symbol = this.symbolSelect.value; await this.loadChart(); }); } this.timeframeButtons.forEach((btn) => { btn.addEventListener('click', async () => { this.timeframeButtons.forEach((b) => b.classList.remove('active')); btn.classList.add('active'); this.timeframe = btn.dataset.chartTimeframe; await this.loadChart(); }); }); if (this.analyzeButton) { this.analyzeButton.addEventListener('click', () => this.runAnalysis()); } } async loadChart() { if (!this.canvas) return; const result = await apiClient.getPriceChart(this.symbol, this.timeframe); const container = this.canvas.parentElement; if (!result.ok) { if (container) { let errorNode = container.querySelector('.chart-error'); if (!errorNode) { errorNode = document.createElement('div'); errorNode.className = 'inline-message inline-error chart-error'; container.appendChild(errorNode); } errorNode.textContent = result.error; } return; } if (container) { const errorNode = container.querySelector('.chart-error'); if (errorNode) errorNode.remove(); } const points = result.data || []; const labels = points.map((point) => point.time || point.timestamp || ''); const prices = points.map((point) => point.price || point.close || point.value); if (this.chart) { this.chart.destroy(); } this.chart = new Chart(this.canvas, { type: 'line', data: { labels, datasets: [ { label: `${this.symbol} (${this.timeframe})`, data: prices, borderColor: '#f472b6', backgroundColor: 'rgba(244, 114, 182, 0.2)', fill: true, tension: 0.4, }, ], }, options: { scales: { x: { ticks: { color: 'var(--text-muted)' } }, y: { ticks: { color: 'var(--text-muted)' } }, }, plugins: { legend: { display: false }, }, }, }); } async runAnalysis() { if (!this.insightsContainer) return; const enabledIndicators = Array.from(this.indicatorInputs) .filter((input) => input.checked) .map((input) => input.value); this.insightsContainer.innerHTML = '

Running AI analysis...

'; const result = await apiClient.analyzeChart(this.symbol, this.timeframe, enabledIndicators); if (!result.ok) { this.insightsContainer.innerHTML = `
${result.error}
`; return; } const payload = result.data || {}; const insights = payload.insights || result.insights || payload; if (!insights) { this.insightsContainer.innerHTML = '

No AI insights returned.

'; return; } const summary = insights.narrative?.summary?.summary || insights.narrative?.summary || insights.narrative?.summary_text; const signals = insights.narrative?.signals || {}; const bullets = Object.entries(signals) .map(([key, value]) => `
  • ${key}: ${(value?.label || 'n/a')} (${value?.score ?? '—'})
  • `) .join(''); this.insightsContainer.innerHTML = `

    AI Insights

    Direction: ${insights.change_direction || 'N/A'} (${insights.change_percent ?? '—'}%)

    Range: High ${insights.high ?? '—'} / Low ${insights.low ?? '—'}

    ${summary || insights.narrative?.summary?.summary || insights.narrative?.summary || ''}

    `; } } export default ChartLabView;