/** * CourseProgressTracker Component * Comprehensive progress visualization at the course level * OQI-002: Modulo Educativo */ import React, { useMemo } from 'react'; import { BookOpen, CheckCircle, Circle, Clock, Play, Lock, Trophy, Target, TrendingUp, Download, ChevronRight, Zap, Calendar, } from 'lucide-react'; export interface ModuleProgress { id: string; title: string; lessonsTotal: number; lessonsCompleted: number; quizScore?: number; quizPassed?: boolean; timeSpentMinutes: number; estimatedMinutes: number; status: 'locked' | 'available' | 'in_progress' | 'completed'; order: number; } export interface CourseProgressData { courseId: string; courseTitle: string; totalLessons: number; completedLessons: number; totalQuizzes: number; passedQuizzes: number; overallProgress: number; xpEarned: number; xpTotal: number; timeSpentMinutes: number; estimatedTotalMinutes: number; startedAt?: string; lastAccessedAt?: string; modules: ModuleProgress[]; } interface CourseProgressTrackerProps { progress: CourseProgressData; onModuleClick?: (moduleId: string) => void; onDownloadReport?: () => void; compact?: boolean; } const CourseProgressTracker: React.FC = ({ progress, onModuleClick, onDownloadReport, compact = false, }) => { const sortedModules = useMemo(() => { return [...progress.modules].sort((a, b) => a.order - b.order); }, [progress.modules]); const completedModules = progress.modules.filter(m => m.status === 'completed').length; const totalModules = progress.modules.length; const formatTime = (minutes: number) => { if (minutes < 60) return `${minutes}m`; const hours = Math.floor(minutes / 60); const mins = minutes % 60; return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`; }; const formatDate = (dateString: string) => { return new Date(dateString).toLocaleDateString('es-ES', { day: 'numeric', month: 'short', year: 'numeric', }); }; const getStatusIcon = (status: ModuleProgress['status']) => { switch (status) { case 'completed': return ; case 'in_progress': return ; case 'locked': return ; default: return ; } }; const getStatusBg = (status: ModuleProgress['status']) => { switch (status) { case 'completed': return 'bg-green-500/10 border-green-500/30'; case 'in_progress': return 'bg-blue-500/10 border-blue-500/30'; case 'locked': return 'bg-gray-800/50 border-gray-700 opacity-60'; default: return 'bg-gray-800/50 border-gray-700'; } }; const estimatedCompletion = useMemo(() => { const remainingMinutes = progress.estimatedTotalMinutes - progress.timeSpentMinutes; if (remainingMinutes <= 0) return 'Completable ahora'; const days = Math.ceil(remainingMinutes / 60 / 2); // Assuming 2 hours/day return `~${days} ${days === 1 ? 'dia' : 'dias'} restantes`; }, [progress]); return (
{/* Header */}

Progreso del Curso

{progress.courseTitle}

{onDownloadReport && ( )}
{/* Overall Progress Bar */}
Progreso General {progress.overallProgress}%
{/* Stats Grid */}
{progress.completedLessons}/{progress.totalLessons}
Lecciones
{progress.passedQuizzes}/{progress.totalQuizzes}
Quizzes
{formatTime(progress.timeSpentMinutes)}
Tiempo
{progress.xpEarned}
XP
{/* Timeline Info */} {(progress.startedAt || progress.lastAccessedAt) && (
{progress.startedAt && ( Iniciado: {formatDate(progress.startedAt)} )}
{estimatedCompletion}
)} {/* Module List */}
Modulos ({completedModules}/{totalModules})
{sortedModules.map((module, index) => { const moduleProgress = module.lessonsTotal > 0 ? Math.round((module.lessonsCompleted / module.lessonsTotal) * 100) : 0; return (
module.status !== 'locked' && onModuleClick?.(module.id)} className={`p-3 rounded-lg border transition-all ${getStatusBg(module.status)} ${ module.status !== 'locked' ? 'cursor-pointer hover:border-gray-600' : '' }`} >
{/* Status Icon */}
{getStatusIcon(module.status)}
{/* Content */}
{index + 1}. {module.title} {module.status !== 'locked' && ( )}
{/* Progress Bar */} {module.status !== 'locked' && (
{module.lessonsCompleted}/{module.lessonsTotal} lecciones {moduleProgress}%
)} {/* Quiz Badge */} {module.quizScore !== undefined && (
Quiz: {module.quizScore}% {formatTime(module.timeSpentMinutes)} / {formatTime(module.estimatedMinutes)}
)}
); })}
{/* Completion Message */} {progress.overallProgress === 100 && (

Curso Completado!

Has ganado {progress.xpEarned} XP

)}
); }; export default CourseProgressTracker;