/** * Dashboard JavaScript functionality */ let productivityChart = null; let toolsChart = null; async function loadDashboardData() { try { // Show loading state showLoadingState(); // Load data in parallel const [ analyticsSummary, productivityMetrics, toolUsageStats, recentProjects ] = await Promise.all([ apiClient.getAnalyticsSummary(), apiClient.getProductivityMetrics(null, 30), apiClient.getToolUsageStats(null, null, 30), apiClient.getProjects(5, 0) ]); // Update summary cards updateSummaryCards(analyticsSummary); // Update engagement metrics updateEngagementMetrics(productivityMetrics); // Update charts updateProductivityChart(productivityMetrics.productivity_trends); updateToolsChart(toolUsageStats); // Update recent projects updateRecentProjects(recentProjects); // Update quick stats updateQuickStats(analyticsSummary); } catch (error) { console.error('Failed to load dashboard data:', error); showErrorState('Failed to load dashboard data. Please try refreshing the page.'); } } function showLoadingState() { // Update cards with loading state document.getElementById('total-sessions').textContent = '-'; document.getElementById('total-time').textContent = '-'; document.getElementById('active-projects').textContent = '-'; document.getElementById('productivity-score').textContent = '-'; } function showErrorState(message) { // Show error message const alertHtml = ` `; const container = document.querySelector('.container'); container.insertAdjacentHTML('afterbegin', alertHtml); } function updateSummaryCards(summary) { const overview = summary.overview || {}; document.getElementById('total-sessions').textContent = overview.total_sessions?.toLocaleString() || '0'; document.getElementById('total-time').textContent = overview.total_time_hours?.toFixed(1) || '0'; document.getElementById('active-projects').textContent = overview.projects_tracked?.toLocaleString() || '0'; document.getElementById('productivity-score').textContent = overview.productivity_indicators?.productivity_score?.toFixed(0) || '0'; } function updateEngagementMetrics(metrics) { document.getElementById('engagement-score').textContent = metrics.engagement_score?.toFixed(0) || '-'; document.getElementById('avg-session-length').textContent = metrics.average_session_length?.toFixed(0) || '-'; document.getElementById('think-time').textContent = metrics.think_time_average?.toFixed(0) || '-'; } function updateProductivityChart(trendsData) { const ctx = document.getElementById('productivityChart').getContext('2d'); // Destroy existing chart if (productivityChart) { productivityChart.destroy(); } const labels = trendsData.map(item => { const date = new Date(item.date); return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }); }); const data = trendsData.map(item => item.score); productivityChart = new Chart(ctx, { type: 'line', data: { labels: labels, datasets: [{ label: 'Productivity Score', data: data, borderColor: '#007bff', backgroundColor: 'rgba(0, 123, 255, 0.1)', borderWidth: 2, fill: true, tension: 0.4 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, max: 100, ticks: { callback: function(value) { return value + '%'; } } }, x: { ticks: { maxTicksLimit: 7 } } } } }); } function updateToolsChart(toolsData) { const ctx = document.getElementById('toolsChart').getContext('2d'); // Destroy existing chart if (toolsChart) { toolsChart.destroy(); } // Get top 5 tools const topTools = toolsData.slice(0, 5); const labels = topTools.map(item => item.tool_name); const data = topTools.map(item => item.usage_count); const colors = [ '#007bff', '#28a745', '#17a2b8', '#ffc107', '#dc3545' ]; toolsChart = new Chart(ctx, { type: 'doughnut', data: { labels: labels, datasets: [{ data: data, backgroundColor: colors, borderWidth: 2, borderColor: '#fff' }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'bottom', labels: { padding: 20, usePointStyle: true } } } } }); } function updateRecentProjects(projects) { const container = document.getElementById('recent-projects'); if (!projects.length) { container.innerHTML = `

No projects found

`; return; } const projectsHtml = projects.map(project => `
${project.name}
${project.path}
${ApiUtils.formatDuration(project.total_time_minutes)} ${project.total_sessions} sessions ${project.languages ? ` ${project.languages.slice(0, 2).join(', ')} ` : ''}
${ApiUtils.formatRelativeTime(project.last_activity)}
`).join(''); container.innerHTML = projectsHtml; } function updateQuickStats(summary) { const container = document.getElementById('quick-stats'); const recent = summary.recent_activity || {}; const statsHtml = `
${recent.sessions_last_7_days || 0}
Sessions this week
${(recent.time_last_7_days_hours || 0).toFixed(1)}h
Time this week
${(recent.daily_average_last_week || 0).toFixed(1)}
Daily average
${summary.overview?.tracking_period_days || 0}
Days tracked
`; container.innerHTML = statsHtml; } function refreshDashboard() { // Add visual feedback const refreshBtn = document.querySelector('[onclick="refreshDashboard()"]'); const icon = refreshBtn.querySelector('i'); icon.classList.add('fa-spin'); refreshBtn.disabled = true; loadDashboardData().finally(() => { icon.classList.remove('fa-spin'); refreshBtn.disabled = false; }); } // Auto-refresh dashboard every 5 minutes setInterval(() => { loadDashboardData(); }, 5 * 60 * 1000); // Handle window resize for charts window.addEventListener('resize', () => { if (productivityChart) { productivityChart.resize(); } if (toolsChart) { toolsChart.resize(); } });