UNPKG

mcp-quiz-server

Version:

🧠 AI-Powered Quiz Management via Model Context Protocol (MCP) - Create, manage, and take quizzes directly from VS Code, Claude, and other AI agents.

258 lines (220 loc) 8.63 kB
/** * @fileoverview Main application entry point * @version 2.1.0 * @requirementsTraceability {@link Requirements.REQ_ARCH_001} - Main application initialization and component orchestration * @requirementsTraceability {@link Requirements.REQ_ARCH_002} - Service layer integration and dependency management * @requirementsTraceability {@link Requirements.REQ_UI_001} - Application UI initialization and component mounting * @requirementsTraceability {@link Requirements.REQ_UI_002} - Tour system integration for user onboarding */ import { AuthManager } from './components/AuthManager'; import { Dashboard } from './components/Dashboard'; import { QuizContent } from './components/quiz/QuizContent'; import { QuizList } from './components/QuizList'; import { ResultsModal } from './components/ResultsModal'; import { SettingsMenu } from './components/SettingsMenu'; import { SidebarToggle } from './components/SidebarToggle'; import { ThemeSelector } from './components/ThemeSelector'; import { TourModal } from './components/TourModal'; import { SettingsService } from './services/SettingsService'; import { ThemeService } from './services/ThemeService'; import { TimerService } from './services/TimerService'; import { TourService } from './services/TourService'; import { AppStore } from './store/AppStore'; import { DOMUtils } from './utils/index'; class QuizApp { private store: AppStore; private themeService: ThemeService; private settingsService: SettingsService; private timerService: TimerService; private tourService: TourService; private components: { authManager: AuthManager; dashboard?: Dashboard; quizList: QuizList; quizContent: QuizContent; themeSelector: ThemeSelector; resultsModal: ResultsModal; settingsMenu: SettingsMenu; sidebarToggle: SidebarToggle; tourModal: TourModal; }; constructor() { this.store = AppStore.getInstance(); this.themeService = ThemeService.getInstance(); this.settingsService = SettingsService.getInstance(); this.timerService = TimerService.getInstance(); this.tourService = TourService.getInstance(); this.components = { authManager: AuthManager.getInstance(), quizList: new QuizList(), quizContent: new QuizContent(), themeSelector: new ThemeSelector(), resultsModal: new ResultsModal(), settingsMenu: new SettingsMenu(), sidebarToggle: new SidebarToggle(), tourModal: new TourModal(), }; } async initialize(): Promise<void> { try { // Initialize theme first this.themeService.initialize(); // Mount all components Object.values(this.components).forEach(component => { component.mount(); }); // Load initial data await this.store.loadQuizzes(); // Initialize tour system (after components are mounted) this.initializeTourSystem(); // Set up global error handling this.setupErrorHandling(); console.log('✅ Quiz Platform initialized successfully'); } catch (error) { console.error('❌ Failed to initialize Quiz Platform:', error); DOMUtils.showToast('Failed to initialize application', 'error'); } } /** * @description Initializes the tour system and shows welcome tour for first-time users */ private initializeTourSystem(): void { try { // Add tour trigger attributes to elements for targeting this.addTourAttributes(); // Check if user should see welcome tour if (this.tourService.shouldShowWelcomeTour()) { // Delay tour start slightly to ensure all components are fully rendered setTimeout(() => { console.log('🎯 Starting welcome tour for first-time user'); this.tourService.startTour('welcome'); }, 1500); } // Add tour trigger to settings menu this.addTourTriggers(); console.log('✨ Tour system initialized successfully'); } catch (error) { console.error('❌ Failed to initialize tour system:', error); } } /** * @description Adds tour-specific data attributes to elements for targeting */ private addTourAttributes(): void { // Add tour attributes to key elements const settingsBtn = document.querySelector('#settings-btn, [data-settings-trigger]'); if (settingsBtn) { settingsBtn.setAttribute('data-tour', 'settings-button'); } const timerToggle = document.querySelector('#timer-toggle'); if (timerToggle) { timerToggle.setAttribute('data-tour', 'timer-toggle'); } const viewToggle = document.querySelector('#view-mode-toggle, [data-view-toggle]'); if (viewToggle) { viewToggle.setAttribute('data-tour', 'view-toggle'); } const navButtons = document.querySelector('.nav-buttons, #navigation-buttons'); if (navButtons) { navButtons.setAttribute('data-tour', 'navigation-buttons'); } } /** * @description Adds tour trigger buttons to UI */ private addTourTriggers(): void { // Add "Help & Tour" option to settings menu const settingsMenu = document.querySelector('#settings-dropdown'); if (settingsMenu) { const tourButton = document.createElement('button'); tourButton.className = 'tour-trigger-btn w-full text-left px-4 py-2 text-sm text-surface-700 dark:text-surface-300 hover:bg-surface-100 dark:hover:bg-surface-600 flex items-center gap-2'; tourButton.innerHTML = ` <i data-lucide="help-circle" class="w-4 h-4"></i> <span>Take Tour</span> `; tourButton.addEventListener('click', () => { console.log('🎯 User requested tour'); this.tourService.startTour('welcome'); }); // Insert before the last item (usually theme selector) const lastItem = settingsMenu.querySelector(':scope > :last-child'); if (lastItem) { settingsMenu.insertBefore(tourButton, lastItem); } else { settingsMenu.appendChild(tourButton); } // Re-initialize Lucide icons for the new button if (typeof (window as any).lucide !== 'undefined') { (window as any).lucide.createIcons(); } } } private setupErrorHandling(): void { window.addEventListener('error', event => { console.error('Global error:', event.error); DOMUtils.showToast('An unexpected error occurred', 'error'); }); window.addEventListener('unhandledrejection', event => { console.error('Unhandled promise rejection:', event.reason); DOMUtils.showToast('An unexpected error occurred', 'error'); }); } // Getter methods for debugging and external access getSettingsService(): SettingsService { return this.settingsService; } getStore(): AppStore { return this.store; } getComponents() { return this.components; } destroy(): void { Object.values(this.components).forEach(component => { component?.unmount(); }); } } /** * Initialize dashboard application * * @description Specialized initialization for dashboard page * * @returns {Promise<void>} * * @since 2025-08-04 * @author Claude Code Agent */ export async function initializeDashboard(): Promise<void> { try { console.log('🚀 Initializing Dashboard Application...'); // Initialize core services const store = AppStore.getInstance(); const themeService = ThemeService.getInstance(); const settingsService = SettingsService.getInstance(); // Apply saved theme await themeService.initialize(); // Initialize dashboard component const dashboard = new Dashboard(); await dashboard.mount(); console.log('✅ Dashboard Application initialized successfully'); // Make available globally for debugging (window as any).__dashboard = dashboard; (window as any).__store = store; } catch (error) { console.error('❌ Dashboard initialization failed:', error); throw error; } } // Initialize the standard quiz application when DOM is ready document.addEventListener('DOMContentLoaded', async () => { // Only initialize standard app if not on dashboard page if (!window.location.pathname.includes('/dashboard')) { const app = new QuizApp(); await app.initialize(); // Make app available globally for debugging (window as any).__quizApp = app; } }); export default QuizApp;