/** * DataScience Masterclass - Progress Tracking * Persists user progress across all modules using localStorage * Version: 2.0.0 */ (function () { 'use strict'; const STORAGE_KEY = 'ds-masterclass-progress'; const VERSION = '2.0.0'; // Module definitions const moduleConfig = { 'deep-learning': { name: 'Deep Learning', icon: '🧠', totalTopics: 12, path: '/DeepLearning/index.html' }, 'machine-learning': { name: 'Machine Learning', icon: '🤖', totalTopics: 42, path: '/ml_complete-all-topics/index.html' }, 'statistics': { name: 'Statistics', icon: '📊', totalTopics: 41, path: '/complete-statistics/index.html' }, 'mathematics': { name: 'Mathematics', icon: '📐', totalTopics: 15, path: '/math-ds-complete/index.html' }, 'feature-engineering': { name: 'Feature Engineering', icon: '⚙️', totalTopics: 12, path: '/feature-engineering/index.html' }, 'visualization': { name: 'Visualization', icon: '📈', totalTopics: 8, path: '/Visualization/index.html' }, 'prompt-engineering': { name: 'Prompt Engineering', icon: '💬', totalTopics: 12, path: '/prompt-engineering-guide/index.html' } }; let progressData = null; /** * Initialize progress tracking */ function init() { loadProgress(); detectCurrentModule(); updateUI(); bindEvents(); console.log('📊 Progress tracking initialized'); } /** * Load progress from localStorage */ function loadProgress() { try { const stored = localStorage.getItem(STORAGE_KEY); if (stored) { const data = JSON.parse(stored); if (data.version === VERSION) { progressData = data; } else { // Migrate or reset if version mismatch progressData = createInitialProgress(); } } else { progressData = createInitialProgress(); } } catch (e) { console.error('Failed to load progress:', e); progressData = createInitialProgress(); } } /** * Create initial progress structure */ function createInitialProgress() { const progress = { version: VERSION, lastUpdated: new Date().toISOString(), lastVisited: null, modules: {} }; Object.keys(moduleConfig).forEach(moduleId => { progress.modules[moduleId] = { completed: [], lastTopic: null, timeSpent: 0 }; }); return progress; } /** * Save progress to localStorage */ function saveProgress() { try { progressData.lastUpdated = new Date().toISOString(); localStorage.setItem(STORAGE_KEY, JSON.stringify(progressData)); } catch (e) { console.error('Failed to save progress:', e); } } /** * Detect current module from URL */ function detectCurrentModule() { const path = window.location.pathname; if (path.includes('DeepLearning')) return 'deep-learning'; if (path.includes('ml_complete')) return 'machine-learning'; if (path.includes('complete-statistics')) return 'statistics'; if (path.includes('math-ds-complete')) return 'mathematics'; if (path.includes('feature-engineering')) return 'feature-engineering'; if (path.includes('Visualization')) return 'visualization'; if (path.includes('prompt-engineering')) return 'prompt-engineering'; return null; } /** * Mark a topic as completed */ function markCompleted(moduleId, topicId) { if (!progressData.modules[moduleId]) return; const completed = progressData.modules[moduleId].completed; if (!completed.includes(topicId)) { completed.push(topicId); progressData.modules[moduleId].lastTopic = topicId; progressData.lastVisited = { module: moduleId, topic: topicId, timestamp: new Date().toISOString() }; saveProgress(); updateUI(); showCompletionToast(moduleId, topicId); } } /** * Mark a topic as incomplete */ function markIncomplete(moduleId, topicId) { if (!progressData.modules[moduleId]) return; const completed = progressData.modules[moduleId].completed; const index = completed.indexOf(topicId); if (index > -1) { completed.splice(index, 1); saveProgress(); updateUI(); } } /** * Toggle topic completion */ function toggleCompleted(moduleId, topicId) { if (!progressData.modules[moduleId]) return; if (isCompleted(moduleId, topicId)) { markIncomplete(moduleId, topicId); } else { markCompleted(moduleId, topicId); } } /** * Check if a topic is completed */ function isCompleted(moduleId, topicId) { if (!progressData.modules[moduleId]) return false; return progressData.modules[moduleId].completed.includes(topicId); } /** * Get module progress */ function getModuleProgress(moduleId) { if (!progressData.modules[moduleId] || !moduleConfig[moduleId]) { return { completed: 0, total: 0, percentage: 0 }; } const completed = progressData.modules[moduleId].completed.length; const total = moduleConfig[moduleId].totalTopics; const percentage = Math.round((completed / total) * 100); return { completed, total, percentage }; } /** * Get overall progress */ function getOverallProgress() { let totalCompleted = 0; let totalTopics = 0; Object.keys(moduleConfig).forEach(moduleId => { if (progressData.modules[moduleId]) { totalCompleted += progressData.modules[moduleId].completed.length; } totalTopics += moduleConfig[moduleId].totalTopics; }); const percentage = Math.round((totalCompleted / totalTopics) * 100); return { completed: totalCompleted, total: totalTopics, percentage }; } /** * Get last visited info */ function getLastVisited() { return progressData.lastVisited; } /** * Reset all progress */ function resetProgress() { if (confirm('Are you sure you want to reset all progress? This cannot be undone.')) { progressData = createInitialProgress(); saveProgress(); updateUI(); } } /** * Reset module progress */ function resetModuleProgress(moduleId) { if (progressData.modules[moduleId]) { progressData.modules[moduleId] = { completed: [], lastTopic: null, timeSpent: 0 }; saveProgress(); updateUI(); } } /** * Update UI elements with progress */ function updateUI() { // Update progress bars document.querySelectorAll('[data-progress-module]').forEach(el => { const moduleId = el.dataset.progressModule; const progress = getModuleProgress(moduleId); const bar = el.querySelector('.progress-bar'); const label = el.querySelector('.progress-label-value'); if (bar) bar.style.width = progress.percentage + '%'; if (label) label.textContent = `${progress.completed}/${progress.total}`; }); // Update overall progress document.querySelectorAll('[data-progress-overall]').forEach(el => { const progress = getOverallProgress(); const bar = el.querySelector('.progress-bar'); const label = el.querySelector('.progress-label-value'); if (bar) bar.style.width = progress.percentage + '%'; if (label) label.textContent = `${progress.percentage}%`; }); // Update topic checkboxes document.querySelectorAll('[data-topic-id]').forEach(el => { const topicId = el.dataset.topicId; const moduleId = el.dataset.moduleId || detectCurrentModule(); if (moduleId) { el.classList.toggle('completed', isCompleted(moduleId, topicId)); } }); // Update continue button updateContinueButton(); } /** * Update "Continue where you left off" button */ function updateContinueButton() { const continueBtn = document.getElementById('continue-learning-btn'); if (!continueBtn) return; const lastVisited = getLastVisited(); if (lastVisited && moduleConfig[lastVisited.module]) { const config = moduleConfig[lastVisited.module]; continueBtn.href = config.path + '#' + lastVisited.topic; continueBtn.querySelector('.continue-module-name').textContent = config.name; continueBtn.style.display = 'flex'; } else { continueBtn.style.display = 'none'; } } /** * Show completion toast notification */ function showCompletionToast(moduleId, topicId) { const toast = document.createElement('div'); toast.className = 'progress-toast'; toast.innerHTML = ` Topic completed! `; document.body.appendChild(toast); // Trigger animation setTimeout(() => toast.classList.add('show'), 10); // Remove after delay setTimeout(() => { toast.classList.remove('show'); setTimeout(() => toast.remove(), 300); }, 2000); } /** * Bind event listeners */ function bindEvents() { // Mark topic complete when clicking checkbox document.addEventListener('click', (e) => { const topicEl = e.target.closest('[data-topic-id]'); if (topicEl && e.target.classList.contains('topic-checkbox')) { const topicId = topicEl.dataset.topicId; const moduleId = topicEl.dataset.moduleId || detectCurrentModule(); if (moduleId) { toggleCompleted(moduleId, topicId); } } }); // Track time spent (basic implementation) let startTime = Date.now(); window.addEventListener('beforeunload', () => { const moduleId = detectCurrentModule(); if (moduleId && progressData.modules[moduleId]) { const elapsed = Math.round((Date.now() - startTime) / 1000); progressData.modules[moduleId].timeSpent += elapsed; saveProgress(); } }); } /** * Export progress data */ function exportProgress() { const dataStr = JSON.stringify(progressData, null, 2); const blob = new Blob([dataStr], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'ds-masterclass-progress.json'; a.click(); URL.revokeObjectURL(url); } /** * Import progress data */ function importProgress(file) { const reader = new FileReader(); reader.onload = (e) => { try { const data = JSON.parse(e.target.result); if (data.version && data.modules) { progressData = data; saveProgress(); updateUI(); alert('Progress imported successfully!'); } else { alert('Invalid progress file'); } } catch (err) { alert('Failed to import progress: ' + err.message); } }; reader.readAsText(file); } // Expose API window.DSProgress = { init, markCompleted, markIncomplete, toggleCompleted, isCompleted, getModuleProgress, getOverallProgress, getLastVisited, resetProgress, resetModuleProgress, exportProgress, importProgress }; // Initialize on DOM ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();