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.

419 lines (388 loc) • 11.2 kB
/** * @fileoverview Dashboard Service - API Communication Layer * @version 1.0.0 * @since 2025-08-04 * @lastUpdated 2025-08-04 * @module DashboardService * @description Service for dashboard-related API operations and data management * @contributors Claude Code Agent * @dependencies ApiClient, AuthService * @requirements REQ-API-003 (Dashboard API integration) * @testCoverage API calls, error handling, data transformation */ import { ApiClient } from './ApiClient'; import { AuthService } from './AuthService'; /** * Dashboard Service * * @description Handles all dashboard-related API communications and data operations. * Provides centralized interface for dashboard data management. * * @example * ```typescript * const dashboardService = new DashboardService(); * const data = await dashboardService.getDashboardData(); * ``` * * @since 2025-08-04 * @author Claude Code Agent * @requirements REQ-API-003 (Dashboard API), REQ-AUTH-002 (Authenticated requests) */ export class DashboardService { private apiClient: ApiClient; private authService: AuthService; constructor() { this.apiClient = ApiClient.getInstance(); this.authService = AuthService.getInstance(); } /** * Get comprehensive dashboard data * * @description Fetches all dashboard data in a single request * * @returns {Promise<DashboardData>} Complete dashboard data * * @since 2025-08-04 * @author Claude Code Agent */ async getDashboardData(): Promise<DashboardData> { try { // Parallel requests for better performance const [userInfo, stats, recentQuizzes, recentActivity] = await Promise.all([ this.getUserInfo(), this.getDashboardStats(), this.getRecentQuizzes(), this.getRecentActivity(), ]); return { user: userInfo, stats, recentQuizzes, recentActivity, lastUpdated: new Date().toISOString(), }; } catch (error) { console.error('Failed to load dashboard data:', error); throw new Error('Unable to load dashboard. Please try again.'); } } /** * Get current user information * * @description Fetches current user profile and permissions * * @returns {Promise<UserInfo>} User information * * @since 2025-08-04 * @author Claude Code Agent */ async getUserInfo(): Promise<UserInfo> { try { const response = await this.apiClient.get('/dashboard/api/user'); return response.data; } catch (error) { console.error('Failed to load user info:', error); throw new Error('Unable to load user information'); } } /** * Get dashboard statistics * * @description Fetches user statistics and metrics * * @returns {Promise<DashboardStats>} Dashboard statistics * * @since 2025-08-04 * @author Claude Code Agent */ async getDashboardStats(): Promise<DashboardStats> { try { const response = await this.apiClient.get('/dashboard/api/stats'); return response.data; } catch (error) { console.error('Failed to load dashboard stats:', error); // Return default stats on error return { totalQuizzes: 0, totalResponses: 0, recentActivity: 0, completionRate: 0, }; } } /** * Get recent quizzes * * @description Fetches user's recent quizzes with limit * * @param {number} limit - Maximum number of quizzes to fetch * @returns {Promise<Quiz[]>} Array of recent quizzes * * @since 2025-08-04 * @author Claude Code Agent */ async getRecentQuizzes(limit: number = 5): Promise<Quiz[]> { try { const response = await this.apiClient.get( `/dashboard/api/quizzes?limit=${limit}&sort=recent` ); return response.data.quizzes || []; } catch (error) { console.error('Failed to load recent quizzes:', error); return []; } } /** * Get recent activity * * @description Fetches user's recent activity feed * * @param {number} limit - Maximum number of activities to fetch * @returns {Promise<Activity[]>} Array of recent activities * * @since 2025-08-04 * @author Claude Code Agent */ async getRecentActivity(limit: number = 10): Promise<Activity[]> { try { const response = await this.apiClient.get(`/dashboard/api/activity?limit=${limit}`); return response.data.activities || []; } catch (error) { console.error('Failed to load recent activity:', error); return []; } } /** * Get user's quiz analytics * * @description Fetches detailed analytics for user's quizzes * * @param {string} timeRange - Time range for analytics ('7d', '30d', '90d', 'all') * @returns {Promise<QuizAnalytics>} Quiz analytics data * * @since 2025-08-04 * @author Claude Code Agent */ async getQuizAnalytics(timeRange: string = '30d'): Promise<QuizAnalytics> { try { const response = await this.apiClient.get(`/dashboard/api/analytics?timeRange=${timeRange}`); return response.data; } catch (error) { console.error('Failed to load quiz analytics:', error); throw new Error('Unable to load analytics data'); } } /** * Update user profile * * @description Updates user profile information * * @param {Partial<UserProfile>} profileData - Profile data to update * @returns {Promise<UserInfo>} Updated user information * * @since 2025-08-04 * @author Claude Code Agent */ async updateProfile(profileData: Partial<UserProfile>): Promise<UserInfo> { try { const response = await this.apiClient.put('/dashboard/api/user/profile', profileData); return response.data; } catch (error) { console.error('Failed to update profile:', error); throw new Error('Unable to update profile. Please try again.'); } } /** * Create new quiz * * @description Creates a new quiz with basic information * * @param {CreateQuizData} quizData - Quiz creation data * @returns {Promise<Quiz>} Created quiz * * @since 2025-08-04 * @author Claude Code Agent */ async createQuiz(quizData: CreateQuizData): Promise<Quiz> { try { const response = await this.apiClient.post('/quiz', quizData); return response.data; } catch (error) { console.error('Failed to create quiz:', error); throw new Error('Unable to create quiz. Please try again.'); } } /** * Delete quiz * * @description Deletes a quiz by ID * * @param {string} quizId - Quiz ID to delete * @returns {Promise<void>} * * @since 2025-08-04 * @author Claude Code Agent */ async deleteQuiz(quizId: string): Promise<void> { try { await this.apiClient.delete(`/quiz/${quizId}`); } catch (error) { console.error('Failed to delete quiz:', error); throw new Error('Unable to delete quiz. Please try again.'); } } /** * Get quiz by ID * * @description Fetches detailed quiz information * * @param {string} quizId - Quiz ID to fetch * @returns {Promise<QuizDetail>} Detailed quiz information * * @since 2025-08-04 * @author Claude Code Agent */ async getQuiz(quizId: string): Promise<QuizDetail> { try { const response = await this.apiClient.get(`/quiz/${quizId}`); return response.data; } catch (error) { console.error('Failed to load quiz:', error); throw new Error('Unable to load quiz details'); } } /** * Search quizzes * * @description Searches user's quizzes with filters * * @param {QuizSearchParams} params - Search parameters * @returns {Promise<QuizSearchResult>} Search results * * @since 2025-08-04 * @author Claude Code Agent */ async searchQuizzes(params: QuizSearchParams): Promise<QuizSearchResult> { try { const queryString = new URLSearchParams(params as any).toString(); const response = await this.apiClient.get(`/dashboard/api/quizzes/search?${queryString}`); return response.data; } catch (error) { console.error('Failed to search quizzes:', error); throw new Error('Search failed. Please try again.'); } } } /** * Type Definitions */ export interface DashboardData { user: UserInfo; stats: DashboardStats; recentQuizzes: Quiz[]; recentActivity: Activity[]; lastUpdated: string; } export interface UserInfo { id: string; username: string; email?: string; firstName?: string; lastName?: string; roles: string[]; permissions: string[]; isActive: boolean; createdAt: string; lastLoginAt?: string; } export interface DashboardStats { totalQuizzes: number; totalResponses: number; recentActivity: number; completionRate: number; } export interface Quiz { id: string; title: string; description?: string; status: 'draft' | 'published' | 'archived'; questions?: QuizQuestion[]; createdAt: string; updatedAt: string; createdBy: string; } export interface QuizDetail extends Quiz { questions: QuizQuestion[]; analytics?: QuizAnalytics; responses?: QuizResponse[]; } export interface QuizQuestion { id: string; question: string; options: string[]; answer: string; explanation?: string; } export interface Activity { id: string; type: 'quiz_created' | 'quiz_updated' | 'quiz_published' | 'response_received'; title: string; description: string; timestamp: string; relatedId?: string; } export interface QuizAnalytics { totalResponses: number; averageScore: number; completionRate: number; responsesByDay: { date: string; count: number }[]; questionAnalytics: QuestionAnalytics[]; } export interface QuestionAnalytics { questionId: string; correctAnswers: number; totalAnswers: number; accuracy: number; } export interface UserProfile { firstName?: string; lastName?: string; email?: string; bio?: string; preferences?: { theme: 'light' | 'dark' | 'system'; notifications: boolean; language: string; }; } export interface CreateQuizData { title: string; description?: string; questions: Omit<QuizQuestion, 'id'>[]; metadata?: { category?: string; difficulty?: 'easy' | 'medium' | 'hard'; tags?: string[]; }; } export interface QuizSearchParams { query?: string; status?: 'draft' | 'published' | 'archived'; category?: string; sortBy?: 'title' | 'createdAt' | 'updatedAt'; sortOrder?: 'asc' | 'desc'; limit?: number; offset?: number; } export interface QuizSearchResult { quizzes: Quiz[]; total: number; hasMore: boolean; } export interface QuizResponse { id: string; userId?: string; answers: { questionId: string; answer: string }[]; score: number; completedAt: string; }