'use client' import { useState, useEffect } from 'react' import { DashboardLayout } from '@/components/dashboard-layout' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' 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 { Badge } from '@/components/ui/badge' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table' import { Calendar, Users, Clock, UserX, UserCheck } from 'lucide-react' import { toast } from 'sonner' import { Spinner } from '@/components/ui/spinner' interface Section { id: string name: string className: string periodName: string studentCount: number isActive: boolean } interface AttendanceRecord { id: string student: { id: string name: string email: string } status: 'present' | 'absent' | 'late' reason?: string partial: { id: string name: string } | null } interface DayHistory { date: string records: AttendanceRecord[] summary: { total: number present: number absent: number late: number } } export default function AttendanceHistoryPage() { const [sections, setSections] = useState([]) const [history, setHistory] = useState([]) const [selectedSection, setSelectedSection] = useState('') const [startDate, setStartDate] = useState('') const [endDate, setEndDate] = useState('') const [loading, setLoading] = useState(false) useEffect(() => { fetchSections() // Set default date range (last 30 days) const today = new Date() const thirtyDaysAgo = new Date(today.getTime() - 30 * 24 * 60 * 60 * 1000) // Format dates in local timezone to avoid offset issues const formatLocalDate = (date: Date) => { const year = date.getFullYear() const month = String(date.getMonth() + 1).padStart(2, '0') const day = String(date.getDate()).padStart(2, '0') return `${year}-${month}-${day}` } setEndDate(formatLocalDate(today)) setStartDate(formatLocalDate(thirtyDaysAgo)) }, []) const fetchSections = async () => { try { const response = await fetch('/api/teacher/sections') if (response.ok) { const data = await response.json() setSections(data.filter((s: Section) => s.isActive)) } } catch (error) { toast.error('Error al cargar las secciones') } } const fetchHistory = async () => { if (!selectedSection) { toast.error('Selecciona una sección') return } setLoading(true) try { const params = new URLSearchParams({ sectionId: selectedSection, ...(startDate && { startDate }), ...(endDate && { endDate }) }) const response = await fetch(`/api/teacher/attendance-history?${params}`) if (response.ok) { const data = await response.json() setHistory(data) } else { toast.error('Error al cargar el historial') } } catch (error) { toast.error('Error al cargar el historial') } finally { setLoading(false) } } const getStatusIcon = (status: string) => { switch (status) { case 'present': return case 'late': return case 'absent': return default: return null } } const getStatusBadge = (status: string) => { switch (status) { case 'present': return Presente case 'late': return Tardanza case 'absent': return Ausente default: return null } } const formatDate = (dateString: string) => { // Evitar offset de timezone usando la fecha directamente const [year, month, day] = dateString.split('-') const monthNames = [ 'enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', 'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre' ] const dayNames = [ 'domingo', 'lunes', 'martes', 'miércoles', 'jueves', 'viernes', 'sábado' ] // Crear fecha en zona local para obtener el día de la semana const localDate = new Date(parseInt(year), parseInt(month) - 1, parseInt(day)) const dayOfWeek = dayNames[localDate.getDay()] return `${dayOfWeek}, ${parseInt(day)} de ${monthNames[parseInt(month) - 1]} de ${year}` } const breadcrumbs = [ { label: 'Dashboard', href: '/teacher' }, { label: 'Historial de Asistencia', href: '/teacher/attendance-history' } ] return (

Historial de Asistencia

{/* Filtros */} Filtros
setStartDate(e.target.value)} className="w-full" />
setEndDate(e.target.value)} className="w-full" />
{/* Resumen General */} {history.length > 0 && ( Resumen del Período
{history.reduce((acc, day) => acc + day.summary.total, 0)}
Total Registros
{history.reduce((acc, day) => acc + day.summary.present, 0)}
Presentes
{history.reduce((acc, day) => acc + day.summary.late, 0)}
Tardanzas
{history.reduce((acc, day) => acc + day.summary.absent, 0)}
Ausentes
)} {/* Tabla de Historial */} {history.length > 0 ? ( Historial de Asistencia Fecha Estudiante Estado Parcial Razón {history.map((day) => day.records.map((record) => ( {day.date.split('-').reverse().join('/')}
{record.student.name}
{record.student.email}
{getStatusIcon(record.status)} {getStatusBadge(record.status)}
{record.partial ? ( {record.partial.name} ) : ( - )} {record.reason ? ( {record.reason} ) : ( - )}
)) )}
) : ( !loading && selectedSection && (

No se encontraron registros de asistencia para el período seleccionado.

) )} {!selectedSection && (

Selecciona una sección para ver el historial de asistencia.

)}
) }