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
text/typescript
/**
* @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;