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