|
|
@@ -9,6 +9,9 @@ import { Alert, AlertDescription } from '@/components/ui/alert';
|
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
|
|
import { Trash2, Edit, Plus, Users } from 'lucide-react';
|
|
|
import { DashboardLayout } from '@/components/dashboard-layout';
|
|
|
+import { Spinner } from '@/components/ui/spinner';
|
|
|
+import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
|
|
+import { Badge } from '@/components/ui/badge';
|
|
|
|
|
|
interface Section {
|
|
|
id: string;
|
|
|
@@ -248,7 +251,7 @@ export default function SectionsPage() {
|
|
|
|
|
|
<div className="flex gap-2">
|
|
|
<Button type="submit" disabled={loading}>
|
|
|
- {loading ? 'Procesando...' : (editingId ? 'Actualizar' : 'Crear')}
|
|
|
+ {loading ? <Spinner size="sm" /> : (editingId ? 'Actualizar' : 'Crear')}
|
|
|
</Button>
|
|
|
{editingId && (
|
|
|
<Button type="button" variant="outline" onClick={handleCancel}>
|
|
|
@@ -278,61 +281,91 @@ export default function SectionsPage() {
|
|
|
<CardTitle>Secciones Registradas ({sections.length})</CardTitle>
|
|
|
</CardHeader>
|
|
|
<CardContent>
|
|
|
- <div className="space-y-3 max-h-96 overflow-y-auto">
|
|
|
- {sections.length === 0 ? (
|
|
|
- <p className="text-gray-500 text-center py-4">No hay secciones registradas</p>
|
|
|
- ) : (
|
|
|
- sections.map((section) => (
|
|
|
- <div
|
|
|
- key={section.id}
|
|
|
- className="flex items-center justify-between p-3 border rounded-lg hover:bg-gray-50"
|
|
|
- >
|
|
|
- <div className="flex-1">
|
|
|
- <div className="flex items-center gap-2">
|
|
|
- <h3 className="font-medium">{section.name}</h3>
|
|
|
- <span className="text-sm bg-blue-100 text-blue-800 px-2 py-1 rounded">
|
|
|
- {section.classCode}
|
|
|
- </span>
|
|
|
- </div>
|
|
|
- <p className="text-sm text-gray-600 mt-1">
|
|
|
- {section.className} - {section.periodName}
|
|
|
- </p>
|
|
|
- <p className="text-xs text-gray-500 mt-1">
|
|
|
- Profesor: {section.teacherName ? `${section.teacherName} (${section.teacherEmail})` : 'Sin asignar'}
|
|
|
- </p>
|
|
|
- <p className="text-xs text-gray-500 mt-1">
|
|
|
- Estudiantes: <span className={`font-medium ${
|
|
|
- section.enrolledStudents >= section.maxStudents
|
|
|
- ? 'text-red-600'
|
|
|
- : section.enrolledStudents >= section.maxStudents * 0.8
|
|
|
- ? 'text-yellow-600'
|
|
|
- : 'text-green-600'
|
|
|
- }`}>
|
|
|
- {section.enrolledStudents}
|
|
|
- </span> / {section.maxStudents} | Estado: {section.isActive ? 'Activa' : 'Inactiva'}
|
|
|
- </p>
|
|
|
- </div>
|
|
|
- <div className="flex gap-2">
|
|
|
- <Button
|
|
|
- size="sm"
|
|
|
- variant="outline"
|
|
|
- onClick={() => handleEdit(section)}
|
|
|
- >
|
|
|
- <Edit className="h-4 w-4" />
|
|
|
- </Button>
|
|
|
- <Button
|
|
|
- size="sm"
|
|
|
- variant="outline"
|
|
|
- onClick={() => handleDelete(section.id)}
|
|
|
- className="text-red-600 hover:text-red-700"
|
|
|
- >
|
|
|
- <Trash2 className="h-4 w-4" />
|
|
|
- </Button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- ))
|
|
|
- )}
|
|
|
- </div>
|
|
|
+ {sections.length === 0 ? (
|
|
|
+ <p className="text-gray-500 text-center py-8">No hay secciones registradas</p>
|
|
|
+ ) : (
|
|
|
+ <div className="max-h-96 overflow-y-auto">
|
|
|
+ <Table>
|
|
|
+ <TableHeader>
|
|
|
+ <TableRow>
|
|
|
+ <TableHead>Sección</TableHead>
|
|
|
+ <TableHead>Clase</TableHead>
|
|
|
+ <TableHead>Profesor</TableHead>
|
|
|
+ <TableHead>Estudiantes</TableHead>
|
|
|
+ <TableHead>Estado</TableHead>
|
|
|
+ <TableHead className="text-right">Acciones</TableHead>
|
|
|
+ </TableRow>
|
|
|
+ </TableHeader>
|
|
|
+ <TableBody>
|
|
|
+ {sections.map((section) => (
|
|
|
+ <TableRow key={section.id}>
|
|
|
+ <TableCell className="font-medium">
|
|
|
+ <div className="flex items-center gap-2">
|
|
|
+ {section.name}
|
|
|
+ <Badge variant="secondary">
|
|
|
+ {section.classCode}
|
|
|
+ </Badge>
|
|
|
+ </div>
|
|
|
+ </TableCell>
|
|
|
+ <TableCell>
|
|
|
+ <div className="text-sm">
|
|
|
+ <div className="font-medium">{section.className}</div>
|
|
|
+ <div className="text-gray-500">{section.periodName}</div>
|
|
|
+ </div>
|
|
|
+ </TableCell>
|
|
|
+ <TableCell className="text-sm">
|
|
|
+ {section.teacherName ? (
|
|
|
+ <div>
|
|
|
+ <div className="font-medium">{section.teacherName}</div>
|
|
|
+ <div className="text-gray-500">{section.teacherEmail}</div>
|
|
|
+ </div>
|
|
|
+ ) : (
|
|
|
+ <span className="text-gray-500">Sin asignar</span>
|
|
|
+ )}
|
|
|
+ </TableCell>
|
|
|
+ <TableCell>
|
|
|
+ <div className="flex items-center gap-2">
|
|
|
+ <Badge variant={
|
|
|
+ section.enrolledStudents >= section.maxStudents
|
|
|
+ ? 'destructive'
|
|
|
+ : section.enrolledStudents >= section.maxStudents * 0.8
|
|
|
+ ? 'outline'
|
|
|
+ : 'default'
|
|
|
+ }>
|
|
|
+ {section.enrolledStudents}/{section.maxStudents}
|
|
|
+ </Badge>
|
|
|
+ </div>
|
|
|
+ </TableCell>
|
|
|
+ <TableCell>
|
|
|
+ <Badge variant={section.isActive ? 'default' : 'outline'}>
|
|
|
+ {section.isActive ? 'Activa' : 'Inactiva'}
|
|
|
+ </Badge>
|
|
|
+ </TableCell>
|
|
|
+ <TableCell className="text-right">
|
|
|
+ <div className="flex gap-2 justify-end">
|
|
|
+ <Button
|
|
|
+ size="sm"
|
|
|
+ variant="outline"
|
|
|
+ onClick={() => handleEdit(section)}
|
|
|
+ >
|
|
|
+ <Edit className="h-4 w-4" />
|
|
|
+ </Button>
|
|
|
+ <Button
|
|
|
+ size="sm"
|
|
|
+ variant="outline"
|
|
|
+ onClick={() => handleDelete(section.id)}
|
|
|
+ className="text-red-600 hover:text-red-700"
|
|
|
+ >
|
|
|
+ <Trash2 className="h-4 w-4" />
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
+ </TableCell>
|
|
|
+ </TableRow>
|
|
|
+ ))}
|
|
|
+ </TableBody>
|
|
|
+ </Table>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
</CardContent>
|
|
|
</Card>
|
|
|
</div>
|