|
|
@@ -1,69 +1,49 @@
|
|
|
-'use client'
|
|
|
-
|
|
|
import { MainLayout } from '@/components/layout/main-layout'
|
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
|
|
-import { Users, BookOpen, GraduationCap, User, TrendingUp, Calendar } from 'lucide-react'
|
|
|
-
|
|
|
-const stats = [
|
|
|
- {
|
|
|
- title: 'Total Usuarios',
|
|
|
- value: '3',
|
|
|
- description: 'Usuarios registrados',
|
|
|
- icon: Users,
|
|
|
- color: 'text-blue-600',
|
|
|
- bgColor: 'bg-blue-100'
|
|
|
- },
|
|
|
- {
|
|
|
- title: 'Clases Activas',
|
|
|
- value: '3',
|
|
|
- description: 'Clases en el periodo actual',
|
|
|
- icon: BookOpen,
|
|
|
- color: 'text-green-600',
|
|
|
- bgColor: 'bg-green-100'
|
|
|
- },
|
|
|
- {
|
|
|
- title: 'Profesores',
|
|
|
- value: '1',
|
|
|
- description: 'Profesores activos',
|
|
|
- icon: GraduationCap,
|
|
|
- color: 'text-purple-600',
|
|
|
- bgColor: 'bg-purple-100'
|
|
|
- },
|
|
|
- {
|
|
|
- title: 'Estudiantes',
|
|
|
- value: '1',
|
|
|
- description: 'Estudiantes matriculados',
|
|
|
- icon: User,
|
|
|
- color: 'text-orange-600',
|
|
|
- bgColor: 'bg-orange-100'
|
|
|
- }
|
|
|
-]
|
|
|
+import { Users, BookOpen, GraduationCap, User, TrendingUp, Calendar, UserCheck, Clock } from 'lucide-react'
|
|
|
+import { getDashboardStats, getRecentActivities, getCurrentPeriod } from './actions'
|
|
|
|
|
|
-const recentActivities = [
|
|
|
- {
|
|
|
- id: 1,
|
|
|
- action: 'Nuevo estudiante registrado',
|
|
|
- user: 'María González',
|
|
|
- time: 'Hace 2 horas',
|
|
|
- type: 'user'
|
|
|
- },
|
|
|
- {
|
|
|
- id: 2,
|
|
|
- action: 'Clase creada',
|
|
|
- user: 'Sistema',
|
|
|
- time: 'Hace 3 horas',
|
|
|
- type: 'class'
|
|
|
- },
|
|
|
- {
|
|
|
- id: 3,
|
|
|
- action: 'Profesor asignado',
|
|
|
- user: 'Juan Pérez',
|
|
|
- time: 'Hace 5 horas',
|
|
|
- type: 'assignment'
|
|
|
- }
|
|
|
-]
|
|
|
+export default async function AdminDashboard() {
|
|
|
+ const [stats, recentActivities, currentPeriod] = await Promise.all([
|
|
|
+ getDashboardStats(),
|
|
|
+ getRecentActivities(),
|
|
|
+ getCurrentPeriod()
|
|
|
+ ])
|
|
|
|
|
|
-export default function AdminDashboard() {
|
|
|
+ const statsCards = [
|
|
|
+ {
|
|
|
+ title: 'Total Usuarios',
|
|
|
+ value: stats.totalUsers.toString(),
|
|
|
+ description: 'Usuarios registrados',
|
|
|
+ icon: Users,
|
|
|
+ color: 'text-blue-600',
|
|
|
+ bgColor: 'bg-blue-100'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: 'Clases Activas',
|
|
|
+ value: stats.totalClasses.toString(),
|
|
|
+ description: 'Clases en el periodo actual',
|
|
|
+ icon: BookOpen,
|
|
|
+ color: 'text-green-600',
|
|
|
+ bgColor: 'bg-green-100'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: 'Profesores',
|
|
|
+ value: stats.totalTeachers.toString(),
|
|
|
+ description: 'Profesores activos',
|
|
|
+ icon: GraduationCap,
|
|
|
+ color: 'text-purple-600',
|
|
|
+ bgColor: 'bg-purple-100'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: 'Estudiantes',
|
|
|
+ value: stats.totalStudents.toString(),
|
|
|
+ description: 'Estudiantes matriculados',
|
|
|
+ icon: User,
|
|
|
+ color: 'text-orange-600',
|
|
|
+ bgColor: 'bg-orange-100'
|
|
|
+ }
|
|
|
+ ]
|
|
|
return (
|
|
|
<MainLayout
|
|
|
title="Dashboard Administrativo"
|
|
|
@@ -73,7 +53,7 @@ export default function AdminDashboard() {
|
|
|
<div className="space-y-6">
|
|
|
{/* Estadísticas */}
|
|
|
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
|
|
- {stats.map((stat) => {
|
|
|
+ {statsCards.map((stat) => {
|
|
|
const Icon = stat.icon
|
|
|
return (
|
|
|
<Card key={stat.title}>
|
|
|
@@ -110,57 +90,142 @@ export default function AdminDashboard() {
|
|
|
</CardHeader>
|
|
|
<CardContent>
|
|
|
<div className="space-y-4">
|
|
|
- {recentActivities.map((activity) => (
|
|
|
- <div key={activity.id} className="flex items-center space-x-4">
|
|
|
- <div className="w-2 h-2 bg-blue-600 rounded-full"></div>
|
|
|
- <div className="flex-1 space-y-1">
|
|
|
- <p className="text-sm font-medium leading-none">
|
|
|
- {activity.action}
|
|
|
- </p>
|
|
|
- <p className="text-sm text-muted-foreground">
|
|
|
- {activity.user} • {activity.time}
|
|
|
- </p>
|
|
|
- </div>
|
|
|
+ {recentActivities.length > 0 ? (
|
|
|
+ recentActivities.map((activity) => {
|
|
|
+ const getActivityColor = (type: string) => {
|
|
|
+ switch (type) {
|
|
|
+ case 'user': return 'bg-blue-600'
|
|
|
+ case 'enrollment': return 'bg-green-600'
|
|
|
+ case 'assignment': return 'bg-purple-600'
|
|
|
+ default: return 'bg-gray-600'
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div key={activity.id} className="flex items-center space-x-4">
|
|
|
+ <div className={`w-2 h-2 rounded-full ${getActivityColor(activity.type)}`}></div>
|
|
|
+ <div className="flex-1 space-y-1">
|
|
|
+ <p className="text-sm font-medium leading-none">
|
|
|
+ {activity.action}
|
|
|
+ </p>
|
|
|
+ <p className="text-sm text-muted-foreground">
|
|
|
+ {activity.user} • {activity.time}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+ })
|
|
|
+ ) : (
|
|
|
+ <div className="text-center py-4">
|
|
|
+ <Clock className="h-8 w-8 mx-auto text-muted-foreground mb-2" />
|
|
|
+ <p className="text-sm text-muted-foreground">
|
|
|
+ No hay actividad reciente
|
|
|
+ </p>
|
|
|
</div>
|
|
|
- ))}
|
|
|
+ )}
|
|
|
</div>
|
|
|
</CardContent>
|
|
|
</Card>
|
|
|
|
|
|
{/* Resumen del Periodo */}
|
|
|
- {/* <Card>
|
|
|
+ <Card>
|
|
|
<CardHeader>
|
|
|
<CardTitle className="flex items-center gap-2">
|
|
|
<Calendar className="h-5 w-5" />
|
|
|
Periodo Académico Actual
|
|
|
</CardTitle>
|
|
|
<CardDescription>
|
|
|
- Información del periodo 2024
|
|
|
+ {currentPeriod ? `Información del ${currentPeriod.name}` : 'No hay periodo activo'}
|
|
|
</CardDescription>
|
|
|
</CardHeader>
|
|
|
<CardContent>
|
|
|
- <div className="space-y-4">
|
|
|
- <div className="flex justify-between items-center">
|
|
|
- <span className="text-sm font-medium">Periodo:</span>
|
|
|
- <span className="text-sm text-muted-foreground">2024</span>
|
|
|
- </div>
|
|
|
- <div className="flex justify-between items-center">
|
|
|
- <span className="text-sm font-medium">Parciales:</span>
|
|
|
- <span className="text-sm text-muted-foreground">3 configurados</span>
|
|
|
- </div>
|
|
|
- <div className="flex justify-between items-center">
|
|
|
- <span className="text-sm font-medium">Estado:</span>
|
|
|
- <span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
|
|
|
- Activo
|
|
|
- </span>
|
|
|
+ {currentPeriod ? (
|
|
|
+ <div className="space-y-4">
|
|
|
+ <div className="flex justify-between items-center">
|
|
|
+ <span className="text-sm font-medium">Periodo:</span>
|
|
|
+ <span className="text-sm text-muted-foreground">{currentPeriod.name}</span>
|
|
|
+ </div>
|
|
|
+ <div className="flex justify-between items-center">
|
|
|
+ <span className="text-sm font-medium">Parciales:</span>
|
|
|
+ <span className="text-sm text-muted-foreground">{currentPeriod.totalPartials} configurados</span>
|
|
|
+ </div>
|
|
|
+ <div className="flex justify-between items-center">
|
|
|
+ <span className="text-sm font-medium">Estado:</span>
|
|
|
+ <span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${
|
|
|
+ currentPeriod.isActive
|
|
|
+ ? 'bg-green-100 text-green-800'
|
|
|
+ : 'bg-red-100 text-red-800'
|
|
|
+ }`}>
|
|
|
+ {currentPeriod.isActive ? 'Activo' : 'Inactivo'}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <div className="flex justify-between items-center">
|
|
|
+ <span className="text-sm font-medium">Clases:</span>
|
|
|
+ <span className="text-sm text-muted-foreground">{currentPeriod.totalClasses} activas</span>
|
|
|
+ </div>
|
|
|
+ <div className="flex justify-between items-center">
|
|
|
+ <span className="text-sm font-medium">Secciones:</span>
|
|
|
+ <span className="text-sm text-muted-foreground">{stats.totalSections} activas</span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <div className="flex justify-between items-center">
|
|
|
- <span className="text-sm font-medium">Clases:</span>
|
|
|
- <span className="text-sm text-muted-foreground">3 activas</span>
|
|
|
+ ) : (
|
|
|
+ <div className="text-center py-4">
|
|
|
+ <Calendar className="h-8 w-8 mx-auto text-muted-foreground mb-2" />
|
|
|
+ <p className="text-sm text-muted-foreground">
|
|
|
+ No hay periodo académico activo
|
|
|
+ </p>
|
|
|
</div>
|
|
|
- </div>
|
|
|
+ )}
|
|
|
</CardContent>
|
|
|
- </Card> */}
|
|
|
+ </Card>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {/* Estadísticas adicionales */}
|
|
|
+ <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
|
+ <Card>
|
|
|
+ <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
|
+ <CardTitle className="text-sm font-medium">
|
|
|
+ Inscripciones Recientes
|
|
|
+ </CardTitle>
|
|
|
+ <UserCheck className="h-4 w-4 text-muted-foreground" />
|
|
|
+ </CardHeader>
|
|
|
+ <CardContent>
|
|
|
+ <div className="text-2xl font-bold">{stats.recentEnrollments}</div>
|
|
|
+ <p className="text-xs text-muted-foreground">
|
|
|
+ Últimos 30 días
|
|
|
+ </p>
|
|
|
+ </CardContent>
|
|
|
+ </Card>
|
|
|
+
|
|
|
+ <Card>
|
|
|
+ <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
|
+ <CardTitle className="text-sm font-medium">
|
|
|
+ Asistencias Registradas
|
|
|
+ </CardTitle>
|
|
|
+ <Clock className="h-4 w-4 text-muted-foreground" />
|
|
|
+ </CardHeader>
|
|
|
+ <CardContent>
|
|
|
+ <div className="text-2xl font-bold">{stats.recentAttendance}</div>
|
|
|
+ <p className="text-xs text-muted-foreground">
|
|
|
+ Últimos 7 días
|
|
|
+ </p>
|
|
|
+ </CardContent>
|
|
|
+ </Card>
|
|
|
+
|
|
|
+ <Card>
|
|
|
+ <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
|
+ <CardTitle className="text-sm font-medium">
|
|
|
+ Periodos Activos
|
|
|
+ </CardTitle>
|
|
|
+ <Calendar className="h-4 w-4 text-muted-foreground" />
|
|
|
+ </CardHeader>
|
|
|
+ <CardContent>
|
|
|
+ <div className="text-2xl font-bold">{stats.activePeriods}</div>
|
|
|
+ <p className="text-xs text-muted-foreground">
|
|
|
+ Periodos académicos
|
|
|
+ </p>
|
|
|
+ </CardContent>
|
|
|
+ </Card>
|
|
|
</div>
|
|
|
</div>
|
|
|
</MainLayout>
|