'use client'; import { useState, useEffect } from 'react'; import { MainLayout } from '@/components/layout/main-layout'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Progress } from '@/components/ui/progress'; import { BookOpen, Users, Calendar, Clock, TrendingUp, Search, Filter, CheckCircle, XCircle, AlertCircle, User, GraduationCap } from 'lucide-react'; import { toast } from 'sonner'; import { LoadingSpinner } from '@/components/ui/spinner'; interface Teacher { id: string; firstName: string; lastName: string; email: string; } interface Period { id: string; name: string; startDate: string; endDate: string; isActive: boolean; } interface Class { id: string; name: string; code: string; description: string | null; period: Period; } interface Section { id: string; name: string; studentCount: number; class: Class; teachers: Teacher[]; } interface AttendanceStats { totalRecords: number; present: number; absent: number; justified: number; attendanceRate: number; } interface EnrolledClass { id: string; enrolledAt: string; section: Section; attendanceStats: AttendanceStats; } interface Student { id: string; firstName: string; lastName: string; admissionNumber: string; } interface ClassesResponse { classes: EnrolledClass[]; student: Student; } export default function StudentClassesPage() { const [classes, setClasses] = useState([]); const [student, setStudent] = useState(null); const [loading, setLoading] = useState(true); const [searchTerm, setSearchTerm] = useState(''); const [selectedPeriod, setSelectedPeriod] = useState('all'); const [selectedStatus, setSelectedStatus] = useState('all'); useEffect(() => { fetchClasses(); }, []); const fetchClasses = async () => { try { setLoading(true); const response = await fetch('/api/student/classes'); if (!response.ok) { throw new Error('Error al cargar las clases'); } const data: ClassesResponse = await response.json(); setClasses(data.classes); setStudent(data.student); } catch (error) { console.error('Error:', error); toast.error('Error al cargar las clases matriculadas'); } finally { setLoading(false); } }; const filteredClasses = classes.filter(enrolledClass => { const matchesSearch = enrolledClass.section.class.name.toLowerCase().includes(searchTerm.toLowerCase()) || enrolledClass.section.class.code.toLowerCase().includes(searchTerm.toLowerCase()) || enrolledClass.section.name.toLowerCase().includes(searchTerm.toLowerCase()) || enrolledClass.section.class.period.name.toLowerCase().includes(searchTerm.toLowerCase()); const matchesPeriod = selectedPeriod === 'all' || enrolledClass.section.class.period.id === selectedPeriod; const matchesStatus = selectedStatus === 'all' || (selectedStatus === 'active' && enrolledClass.section.class.period.isActive) || (selectedStatus === 'inactive' && !enrolledClass.section.class.period.isActive); return matchesSearch && matchesPeriod && matchesStatus; }); const periods = Array.from(new Set(classes.map(c => c.section.class.period))) .filter((period, index, self) => self.findIndex(p => p.id === period.id) === index); const activeClasses = filteredClasses.filter(c => c.section.class.period.isActive); const totalAttendanceRecords = filteredClasses.reduce((sum, c) => sum + c.attendanceStats.totalRecords, 0); const averageAttendanceRate = filteredClasses.length > 0 ? Math.round(filteredClasses.reduce((sum, c) => sum + c.attendanceStats.attendanceRate, 0) / filteredClasses.length) : 0; const getAttendanceColor = (rate: number) => { if (rate >= 90) return 'text-green-600'; if (rate >= 75) return 'text-yellow-600'; return 'text-red-600'; }; const getAttendanceBadgeVariant = (rate: number): 'default' | 'secondary' | 'destructive' => { if (rate >= 90) return 'default'; if (rate >= 75) return 'secondary'; return 'destructive'; }; const formatDate = (dateString: string) => { return new Date(dateString).toLocaleDateString('es-ES', { year: 'numeric', month: 'long', day: 'numeric' }); }; const getTeacherNames = (teachers: Teacher[]) => { return teachers.map(teacher => `${teacher.firstName} ${teacher.lastName}`).join(', '); }; if (loading) { return (
); } return (
{/* Header */}

Mis Clases Matriculadas

{student && `${student.firstName} ${student.lastName} - ${student.admissionNumber}`}

{/* Estadísticas Generales */}
Total de Clases
{filteredClasses.length}

{activeClasses.length} activas

Registros de Asistencia
{totalAttendanceRecords}

Total acumulado

Asistencia Promedio
{averageAttendanceRate}%

Todas las clases

Períodos Únicos
{periods.length}

Histórico

{/* Filtros */} Filtros
setSearchTerm(e.target.value)} className="pl-10" />
{/* Lista de Clases */}
{filteredClasses.length > 0 ? ( filteredClasses.map((enrolledClass) => (
{enrolledClass.section.class.name} {enrolledClass.section.class.code} - {enrolledClass.section.name}
{enrolledClass.section.class.period.name}
{/* Información de la clase */}
{enrolledClass.section.class.description && (

{enrolledClass.section.class.description}

)}
{enrolledClass.section.studentCount} estudiantes
{getTeacherNames(enrolledClass.section.teachers) || 'Sin profesor asignado'}
Matriculado: {formatDate(enrolledClass.enrolledAt)}
Período: {formatDate(enrolledClass.section.class.period.startDate)} - {formatDate(enrolledClass.section.class.period.endDate)}
{/* Estadísticas de Asistencia */}

Asistencia

{enrolledClass.attendanceStats.attendanceRate}%
{enrolledClass.attendanceStats.present}
Presente
{enrolledClass.attendanceStats.absent}
Ausente
{enrolledClass.attendanceStats.justified}
Justificado
{enrolledClass.attendanceStats.totalRecords}
Total
)) ) : (

No se encontraron clases

{searchTerm || selectedPeriod !== 'all' || selectedStatus !== 'all' ? 'No hay clases que coincidan con los filtros aplicados.' : 'No tienes clases matriculadas en este momento.'}

{(searchTerm || selectedPeriod !== 'all' || selectedStatus !== 'all') && ( )}
)}
); }