UNPKG

@codejoy/random-learner

Version:

A comprehensive interview preparation and learning companion with AI-powered questions, mock interviews, skill assessments, and company-specific question sets for technical job interviews

1,203 lines (1,030 loc) 41.9 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Learning Analytics Dashboard</title> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: #333; min-height: 100vh; padding: 20px; } .container { max-width: 1400px; margin: 0 auto; background: white; border-radius: 15px; padding: 30px; box-shadow: 0 10px 30px rgba(0,0,0,0.2); animation: slideIn 0.3s ease-out; } @keyframes slideIn { from { opacity: 0; transform: translateY(-20px); } to { opacity: 1; transform: translateY(0); } } .header { text-align: center; margin-bottom: 30px; padding-bottom: 20px; border-bottom: 2px solid #f0f0f0; } .header h1 { color: #667eea; font-size: 2.5em; margin-bottom: 10px; } .header p { color: #666; font-size: 1.1em; } .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; margin-bottom: 30px; } .stat-card { background: linear-gradient(135deg, #f8f9ff, #e8ecff); border-radius: 12px; padding: 20px; text-align: center; border-left: 4px solid #667eea; transition: transform 0.2s ease; } .stat-card:hover { transform: translateY(-2px); } .stat-value { font-size: 2.5em; font-weight: bold; color: #667eea; margin-bottom: 5px; } .stat-label { color: #666; font-size: 0.9em; text-transform: uppercase; letter-spacing: 0.5px; } .stat-change { font-size: 0.8em; margin-top: 5px; } .stat-change.positive { color: #4caf50; } .stat-change.negative { color: #f44336; } .charts-section { display: grid; grid-template-columns: 1fr 1fr; gap: 30px; margin-bottom: 30px; } .chart-container { background: #f8f9ff; border-radius: 12px; padding: 20px; border-left: 4px solid #667eea; } .chart-title { font-size: 1.2em; font-weight: bold; color: #333; margin-bottom: 15px; text-align: center; } .chart-canvas { max-height: 300px; } .topics-section { margin-bottom: 30px; } .section-title { font-size: 1.5em; font-weight: bold; color: #333; margin-bottom: 20px; text-align: center; } .topics-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; } .topic-card { background: white; border-radius: 8px; padding: 15px; border-left: 4px solid #667eea; box-shadow: 0 2px 8px rgba(0,0,0,0.1); } .topic-name { font-weight: bold; color: #333; margin-bottom: 8px; text-transform: capitalize; } .topic-stats { display: flex; justify-content: space-between; align-items: center; } .topic-accuracy { font-size: 1.2em; font-weight: bold; } .accuracy-high { color: #4caf50; } .accuracy-medium { color: #ff9800; } .accuracy-low { color: #f44336; } .topic-count { color: #666; font-size: 0.9em; } .achievements-section { margin-bottom: 30px; } .achievements-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 15px; } .achievement-card { background: linear-gradient(135deg, #ffd700, #ffed4e); border-radius: 8px; padding: 15px; text-align: center; box-shadow: 0 2px 8px rgba(0,0,0,0.1); } .achievement-icon { font-size: 2em; margin-bottom: 10px; } .achievement-name { font-weight: bold; color: #333; margin-bottom: 5px; } .achievement-desc { color: #666; font-size: 0.9em; } .ai-insights-section { background: linear-gradient(135deg, #e8f5e8, #f0fff0); border-radius: 12px; padding: 25px; border-left: 4px solid #4caf50; margin-bottom: 30px; } .insights-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } .insights-title { font-size: 1.3em; font-weight: bold; color: #333; } .insights-button { background: linear-gradient(135deg, #4caf50, #45a049); color: white; border: none; border-radius: 8px; padding: 10px 20px; cursor: pointer; font-size: 1em; font-weight: 500; transition: all 0.2s ease; } .insights-button:hover:not(:disabled) { background: linear-gradient(135deg, #45a049, #3d8b40); transform: translateY(-2px); } .insights-button:disabled { opacity: 0.6; cursor: not-allowed; } .insights-content { background: white; border-radius: 8px; padding: 20px; white-space: pre-wrap; line-height: 1.6; color: #333; min-height: 100px; border: 1px solid #e0e0e0; } .loading { text-align: center; color: #666; font-style: italic; } .loading::after { content: ''; animation: dots 1.5s infinite; } @keyframes dots { 0%, 20% { content: '.'; } 40% { content: '..'; } 60%, 100% { content: '...'; } } .actions-section { text-align: center; padding-top: 20px; border-top: 2px solid #f0f0f0; } .action-button { background: linear-gradient(135deg, #667eea, #764ba2); color: white; border: none; border-radius: 8px; padding: 12px 25px; margin: 0 10px; cursor: pointer; font-size: 1em; font-weight: 500; transition: all 0.2s ease; } .action-button:hover { background: linear-gradient(135deg, #5a67d8, #6b46c1); transform: translateY(-2px); } .action-button.danger { background: linear-gradient(135deg, #f44336, #d32f2f); } .action-button.danger:hover { background: linear-gradient(135deg, #d32f2f, #c62828); } /* Interview Readiness Styles */ .readiness-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 30px; margin-bottom: 20px; } .readiness-overview { background: #f8f9fa; border-radius: 15px; padding: 25px; text-align: center; } .readiness-score { margin-bottom: 20px; } .score-circle { width: 120px; height: 120px; border-radius: 50%; background: conic-gradient(#667eea 0deg, #667eea var(--readiness-angle, 0deg), #e9ecef var(--readiness-angle, 0deg), #e9ecef 360deg); display: flex; align-items: center; justify-content: center; margin: 0 auto 15px; position: relative; } .score-circle::before { content: ''; width: 90px; height: 90px; background: white; border-radius: 50%; position: absolute; } .score-value { font-size: 1.8em; font-weight: bold; color: #667eea; z-index: 1; } .score-label { font-size: 1.1em; color: #666; font-weight: 500; } .readiness-details { text-align: left; } .detail-item { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #e9ecef; } .detail-item:last-child { border-bottom: none; } .detail-label { color: #666; } .detail-value { font-weight: bold; color: #333; } .company-readiness { background: #f8f9fa; border-radius: 15px; padding: 25px; } .company-readiness h3 { margin-bottom: 20px; color: #333; } .company-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px; } .company-item { background: white; padding: 15px; border-radius: 10px; border-left: 4px solid #667eea; display: flex; justify-content: space-between; align-items: center; } .company-name { font-weight: 500; color: #333; } .company-score { font-weight: bold; color: #667eea; } /* Skill Assessment Styles */ .skill-categories { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; margin-bottom: 25px; } .skill-category { background: #f8f9fa; border-radius: 15px; padding: 20px; border-left: 5px solid #667eea; } .category-name { font-size: 1.1em; font-weight: bold; color: #333; margin-bottom: 15px; } .category-score { font-size: 2em; font-weight: bold; color: #667eea; margin-bottom: 10px; } .skill-bar { height: 6px; background: #e9ecef; border-radius: 3px; overflow: hidden; margin-bottom: 10px; } .skill-fill { height: 100%; background: linear-gradient(90deg, #667eea, #764ba2); border-radius: 3px; transition: width 0.8s ease; } .confidence-indicator { font-size: 0.8em; padding: 2px 8px; border-radius: 10px; font-weight: bold; text-transform: uppercase; } .confidence-high { background: #d4edda; color: #155724; } .confidence-medium { background: #fff3cd; color: #856404; } .confidence-low { background: #f8d7da; color: #721c24; } .assessment-actions { text-align: center; margin-top: 20px; } .action-button.secondary { background: #6c757d; margin-left: 15px; } .action-button.secondary:hover { background: #5a6268; } /* Weakness Analysis Styles */ .weakness-summary { display: grid; grid-template-columns: 1fr 2fr; gap: 30px; } .weakness-stats { background: #f8f9fa; border-radius: 15px; padding: 25px; display: flex; flex-direction: column; gap: 20px; } .stat-item { text-align: center; } .stat-value { font-size: 2.5em; font-weight: bold; color: #667eea; margin-bottom: 5px; } .stat-label { color: #666; font-size: 0.9em; } .top-weaknesses { background: #f8f9fa; border-radius: 15px; padding: 25px; } .weakness-item { display: flex; justify-content: space-between; align-items: center; padding: 12px 0; border-bottom: 1px solid #e9ecef; } .weakness-item:last-child { border-bottom: none; } .weakness-name { font-weight: 500; color: #333; } .weakness-severity { padding: 2px 8px; border-radius: 10px; font-size: 0.7em; font-weight: bold; text-transform: uppercase; } .severity-critical { background: #f8d7da; color: #721c24; } .severity-high { background: #fff3cd; color: #856404; } .severity-medium { background: #cce5ff; color: #004085; } .severity-low { background: #d4edda; color: #155724; } /* Enhanced Responsive Design */ @media (max-width: 768px) { .readiness-grid { grid-template-columns: 1fr; } .weakness-summary { grid-template-columns: 1fr; } .company-grid { grid-template-columns: 1fr; } .skill-categories { grid-template-columns: 1fr; } } @media (max-width: 768px) { .charts-section { grid-template-columns: 1fr; } .container { padding: 20px; margin: 10px; } .header h1 { font-size: 2em; } } </style> </head> <body> <div class="container"> <div class="header"> <h1>📊 Learning Analytics Dashboard</h1> <p>Track your progress, identify strengths, and get AI-powered insights</p> </div> <div id="loading" class="loading" style="text-align: center; padding: 50px;"> Loading your analytics data </div> <div id="dashboard-content" style="display: none;"> <!-- Stats Overview --> <div class="stats-grid"> <div class="stat-card"> <div class="stat-value" id="total-questions">0</div> <div class="stat-label">Total Questions</div> <div class="stat-change" id="questions-change"></div> </div> <div class="stat-card"> <div class="stat-value" id="overall-accuracy">0%</div> <div class="stat-label">Overall Accuracy</div> <div class="stat-change" id="accuracy-change"></div> </div> <div class="stat-card"> <div class="stat-value" id="current-streak">0</div> <div class="stat-label">Current Streak</div> <div class="stat-change" id="streak-info"></div> </div> <div class="stat-card"> <div class="stat-value" id="weekly-questions">0</div> <div class="stat-label">This Week</div> <div class="stat-change" id="weekly-accuracy"></div> </div> </div> <!-- Charts --> <div class="charts-section"> <div class="chart-container"> <div class="chart-title">Weekly Progress</div> <canvas id="weekly-chart" class="chart-canvas"></canvas> </div> <div class="chart-container"> <div class="chart-title">Topic Performance</div> <canvas id="topics-chart" class="chart-canvas"></canvas> </div> </div> <!-- AI Insights --> <div class="ai-insights-section"> <div class="insights-header"> <div class="insights-title">🤖 AI Learning Insights</div> <button id="generate-insights-btn" class="insights-button">Get AI Insights</button> </div> <div id="insights-content" class="insights-content"> Click "Get AI Insights" to receive personalized recommendations based on your learning data. </div> </div> <!-- Topics Performance --> <div class="topics-section"> <div class="section-title">📚 Topic Performance</div> <div id="topics-grid" class="topics-grid"> <!-- Topics will be populated here --> </div> </div> <!-- Achievements --> <div class="achievements-section"> <div class="section-title">🏆 Achievements</div> <div id="achievements-grid" class="achievements-grid"> <!-- Achievements will be populated here --> </div> </div> <!-- Interview Readiness Section --> <div class="section"> <h2 class="section-title">🎯 Interview Readiness</h2> <div class="readiness-grid"> <div class="readiness-overview"> <div class="readiness-score" id="overall-readiness"> <div class="score-circle"> <div class="score-value" id="readiness-percentage">0%</div> </div> <div class="score-label">Interview Ready</div> </div> <div class="readiness-details"> <div class="detail-item"> <span class="detail-label">Experience Level:</span> <span class="detail-value" id="experience-level">Analyzing...</span> </div> <div class="detail-item"> <span class="detail-label">Skill Score:</span> <span class="detail-value" id="skill-score">0/100</span> </div> <div class="detail-item"> <span class="detail-label">Mock Interviews:</span> <span class="detail-value" id="mock-interviews">0</span> </div> </div> </div> <div class="company-readiness"> <h3>Company Readiness</h3> <div class="company-grid" id="company-readiness"> <!-- Company readiness will be populated --> </div> </div> </div> </div> <!-- Skill Assessment Section --> <div class="section"> <h2 class="section-title">🏆 Skill Assessment</h2> <div class="skill-categories" id="skill-categories"> <!-- Skill categories will be populated --> </div> <div class="assessment-actions"> <button id="conduct-assessment-btn" class="action-button">🔍 Conduct Full Assessment</button> <button id="view-assessment-btn" class="action-button secondary">📊 View Last Assessment</button> </div> </div> <!-- Weakness Analysis Section --> <div class="section"> <h2 class="section-title">🎯 Weakness Analysis</h2> <div class="weakness-summary" id="weakness-summary"> <div class="weakness-stats"> <div class="stat-item"> <div class="stat-value" id="total-weaknesses">0</div> <div class="stat-label">Areas to Improve</div> </div> <div class="stat-item"> <div class="stat-value" id="critical-weaknesses">0</div> <div class="stat-label">Critical Issues</div> </div> <div class="stat-item"> <div class="stat-value" id="targeted-questions">0</div> <div class="stat-label">Targeted Questions</div> </div> </div> <div class="top-weaknesses" id="top-weaknesses"> <!-- Top weaknesses will be populated --> </div> </div> </div> <!-- Actions --> <div class="actions-section"> <button id="export-btn" class="action-button">📤 Export Data</button> <button id="clear-btn" class="action-button danger">🗑️ Clear Analytics</button> </div> </div> </div> <script> const { ipcRenderer } = require('electron'); let analyticsData = null; let weeklyChart = null; let topicsChart = null; // Load analytics data when page loads async function loadAnalytics() { try { analyticsData = await ipcRenderer.invoke('get-analytics'); // Load additional data for enhanced analytics await loadEnhancedAnalytics(); displayAnalytics(); document.getElementById('loading').style.display = 'none'; document.getElementById('dashboard-content').style.display = 'block'; } catch (error) { console.error('Failed to load analytics:', error); document.getElementById('loading').textContent = 'Failed to load analytics data'; } } // Load enhanced analytics data async function loadEnhancedAnalytics() { try { // Load skill assessment data const latestAssessment = await ipcRenderer.invoke('get-latest-assessment'); if (latestAssessment) { displaySkillAssessment(latestAssessment); displayInterviewReadiness(latestAssessment.interviewReadiness); } // Load weakness analysis const weaknessSummary = await ipcRenderer.invoke('get-weakness-summary'); if (weaknessSummary) { displayWeaknessAnalysis(weaknessSummary); } // Load interview stats const interviewStats = await ipcRenderer.invoke('get-interview-stats'); if (interviewStats) { updateInterviewStats(interviewStats); } } catch (error) { console.error('Failed to load enhanced analytics:', error); } } function displayAnalytics() { if (!analyticsData) return; // Update stats cards document.getElementById('total-questions').textContent = analyticsData.totalStats.questionsAnswered; document.getElementById('overall-accuracy').textContent = analyticsData.totalStats.overallAccuracy + '%'; document.getElementById('current-streak').textContent = analyticsData.totalStats.currentStreak; document.getElementById('weekly-questions').textContent = analyticsData.weeklyStats.totalQuestions; // Update stat changes document.getElementById('questions-change').textContent = `Longest streak: ${analyticsData.totalStats.longestStreak}`; document.getElementById('accuracy-change').textContent = `${analyticsData.totalStats.correctAnswers}/${analyticsData.totalStats.questionsAnswered} correct`; document.getElementById('streak-info').textContent = `Best: ${analyticsData.totalStats.longestStreak}`; document.getElementById('weekly-accuracy').textContent = `${analyticsData.weeklyStats.accuracy}% accuracy`; // Create charts createWeeklyChart(); createTopicsChart(); // Display topics displayTopics(); // Display achievements displayAchievements(); } function createWeeklyChart() { const ctx = document.getElementById('weekly-chart').getContext('2d'); if (weeklyChart) { weeklyChart.destroy(); } const dailyData = analyticsData.weeklyStats.dailyData; weeklyChart = new Chart(ctx, { type: 'line', data: { labels: dailyData.map(d => d.day), datasets: [{ label: 'Questions Answered', data: dailyData.map(d => d.questions), borderColor: '#667eea', backgroundColor: 'rgba(102, 126, 234, 0.1)', tension: 0.4, fill: true }, { label: 'Accuracy %', data: dailyData.map(d => d.accuracy), borderColor: '#4caf50', backgroundColor: 'rgba(76, 175, 80, 0.1)', tension: 0.4, yAxisID: 'y1' }] }, options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, position: 'left' }, y1: { type: 'linear', display: true, position: 'right', max: 100, grid: { drawOnChartArea: false, }, } }, plugins: { legend: { display: true } } } }); } function createTopicsChart() { const ctx = document.getElementById('topics-chart').getContext('2d'); if (topicsChart) { topicsChart.destroy(); } const topTopics = analyticsData.topicPerformance.slice(0, 6); topicsChart = new Chart(ctx, { type: 'doughnut', data: { labels: topTopics.map(t => t.topic.charAt(0).toUpperCase() + t.topic.slice(1)), datasets: [{ data: topTopics.map(t => t.total), backgroundColor: [ '#667eea', '#4caf50', '#ff9800', '#f44336', '#9c27b0', '#00bcd4' ] }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'bottom' } } } }); } function displayTopics() { const topicsGrid = document.getElementById('topics-grid'); topicsGrid.innerHTML = ''; if (analyticsData.topicPerformance.length === 0) { topicsGrid.innerHTML = '<p style="text-align: center; color: #666; grid-column: 1 / -1;">No topic data available yet. Start answering questions to see your performance!</p>'; return; } analyticsData.topicPerformance.forEach(topic => { const topicCard = document.createElement('div'); topicCard.className = 'topic-card'; let accuracyClass = 'accuracy-medium'; if (topic.accuracy >= 80) accuracyClass = 'accuracy-high'; else if (topic.accuracy < 60) accuracyClass = 'accuracy-low'; topicCard.innerHTML = ` <div class="topic-name">${topic.topic}</div> <div class="topic-stats"> <span class="topic-accuracy ${accuracyClass}">${topic.accuracy}%</span> <span class="topic-count">${topic.correct}/${topic.total}</span> </div> `; topicsGrid.appendChild(topicCard); }); } function displayAchievements() { const achievementsGrid = document.getElementById('achievements-grid'); achievementsGrid.innerHTML = ''; if (analyticsData.achievements.length === 0) { achievementsGrid.innerHTML = '<p style="text-align: center; color: #666; grid-column: 1 / -1;">No achievements yet. Keep learning to unlock your first achievement! 🎯</p>'; return; } analyticsData.achievements.forEach(achievement => { const achievementCard = document.createElement('div'); achievementCard.className = 'achievement-card'; achievementCard.innerHTML = ` <div class="achievement-icon">🏆</div> <div class="achievement-name">${achievement.name}</div> <div class="achievement-desc">${achievement.description}</div> `; achievementsGrid.appendChild(achievementCard); }); } // AI Insights document.getElementById('generate-insights-btn').addEventListener('click', async () => { const button = document.getElementById('generate-insights-btn'); const content = document.getElementById('insights-content'); button.disabled = true; button.textContent = 'Generating...'; content.innerHTML = '<div class="loading">Analyzing your learning data and generating personalized insights</div>'; try { const result = await ipcRenderer.invoke('get-ai-insights'); if (result.success) { content.textContent = result.insights; } else { content.textContent = result.error || 'Failed to generate insights. Please try again.'; } } catch (error) { content.textContent = 'Failed to generate insights. Please check your AI configuration and try again.'; } finally { button.disabled = false; button.textContent = 'Refresh Insights'; } }); // Export data // Display skill assessment data function displaySkillAssessment(assessment) { if (!assessment || !assessment.categoryScores) return; const container = document.getElementById('skill-categories'); container.innerHTML = ''; const categoryNames = { 'technical-skills': 'Technical Skills', 'problem-solving': 'Problem Solving', 'coding-proficiency': 'Coding Proficiency', 'communication': 'Communication' }; Object.entries(assessment.categoryScores).forEach(([category, data]) => { const categoryDiv = document.createElement('div'); categoryDiv.className = 'skill-category'; categoryDiv.innerHTML = ` <div class="category-name">${categoryNames[category] || category}</div> <div class="category-score">${Math.round(data.score)}</div> <div class="skill-bar"> <div class="skill-fill" style="width: ${data.score}%"></div> </div> <div class="confidence-indicator confidence-${data.confidence}"> ${data.confidence} confidence </div> `; container.appendChild(categoryDiv); }); // Update overall skill score document.getElementById('skill-score').textContent = `${assessment.overallScore}/100`; document.getElementById('experience-level').textContent = assessment.experienceLevel?.name || 'Analyzing...'; } // Display interview readiness function displayInterviewReadiness(readiness) { if (!readiness) return; // Update overall readiness const readinessPercentage = readiness.overall || 0; document.getElementById('readiness-percentage').textContent = `${readinessPercentage}%`; // Set readiness circle progress const readinessAngle = (readinessPercentage / 100) * 360; document.getElementById('overall-readiness').querySelector('.score-circle') .style.setProperty('--readiness-angle', `${readinessAngle}deg`); // Display company readiness const companyContainer = document.getElementById('company-readiness'); companyContainer.innerHTML = ''; const companyNames = { 'startup': 'Startup', 'big-tech': 'Big Tech', 'enterprise': 'Enterprise', 'consulting': 'Consulting' }; if (readiness.byCompany) { Object.entries(readiness.byCompany).forEach(([company, score]) => { const companyDiv = document.createElement('div'); companyDiv.className = 'company-item'; companyDiv.innerHTML = ` <span class="company-name">${companyNames[company] || company}</span> <span class="company-score">${score}%</span> `; companyContainer.appendChild(companyDiv); }); } } // Display weakness analysis function displayWeaknessAnalysis(weaknessSummary) { if (!weaknessSummary) return; // Update weakness stats document.getElementById('total-weaknesses').textContent = weaknessSummary.totalWeaknesses || 0; document.getElementById('critical-weaknesses').textContent = weaknessSummary.criticalWeaknesses || 0; // Get targeted questions count ipcRenderer.invoke('get-targeted-topics', 10).then(topics => { document.getElementById('targeted-questions').textContent = topics.length; }); // Display top weaknesses const weaknessContainer = document.getElementById('top-weaknesses'); weaknessContainer.innerHTML = '<h4 style="margin-bottom: 15px; color: #333;">Top Areas for Improvement</h4>'; if (weaknessSummary.topWeaknesses && weaknessSummary.topWeaknesses.length > 0) { weaknessSummary.topWeaknesses.forEach(weakness => { const weaknessDiv = document.createElement('div'); weaknessDiv.className = 'weakness-item'; weaknessDiv.innerHTML = ` <span class="weakness-name">${weakness.description || weakness.name}</span> <span class="weakness-severity severity-${weakness.severity}">${weakness.severity}</span> `; weaknessContainer.appendChild(weaknessDiv); }); } else { weaknessContainer.innerHTML += '<p style="color: #666; text-align: center;">No significant weaknesses identified. Great job!</p>'; } } // Update interview stats function updateInterviewStats(interviewStats) { if (!interviewStats) return; document.getElementById('mock-interviews').textContent = interviewStats.totalInterviews || 0; } // Conduct skill assessment async function conductSkillAssessment() { try { document.getElementById('conduct-assessment-btn').disabled = true; document.getElementById('conduct-assessment-btn').textContent = '🔍 Analyzing...'; const assessment = await ipcRenderer.invoke('conduct-skill-assessment'); displaySkillAssessment(assessment); displayInterviewReadiness(assessment.interviewReadiness); document.getElementById('conduct-assessment-btn').disabled = false; document.getElementById('conduct-assessment-btn').textContent = '🔍 Conduct Full Assessment'; alert('Skill assessment completed! Check the results above.'); } catch (error) { console.error('Failed to conduct assessment:', error); document.getElementById('conduct-assessment-btn').disabled = false; document.getElementById('conduct-assessment-btn').textContent = '🔍 Conduct Full Assessment'; alert('Failed to conduct assessment: ' + error.message); } } // View skill assessment async function viewSkillAssessment() { try { // This will open the dedicated skill assessment window const { ipcRenderer } = require('electron'); await ipcRenderer.invoke('show-skill-assessment-window'); } catch (error) { console.error('Failed to open skill assessment:', error); } } // Event listeners for new buttons document.getElementById('conduct-assessment-btn').addEventListener('click', conductSkillAssessment); document.getElementById('view-assessment-btn').addEventListener('click', viewSkillAssessment); document.getElementById('export-btn').addEventListener('click', async () => { try { const data = await ipcRenderer.invoke('export-analytics'); const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `learning-analytics-${new Date().toISOString().split('T')[0]}.json`; a.click(); URL.revokeObjectURL(url); } catch (error) { alert('Failed to export data: ' + error.message); } }); // Clear analytics document.getElementById('clear-btn').addEventListener('click', async () => { if (confirm('Are you sure you want to clear all analytics data? This action cannot be undone.')) { try { await ipcRenderer.invoke('clear-analytics'); alert('Analytics data cleared successfully!'); loadAnalytics(); // Reload the page } catch (error) { alert('Failed to clear data: ' + error.message); } } }); // Load analytics on page load loadAnalytics(); </script> </body> </html>