@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
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>