/** * Academy UI Manager * Handles level selection, checkpoint modals, and integration with campaign/preference/library systems */ class AcademyUI { constructor() { this.currentModal = null; this.init(); } init() { console.log('🎓 Academy UI Manager initialized'); } /** * Show level selection screen * Displays all 30 levels with locked/unlocked states */ showLevelSelect() { const unlockedLevels = window.campaignManager.getUnlockedLevels(); const completedLevels = window.gameData.academyProgress.completedLevels; const currentLevel = window.gameData.academyProgress.currentLevel; let html = `

🎓 The Academy - Campaign

Select your next level

${completedLevels.length}/30 Levels Complete

`; // Generate 30 level buttons for (let i = 1; i <= 30; i++) { const isUnlocked = unlockedLevels.includes(i); const isCompleted = completedLevels.includes(i); const isCurrent = i === currentLevel; const isCheckpoint = window.campaignManager.isCheckpointLevel(i); const arc = window.campaignManager.getArcForLevel(i); const statusClass = isCompleted ? 'completed' : isUnlocked ? 'unlocked' : 'locked'; const icon = isCompleted ? '✓' : isCheckpoint ? '⚡' : isUnlocked ? '▶' : '🔒'; html += ` `; } html += `

Select a level to view details

`; // Show in the academy setup container const setupContainer = document.getElementById('academy-setup'); if (setupContainer) { setupContainer.innerHTML = html; setupContainer.style.display = 'block'; } } /** * Select a level and show its details * @param {number} levelNum - Level to select */ selectLevel(levelNum) { const arc = window.campaignManager.getArcForLevel(levelNum); const isCheckpoint = window.campaignManager.isCheckpointLevel(levelNum); const isCompleted = window.campaignManager.isLevelCompleted(levelNum); // Show level details in info panel const infoPanelContent = this.getLevelInfoHTML(levelNum, arc, isCheckpoint, isCompleted); const infoPanel = document.getElementById('level-info-panel'); if (infoPanel) { infoPanel.innerHTML = infoPanelContent; } } /** * Get level info HTML * @param {number} levelNum - Level number * @param {string} arc - Arc name * @param {boolean} isCheckpoint - Is checkpoint level * @param {boolean} isCompleted - Is completed * @returns {string} HTML content */ getLevelInfoHTML(levelNum, arc, isCheckpoint, isCompleted) { return `

Level ${levelNum}: ${this.getLevelTitle(levelNum)}

${arc} Arc ${isCheckpoint ? '⚡ Checkpoint' : ''} ${isCompleted ? '✓ Completed' : ''}

${this.getLevelDescription(levelNum)}

${isCheckpoint ? '

💡 You will be asked to update your preferences before starting this level.

' : ''}
`; } /** * Get level title based on number * @param {number} levelNum - Level number * @returns {string} Level title */ getLevelTitle(levelNum) { const titles = { 1: "First Edge", 5: "Foundation Complete", 10: "Feature Discovery Complete", 15: "Deepening", 20: "Mastery", 25: "Final Challenge", 30: "Graduation" }; return titles[levelNum] || `Training Session ${levelNum}`; } /** * Get level description * @param {number} levelNum - Level number * @returns {string} Level description */ getLevelDescription(levelNum) { if (levelNum === 1) return "Welcome to The Academy. Begin your journey with basic edging training."; if (levelNum === 5) return "Complete the Foundation arc. Test your progress with a checkpoint session."; if (levelNum === 10) return "Feature Discovery complete. Time to optimize your preferences."; if (levelNum === 15) return "Halfway through. Deepen your training with advanced techniques."; if (levelNum === 20) return "Enter the Mastery arc. Push your limits further."; if (levelNum === 25) return "Final checkpoint before graduation. Prepare for the ultimate test."; if (levelNum === 30) return "The final test. Graduate from The Academy."; return "Continue your training journey with this session."; } /** * Start a level (with checkpoint modal if needed) * @param {number} levelNum - Level to start */ startLevel(levelNum) { console.log(`🎯 Starting Level ${levelNum}...`); // Check if this is a checkpoint level if (window.campaignManager.isCheckpointLevel(levelNum)) { this.showCheckpointModal(levelNum); } else { this.beginLevel(levelNum); } } /** * Show checkpoint preference modal * @param {number} levelNum - Checkpoint level number */ showCheckpointModal(levelNum) { const config = window.preferenceManager.getCheckpointModalConfig(levelNum); if (!config) { console.error('No checkpoint config for level', levelNum); this.beginLevel(levelNum); return; } const modalHTML = this.buildCheckpointModalHTML(levelNum, config); // Create modal overlay const overlay = document.createElement('div'); overlay.className = 'checkpoint-modal-overlay'; overlay.innerHTML = modalHTML; document.body.appendChild(overlay); this.currentModal = overlay; // Initialize tabs this.initCheckpointModalTabs(levelNum, config); } /** * Build checkpoint modal HTML * @param {number} levelNum - Level number * @param {Object} config - Modal configuration * @returns {string} Modal HTML */ buildCheckpointModalHTML(levelNum, config) { return `

${config.title}

${config.description}

`; } /** * Initialize checkpoint modal tabs * @param {number} levelNum - Level number * @param {Object} config - Modal configuration */ initCheckpointModalTabs(levelNum, config) { // Tab switching const tabBtns = document.querySelectorAll('.tab-btn'); tabBtns.forEach(btn => { btn.addEventListener('click', () => { const tabName = btn.dataset.tab; // Update active states tabBtns.forEach(b => b.classList.remove('active')); btn.classList.add('active'); document.querySelectorAll('.tab-panel').forEach(panel => { panel.classList.remove('active'); }); document.getElementById(`${tabName}-panel`).classList.add('active'); }); }); // Populate preferences editor this.populatePreferencesEditor(config.categories); // Populate library manager this.populateLibraryManager(); } /** * Populate preferences editor * @param {Array} categories - Categories to show */ populatePreferencesEditor(categories) { const container = document.getElementById('preferences-editor'); if (!container) return; let html = ''; categories.forEach(category => { const prefs = window.preferenceManager.getCategoryPreferences(category); html += `
`; html += `

${this.getCategoryDisplayName(category)}

`; html += this.buildCategoryEditor(category, prefs); html += `
`; }); container.innerHTML = html; } /** * Get category display name * @param {string} category - Category key * @returns {string} Display name */ getCategoryDisplayName(category) { const names = { contentThemes: '🎭 Content Themes', visualPreferences: '👁️ Visual Preferences', intensity: '⚡ Intensity Levels', captionTone: '💬 Caption Tone', audioPreferences: '🔊 Audio Preferences', sessionDuration: '⏱️ Session Duration', featurePreferences: '🎮 Feature Preferences', boundaries: '🛡️ Boundaries' }; return names[category] || category; } /** * Build category editor HTML * @param {string} category - Category name * @param {Object} prefs - Preferences object * @returns {string} Editor HTML */ buildCategoryEditor(category, prefs) { if (category === 'intensity') { return this.buildIntensitySliders(prefs); } else if (category === 'sessionDuration') { return this.buildDurationSelector(prefs); } else { return this.buildCheckboxes(category, prefs); } } /** * Build intensity sliders * @param {Object} prefs - Intensity preferences * @returns {string} HTML */ buildIntensitySliders(prefs) { let html = ''; for (const [key, value] of Object.entries(prefs)) { html += `
`; } return html; } /** * Build duration selector * @param {Object} prefs - Duration preferences * @returns {string} HTML */ buildDurationSelector(prefs) { const options = ['short', 'medium', 'long', 'marathon']; let html = ''; return html; } /** * Build checkboxes for category * @param {string} category - Category name * @param {Object} prefs - Preferences object * @returns {string} HTML */ buildCheckboxes(category, prefs) { let html = '
'; for (const [key, value] of Object.entries(prefs)) { if (value !== null) { // Skip undiscovered features html += ` `; } } html += '
'; return html; } /** * Populate library manager */ populateLibraryManager() { const container = document.getElementById('library-manager'); if (!container) return; // Sync with existing library first const syncResult = window.libraryManager.syncWithExistingLibrary(); const stats = window.libraryManager.getLibraryStats(); container.innerHTML = `

📊 Library Statistics

Total Videos ${stats.totalItems}
Tagged ${stats.taggedItems}
Avg Rating ${stats.averageRating}⭐
Favorites ${stats.totalFavorites}

💡 Your existing video library (${syncResult.total} videos) is automatically imported. You can add tags and ratings to organize your content.

📚 Manage your full library from the main menu Library tab for more detailed controls.

`; } /** * Save checkpoint preferences and start level * @param {number} levelNum - Level to start */ saveCheckpointAndStart(levelNum) { console.log('💾 Saving checkpoint preferences...'); // Collect all preference changes const updates = {}; // Get all checkboxes document.querySelectorAll('input[type="checkbox"][data-category]').forEach(checkbox => { const category = checkbox.dataset.category; const key = checkbox.dataset.key; if (!updates[category]) updates[category] = {}; updates[category][key] = checkbox.checked; }); // Get all sliders document.querySelectorAll('input[type="range"][data-category]').forEach(slider => { const category = slider.dataset.category; const key = slider.dataset.key; if (!updates[category]) updates[category] = {}; updates[category][key] = parseInt(slider.value); }); // Get all selects document.querySelectorAll('select[data-category]').forEach(select => { const category = select.dataset.category; const key = select.dataset.key; if (!updates[category]) updates[category] = {}; updates[category][key] = select.value; }); // Save to preferenceManager let saved = true; if (Object.keys(updates).length > 0) { saved = window.preferenceManager.updateMultipleCategories(updates, levelNum); if (saved) { console.log('✅ Preferences updated:', updates); } else { console.error('❌ Failed to save preferences'); alert('⚠️ Unable to save preferences. Storage may be full.\n\nPlease restart the app and try again.'); return; } } // Close modal and begin level this.closeCheckpointModal(); this.beginLevel(levelNum); } /** * Close checkpoint modal */ closeCheckpointModal() { if (this.currentModal) { this.currentModal.remove(); this.currentModal = null; } } /** * Begin level (after checkpoint or directly) * @param {number} levelNum - Level to start */ beginLevel(levelNum) { console.log(`🚀 Beginning Level ${levelNum}...`); // Use campaignManager to start level const levelConfig = window.campaignManager.startLevel(levelNum); if (!levelConfig) { alert('Unable to start this level. Please check requirements.'); return; } // Hide level select screen const setupContainer = document.getElementById('academy-setup'); if (setupContainer) { setupContainer.style.display = 'none'; } // Start the actual training session // This would integrate with existing training-academy.html session logic this.startTrainingSession(levelConfig); } /** * Start training session with level config * @param {Object} levelConfig - Level configuration */ startTrainingSession(levelConfig) { console.log('🎓 Starting training session with config:', levelConfig); // Get detailed level configuration from academyLevelData const detailedConfig = window.academyLevelData.getLevelConfig(levelConfig.levelNumber); if (!detailedConfig) { console.error('⚠️ No level data found for level:', levelConfig.levelNumber); return; } console.log('📊 Detailed level config:', detailedConfig); // Get content filter based on user preferences const preferenceFilter = window.preferenceManager.getContentFilter(); // Sync with existing library to ensure we have latest videos window.libraryManager.syncWithExistingLibrary(); // Get media requirements for this level const mediaRequirements = window.academyLevelData.getMediaForLevel( levelConfig.levelNumber, window.preferenceManager.getPreferences() ); console.log('🎬 Media requirements:', mediaRequirements); // Get filtered media from library let mediaItems = window.libraryManager.getMediaForPreferences( mediaRequirements.videoFilter, mediaRequirements.videoCount ); // Fallback to all videos if no matches if (mediaItems.length === 0) { console.warn('⚠️ No media items matched preferences. Using all available videos.'); mediaItems = window.libraryManager.getAllVideosWithMetadata(); } console.log('🎬 Loaded media for session:', mediaItems.length, 'items'); console.log('🎯 Preference filter:', preferenceFilter); console.log('⏱️ Session duration:', detailedConfig.session.duration); console.log('📋 Tasks:', detailedConfig.tasks.length); console.log('🎯 Objectives:', detailedConfig.objectives); // Sync videos to videoPlayerManager for video playback if (window.videoPlayerManager && mediaItems.length > 0) { const videoPaths = mediaItems.map(item => item.path || item.fullPath); window.videoPlayerManager.videoLibrary.background = videoPaths; window.videoPlayerManager.videoLibrary.task = videoPaths; window.videoPlayerManager.videoLibrary.reward = videoPaths; window.videoPlayerManager.videoLibrary.punishment = videoPaths; console.log(`🔄 Synced ${videoPaths.length} videos to videoPlayerManager for Level ${levelConfig.levelNumber}`); } // Update trainingVideoLibrary global for training-academy.html if (mediaItems.length > 0) { window.trainingVideoLibrary = mediaItems; console.log(`📹 Set trainingVideoLibrary with ${mediaItems.length} videos`); } // Enable video if this level requires it (has video media requirements) if (detailedConfig.media && detailedConfig.media.videos && detailedConfig.media.videos.required > 0) { // Load and update settings to enable video const settings = typeof window.loadAcademySettings === 'function' ? window.loadAcademySettings() : { enableVideo: false }; if (!settings.enableVideo) { console.log('🎬 Level requires video - enabling video in settings'); settings.enableVideo = true; if (typeof window.saveAcademySettings === 'function') { window.saveAcademySettings(settings); } } } // Set the selected training mode to trigger proper training flow window.selectedTrainingMode = 'training-academy'; // Store current level info globally for access during session window.currentAcademyLevel = { levelNumber: levelConfig.levelNumber, config: detailedConfig, mediaRequirements: mediaRequirements }; // Call the existing training session starter if (typeof window.startTrainingSession === 'function') { window.startTrainingSession(); } else { console.error('⚠️ startTrainingSession() not found in window scope'); } } } // Create global instance window.academyUI = new AcademyUI();