|
|
@@ -1,91 +1,116 @@
|
|
|
'use client'
|
|
|
|
|
|
+import { useEffect, useState } from 'react'
|
|
|
import { MainLayout } from '@/components/layout/main-layout'
|
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
|
|
-import { BookOpen, Users, Calendar, ClipboardList, Clock, CheckCircle } from 'lucide-react'
|
|
|
+import { BookOpen, Users, Calendar, ClipboardList, Clock, CheckCircle, Loader2 } from 'lucide-react'
|
|
|
+import { TeacherDashboardData } from '@/types/teacher'
|
|
|
|
|
|
-const stats = [
|
|
|
- {
|
|
|
- title: 'Mis Clases',
|
|
|
- value: '3',
|
|
|
- description: 'Clases asignadas',
|
|
|
- icon: BookOpen,
|
|
|
- color: 'text-blue-600',
|
|
|
- bgColor: 'bg-blue-100'
|
|
|
- },
|
|
|
- {
|
|
|
- title: 'Estudiantes',
|
|
|
- value: '15',
|
|
|
- description: 'Total de estudiantes',
|
|
|
- icon: Users,
|
|
|
- color: 'text-green-600',
|
|
|
- bgColor: 'bg-green-100'
|
|
|
- },
|
|
|
- {
|
|
|
- title: 'Clases Hoy',
|
|
|
- value: '2',
|
|
|
- description: 'Clases programadas',
|
|
|
- icon: Calendar,
|
|
|
- color: 'text-purple-600',
|
|
|
- bgColor: 'bg-purple-100'
|
|
|
- },
|
|
|
- {
|
|
|
- title: 'Asistencia Promedio',
|
|
|
- value: '85%',
|
|
|
- description: 'Este mes',
|
|
|
- icon: CheckCircle,
|
|
|
- color: 'text-orange-600',
|
|
|
- bgColor: 'bg-orange-100'
|
|
|
+export default function TeacherDashboard() {
|
|
|
+ const [dashboardData, setDashboardData] = useState<TeacherDashboardData | null>(null)
|
|
|
+ const [loading, setLoading] = useState(true)
|
|
|
+ const [error, setError] = useState<string | null>(null)
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ const fetchDashboardData = async () => {
|
|
|
+ try {
|
|
|
+ const response = await fetch('/api/teacher/dashboard')
|
|
|
+ if (!response.ok) {
|
|
|
+ throw new Error('Error al cargar los datos del dashboard')
|
|
|
+ }
|
|
|
+ const data = await response.json()
|
|
|
+ setDashboardData(data)
|
|
|
+ } catch (err) {
|
|
|
+ setError(err instanceof Error ? err.message : 'Error desconocido')
|
|
|
+ } finally {
|
|
|
+ setLoading(false)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ fetchDashboardData()
|
|
|
+ }, [])
|
|
|
+
|
|
|
+ const stats = dashboardData ? [
|
|
|
+ {
|
|
|
+ title: 'Mis Clases',
|
|
|
+ value: dashboardData.stats.totalClasses.toString(),
|
|
|
+ description: 'Clases asignadas',
|
|
|
+ icon: BookOpen,
|
|
|
+ color: 'text-blue-600',
|
|
|
+ bgColor: 'bg-blue-100'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: 'Estudiantes',
|
|
|
+ value: dashboardData.stats.totalStudents.toString(),
|
|
|
+ description: 'Total de estudiantes',
|
|
|
+ icon: Users,
|
|
|
+ color: 'text-green-600',
|
|
|
+ bgColor: 'bg-green-100'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: 'Clases Hoy',
|
|
|
+ value: dashboardData.stats.todayClasses.toString(),
|
|
|
+ description: 'Clases programadas',
|
|
|
+ icon: Calendar,
|
|
|
+ color: 'text-purple-600',
|
|
|
+ bgColor: 'bg-purple-100'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: 'Asistencia Promedio',
|
|
|
+ value: `${dashboardData.stats.averageAttendance}%`,
|
|
|
+ description: 'Este mes',
|
|
|
+ icon: CheckCircle,
|
|
|
+ color: 'text-orange-600',
|
|
|
+ bgColor: 'bg-orange-100'
|
|
|
+ }
|
|
|
+ ] : []
|
|
|
+
|
|
|
+ if (loading) {
|
|
|
+ return (
|
|
|
+ <MainLayout
|
|
|
+ title="Dashboard Profesor"
|
|
|
+ subtitle="Gestión de clases y asistencia"
|
|
|
+ requiredRole="TEACHER"
|
|
|
+ >
|
|
|
+ <div className="flex items-center justify-center h-64">
|
|
|
+ <Loader2 className="h-8 w-8 animate-spin" />
|
|
|
+ <span className="ml-2">Cargando datos del dashboard...</span>
|
|
|
+ </div>
|
|
|
+ </MainLayout>
|
|
|
+ )
|
|
|
}
|
|
|
-]
|
|
|
|
|
|
-const todayClasses = [
|
|
|
- {
|
|
|
- id: 1,
|
|
|
- name: 'Matemáticas I',
|
|
|
- section: 'Sección A',
|
|
|
- time: '08:00 - 10:00',
|
|
|
- room: 'Aula 101',
|
|
|
- students: 25
|
|
|
- },
|
|
|
- {
|
|
|
- id: 2,
|
|
|
- name: 'Programación I',
|
|
|
- section: 'Sección B',
|
|
|
- time: '14:00 - 16:00',
|
|
|
- room: 'Lab 201',
|
|
|
- students: 20
|
|
|
+ if (error) {
|
|
|
+ return (
|
|
|
+ <MainLayout
|
|
|
+ title="Dashboard Profesor"
|
|
|
+ subtitle="Gestión de clases y asistencia"
|
|
|
+ requiredRole="TEACHER"
|
|
|
+ >
|
|
|
+ <div className="flex items-center justify-center h-64">
|
|
|
+ <div className="text-center">
|
|
|
+ <p className="text-red-600 mb-2">Error al cargar los datos</p>
|
|
|
+ <p className="text-sm text-muted-foreground">{error}</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </MainLayout>
|
|
|
+ )
|
|
|
}
|
|
|
-]
|
|
|
|
|
|
-const recentAttendance = [
|
|
|
- {
|
|
|
- id: 1,
|
|
|
- class: 'Matemáticas I - Sección A',
|
|
|
- date: '2024-01-20',
|
|
|
- present: 23,
|
|
|
- total: 25,
|
|
|
- percentage: 92
|
|
|
- },
|
|
|
- {
|
|
|
- id: 2,
|
|
|
- class: 'Programación I - Sección B',
|
|
|
- date: '2024-01-19',
|
|
|
- present: 18,
|
|
|
- total: 20,
|
|
|
- percentage: 90
|
|
|
- },
|
|
|
- {
|
|
|
- id: 3,
|
|
|
- class: 'Física I - Sección A',
|
|
|
- date: '2024-01-18',
|
|
|
- present: 20,
|
|
|
- total: 22,
|
|
|
- percentage: 91
|
|
|
+ if (!dashboardData) {
|
|
|
+ return (
|
|
|
+ <MainLayout
|
|
|
+ title="Dashboard Profesor"
|
|
|
+ subtitle="Gestión de clases y asistencia"
|
|
|
+ requiredRole="TEACHER"
|
|
|
+ >
|
|
|
+ <div className="flex items-center justify-center h-64">
|
|
|
+ <p className="text-muted-foreground">No hay datos disponibles</p>
|
|
|
+ </div>
|
|
|
+ </MainLayout>
|
|
|
+ )
|
|
|
}
|
|
|
-]
|
|
|
|
|
|
-export default function TeacherDashboard() {
|
|
|
return (
|
|
|
<MainLayout
|
|
|
title="Dashboard Profesor"
|
|
|
@@ -132,22 +157,28 @@ export default function TeacherDashboard() {
|
|
|
</CardHeader>
|
|
|
<CardContent>
|
|
|
<div className="space-y-4">
|
|
|
- {todayClasses.map((classItem) => (
|
|
|
- <div key={classItem.id} className="flex items-center justify-between p-3 border rounded-lg">
|
|
|
- <div className="space-y-1">
|
|
|
- <p className="text-sm font-medium">{classItem.name}</p>
|
|
|
- <p className="text-xs text-muted-foreground">
|
|
|
- {classItem.section} • {classItem.room}
|
|
|
- </p>
|
|
|
- </div>
|
|
|
- <div className="text-right">
|
|
|
- <p className="text-sm font-medium">{classItem.time}</p>
|
|
|
- <p className="text-xs text-muted-foreground">
|
|
|
- {classItem.students} estudiantes
|
|
|
- </p>
|
|
|
+ {dashboardData.todayClasses.length > 0 ? (
|
|
|
+ dashboardData.todayClasses.map((classItem) => (
|
|
|
+ <div key={classItem.id} className="flex items-center justify-between p-3 border rounded-lg">
|
|
|
+ <div className="space-y-1">
|
|
|
+ <p className="text-sm font-medium">{classItem.name}</p>
|
|
|
+ <p className="text-xs text-muted-foreground">
|
|
|
+ {classItem.section} • {classItem.room}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <div className="text-right">
|
|
|
+ {/*<p className="text-sm font-medium">{classItem.time}</p>*/}
|
|
|
+ <p className="text-xs text-muted-foreground">
|
|
|
+ {classItem.students} estudiantes
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- ))}
|
|
|
+ ))
|
|
|
+ ) : (
|
|
|
+ <p className="text-sm text-muted-foreground text-center py-4">
|
|
|
+ No hay clases programadas para hoy
|
|
|
+ </p>
|
|
|
+ )}
|
|
|
</div>
|
|
|
</CardContent>
|
|
|
</Card>
|
|
|
@@ -165,28 +196,34 @@ export default function TeacherDashboard() {
|
|
|
</CardHeader>
|
|
|
<CardContent>
|
|
|
<div className="space-y-4">
|
|
|
- {recentAttendance.map((record) => (
|
|
|
- <div key={record.id} className="flex items-center justify-between">
|
|
|
- <div className="space-y-1">
|
|
|
- <p className="text-sm font-medium">{record.class}</p>
|
|
|
- <p className="text-xs text-muted-foreground">{record.date}</p>
|
|
|
+ {dashboardData.recentAttendance.length > 0 ? (
|
|
|
+ dashboardData.recentAttendance.map((record) => (
|
|
|
+ <div key={record.id} className="flex items-center justify-between">
|
|
|
+ <div className="space-y-1">
|
|
|
+ <p className="text-sm font-medium">{record.class}</p>
|
|
|
+ <p className="text-xs text-muted-foreground">{record.date}</p>
|
|
|
+ </div>
|
|
|
+ <div className="text-right">
|
|
|
+ <p className="text-sm font-medium">
|
|
|
+ {record.present}/{record.total}
|
|
|
+ </p>
|
|
|
+ <p className={`text-xs font-medium ${
|
|
|
+ record.percentage >= 90
|
|
|
+ ? 'text-green-600'
|
|
|
+ : record.percentage >= 80
|
|
|
+ ? 'text-yellow-600'
|
|
|
+ : 'text-red-600'
|
|
|
+ }`}>
|
|
|
+ {record.percentage}%
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <div className="text-right">
|
|
|
- <p className="text-sm font-medium">
|
|
|
- {record.present}/{record.total}
|
|
|
- </p>
|
|
|
- <p className={`text-xs font-medium ${
|
|
|
- record.percentage >= 90
|
|
|
- ? 'text-green-600'
|
|
|
- : record.percentage >= 80
|
|
|
- ? 'text-yellow-600'
|
|
|
- : 'text-red-600'
|
|
|
- }`}>
|
|
|
- {record.percentage}%
|
|
|
- </p>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- ))}
|
|
|
+ ))
|
|
|
+ ) : (
|
|
|
+ <p className="text-sm text-muted-foreground text-center py-4">
|
|
|
+ No hay registros de asistencia recientes
|
|
|
+ </p>
|
|
|
+ )}
|
|
|
</div>
|
|
|
</CardContent>
|
|
|
</Card>
|