소스 검색

placeholder galore

Matthew Trejo 4 달 전
부모
커밋
89e58bde53
5개의 변경된 파일458개의 추가작업 그리고 5개의 파일을 삭제
  1. 62 0
      src/app/student/attendance/page.tsx
  2. 62 0
      src/app/student/classes/page.tsx
  3. 256 0
      src/app/student/dashboard/page.tsx
  4. 62 0
      src/app/student/schedule/page.tsx
  5. 16 5
      src/components/app-sidebar.tsx

+ 62 - 0
src/app/student/attendance/page.tsx

@@ -0,0 +1,62 @@
+'use client'
+
+import { DashboardLayout } from '@/components/dashboard-layout'
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
+import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from '@/components/ui/breadcrumb'
+import { ClipboardList, Construction } from 'lucide-react'
+
+export default function StudentAttendancePage() {
+  return (
+    <DashboardLayout>
+      <div className="space-y-6">
+        {/* Breadcrumb */}
+        <Breadcrumb>
+          <BreadcrumbList>
+            <BreadcrumbItem>
+              <BreadcrumbLink href="/student/dashboard">Estudiante</BreadcrumbLink>
+            </BreadcrumbItem>
+            <BreadcrumbSeparator />
+            <BreadcrumbItem>
+              <BreadcrumbPage>Mi Asistencia</BreadcrumbPage>
+            </BreadcrumbItem>
+          </BreadcrumbList>
+        </Breadcrumb>
+
+        {/* Header */}
+        <div className="flex items-center gap-3">
+          <div className="p-2 bg-primary/10 rounded-lg">
+            <ClipboardList className="h-6 w-6 text-primary" />
+          </div>
+          <div>
+            <h1 className="text-2xl font-bold">Mi Asistencia</h1>
+            <p className="text-muted-foreground">Historial detallado de tu asistencia</p>
+          </div>
+        </div>
+
+        {/* Contenido Pendiente */}
+        <Card>
+          <CardHeader>
+            <CardTitle className="flex items-center gap-2">
+              <Construction className="h-5 w-5 text-yellow-600" />
+              Página en Desarrollo
+            </CardTitle>
+            <CardDescription>
+              Esta funcionalidad está pendiente de implementar
+            </CardDescription>
+          </CardHeader>
+          <CardContent>
+            <div className="flex flex-col items-center justify-center py-12 text-center">
+              <div className="p-4 bg-yellow-100 rounded-full mb-4">
+                <Construction className="h-12 w-12 text-yellow-600" />
+              </div>
+              <h3 className="text-lg font-semibold mb-2">Pendiente de Hacer</h3>
+              <p className="text-muted-foreground max-w-md">
+                La página de "Mi Asistencia" está en desarrollo. Aquí podrás ver tu historial completo de asistencia, estadísticas por materia, y reportes detallados.
+              </p>
+            </div>
+          </CardContent>
+        </Card>
+      </div>
+    </DashboardLayout>
+  )
+}

+ 62 - 0
src/app/student/classes/page.tsx

@@ -0,0 +1,62 @@
+'use client'
+
+import { DashboardLayout } from '@/components/dashboard-layout'
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
+import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from '@/components/ui/breadcrumb'
+import { BookOpen, Construction } from 'lucide-react'
+
+export default function StudentClassesPage() {
+  return (
+    <DashboardLayout>
+      <div className="space-y-6">
+        {/* Breadcrumb */}
+        <Breadcrumb>
+          <BreadcrumbList>
+            <BreadcrumbItem>
+              <BreadcrumbLink href="/student/dashboard">Estudiante</BreadcrumbLink>
+            </BreadcrumbItem>
+            <BreadcrumbSeparator />
+            <BreadcrumbItem>
+              <BreadcrumbPage>Mis Clases</BreadcrumbPage>
+            </BreadcrumbItem>
+          </BreadcrumbList>
+        </Breadcrumb>
+
+        {/* Header */}
+        <div className="flex items-center gap-3">
+          <div className="p-2 bg-primary/10 rounded-lg">
+            <BookOpen className="h-6 w-6 text-primary" />
+          </div>
+          <div>
+            <h1 className="text-2xl font-bold">Mis Clases</h1>
+            <p className="text-muted-foreground">Gestión de tus clases y materias</p>
+          </div>
+        </div>
+
+        {/* Contenido Pendiente */}
+        <Card>
+          <CardHeader>
+            <CardTitle className="flex items-center gap-2">
+              <Construction className="h-5 w-5 text-yellow-600" />
+              Página en Desarrollo
+            </CardTitle>
+            <CardDescription>
+              Esta funcionalidad está pendiente de implementar
+            </CardDescription>
+          </CardHeader>
+          <CardContent>
+            <div className="flex flex-col items-center justify-center py-12 text-center">
+              <div className="p-4 bg-yellow-100 rounded-full mb-4">
+                <Construction className="h-12 w-12 text-yellow-600" />
+              </div>
+              <h3 className="text-lg font-semibold mb-2">Pendiente de Hacer</h3>
+              <p className="text-muted-foreground max-w-md">
+                La página de "Mis Clases" está en desarrollo. Aquí podrás ver información detallada sobre tus materias, horarios de clase, y recursos académicos.
+              </p>
+            </div>
+          </CardContent>
+        </Card>
+      </div>
+    </DashboardLayout>
+  )
+}

+ 256 - 0
src/app/student/dashboard/page.tsx

@@ -0,0 +1,256 @@
+'use client'
+
+import { useState, useEffect } from 'react'
+import { DashboardLayout } from '@/components/dashboard-layout'
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
+import { Badge } from '@/components/ui/badge'
+import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from '@/components/ui/breadcrumb'
+import { BookOpen, Calendar, Users, CheckCircle, XCircle, Clock } from 'lucide-react'
+import { toast } from 'sonner'
+
+interface Section {
+  id: string
+  name: string
+  className: string
+  classCode: string
+  credits: number
+  teacherName: string
+  isActive: boolean
+}
+
+interface AttendanceSummary {
+  totalClasses: number
+  present: number
+  absent: number
+  tardy: number
+  attendanceRate: number
+}
+
+export default function StudentDashboard() {
+  const [sections, setSections] = useState<Section[]>([])
+  const [attendanceSummary, setAttendanceSummary] = useState<AttendanceSummary | null>(null)
+  const [loading, setLoading] = useState(true)
+
+  useEffect(() => {
+    fetchStudentData()
+  }, [])
+
+  const fetchStudentData = async () => {
+    try {
+      // Simular datos por ahora - en el futuro se conectará a APIs reales
+      const mockSections: Section[] = [
+        {
+          id: '1',
+          name: 'Sección A',
+          className: 'Matemáticas Avanzadas',
+          classCode: 'MAT-401',
+          credits: 4,
+          teacherName: 'Prof. García',
+          isActive: true
+        },
+        {
+          id: '2',
+          name: 'Sección B',
+          className: 'Programación Web',
+          classCode: 'INF-301',
+          credits: 3,
+          teacherName: 'Prof. Rodríguez',
+          isActive: true
+        },
+        {
+          id: '3',
+          name: 'Sección C',
+          className: 'Base de Datos',
+          classCode: 'INF-302',
+          credits: 3,
+          teacherName: 'Prof. Martínez',
+          isActive: true
+        }
+      ]
+
+      const mockAttendance: AttendanceSummary = {
+        totalClasses: 45,
+        present: 38,
+        absent: 4,
+        tardy: 3,
+        attendanceRate: 84.4
+      }
+
+      setSections(mockSections)
+      setAttendanceSummary(mockAttendance)
+    } catch (error) {
+      console.error('Error:', error)
+      toast.error('Error al cargar los datos')
+    } finally {
+      setLoading(false)
+    }
+  }
+
+  const getAttendanceColor = (rate: number) => {
+    if (rate >= 90) return 'text-green-600'
+    if (rate >= 80) return 'text-yellow-600'
+    return 'text-red-600'
+  }
+
+  const getAttendanceBadgeVariant = (rate: number) => {
+    if (rate >= 90) return 'default'
+    if (rate >= 80) return 'secondary'
+    return 'destructive'
+  }
+
+  if (loading) {
+    return (
+      <DashboardLayout>
+        <div className="flex items-center justify-center min-h-[400px]">
+          <div className="text-center">
+            <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto mb-4"></div>
+            <p className="text-muted-foreground">Cargando...</p>
+          </div>
+        </div>
+      </DashboardLayout>
+    )
+  }
+
+  return (
+    <DashboardLayout>
+      <div className="space-y-6">
+        {/* Breadcrumb */}
+        <Breadcrumb>
+          <BreadcrumbList>
+            <BreadcrumbItem>
+              <BreadcrumbLink href="/student">Estudiante</BreadcrumbLink>
+            </BreadcrumbItem>
+            <BreadcrumbSeparator />
+            <BreadcrumbItem>
+              <BreadcrumbPage>Dashboard</BreadcrumbPage>
+            </BreadcrumbItem>
+          </BreadcrumbList>
+        </Breadcrumb>
+
+        {/* Header */}
+        <div className="flex items-center gap-3">
+          <div className="p-2 bg-primary/10 rounded-lg">
+            <BookOpen className="h-6 w-6 text-primary" />
+          </div>
+          <div>
+            <h1 className="text-2xl font-bold">Mi Dashboard</h1>
+            <p className="text-muted-foreground">Resumen de tus clases y asistencia</p>
+          </div>
+        </div>
+
+        {/* Resumen de Asistencia */}
+        {attendanceSummary && (
+          <div className="grid grid-cols-1 md:grid-cols-4 gap-4">
+            <Card>
+              <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
+                <CardTitle className="text-sm font-medium">Total Clases</CardTitle>
+                <Calendar className="h-4 w-4 text-muted-foreground" />
+              </CardHeader>
+              <CardContent>
+                <div className="text-2xl font-bold">{attendanceSummary.totalClasses}</div>
+              </CardContent>
+            </Card>
+
+            <Card>
+              <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
+                <CardTitle className="text-sm font-medium">Presente</CardTitle>
+                <CheckCircle className="h-4 w-4 text-green-600" />
+              </CardHeader>
+              <CardContent>
+                <div className="text-2xl font-bold text-green-600">{attendanceSummary.present}</div>
+              </CardContent>
+            </Card>
+
+            <Card>
+              <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
+                <CardTitle className="text-sm font-medium">Ausente</CardTitle>
+                <XCircle className="h-4 w-4 text-red-600" />
+              </CardHeader>
+              <CardContent>
+                <div className="text-2xl font-bold text-red-600">{attendanceSummary.absent}</div>
+              </CardContent>
+            </Card>
+
+            <Card>
+              <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
+                <CardTitle className="text-sm font-medium">Tardanza</CardTitle>
+                <Clock className="h-4 w-4 text-yellow-600" />
+              </CardHeader>
+              <CardContent>
+                <div className="text-2xl font-bold text-yellow-600">{attendanceSummary.tardy}</div>
+              </CardContent>
+            </Card>
+          </div>
+        )}
+
+        {/* Porcentaje de Asistencia */}
+        {attendanceSummary && (
+          <Card>
+            <CardHeader>
+              <CardTitle className="flex items-center gap-2">
+                <CheckCircle className="h-5 w-5" />
+                Porcentaje de Asistencia
+              </CardTitle>
+            </CardHeader>
+            <CardContent>
+              <div className="flex items-center justify-between">
+                <div>
+                  <div className={`text-3xl font-bold ${getAttendanceColor(attendanceSummary.attendanceRate)}`}>
+                    {attendanceSummary.attendanceRate}%
+                  </div>
+                  <p className="text-sm text-muted-foreground mt-1">
+                    {attendanceSummary.present} de {attendanceSummary.totalClasses} clases
+                  </p>
+                </div>
+                <Badge variant={getAttendanceBadgeVariant(attendanceSummary.attendanceRate)}>
+                  {attendanceSummary.attendanceRate >= 90 ? 'Excelente' : 
+                   attendanceSummary.attendanceRate >= 80 ? 'Bueno' : 'Necesita Mejorar'}
+                </Badge>
+              </div>
+            </CardContent>
+          </Card>
+        )}
+
+        {/* Mis Secciones */}
+        <Card>
+          <CardHeader>
+            <CardTitle className="flex items-center gap-2">
+              <Users className="h-5 w-5" />
+              Mis Secciones
+            </CardTitle>
+            <CardDescription>
+              Clases en las que estás inscrito este período
+            </CardDescription>
+          </CardHeader>
+          <CardContent>
+            <div className="space-y-4">
+              {sections.map((section) => (
+                <div key={section.id} className="flex items-center justify-between p-4 border rounded-lg">
+                  <div className="flex items-center gap-4">
+                    <div className="p-2 bg-primary/10 rounded-lg">
+                      <BookOpen className="h-4 w-4 text-primary" />
+                    </div>
+                    <div>
+                      <h3 className="font-semibold">{section.className}</h3>
+                      <p className="text-sm text-muted-foreground">
+                        {section.classCode} - {section.name}
+                      </p>
+                      <p className="text-sm text-muted-foreground">
+                        {section.teacherName} • {section.credits} créditos
+                      </p>
+                    </div>
+                  </div>
+                  <div className="flex items-center gap-2">
+                    <Badge variant={section.isActive ? 'default' : 'secondary'}>
+                      {section.isActive ? 'Activa' : 'Inactiva'}
+                    </Badge>
+                  </div>
+                </div>
+              ))}
+            </div>
+          </CardContent>
+        </Card>
+      </div>
+    </DashboardLayout>
+  )
+}

+ 62 - 0
src/app/student/schedule/page.tsx

@@ -0,0 +1,62 @@
+'use client'
+
+import { DashboardLayout } from '@/components/dashboard-layout'
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
+import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from '@/components/ui/breadcrumb'
+import { Calendar, Construction } from 'lucide-react'
+
+export default function StudentSchedulePage() {
+  return (
+    <DashboardLayout>
+      <div className="space-y-6">
+        {/* Breadcrumb */}
+        <Breadcrumb>
+          <BreadcrumbList>
+            <BreadcrumbItem>
+              <BreadcrumbLink href="/student/dashboard">Estudiante</BreadcrumbLink>
+            </BreadcrumbItem>
+            <BreadcrumbSeparator />
+            <BreadcrumbItem>
+              <BreadcrumbPage>Horarios</BreadcrumbPage>
+            </BreadcrumbItem>
+          </BreadcrumbList>
+        </Breadcrumb>
+
+        {/* Header */}
+        <div className="flex items-center gap-3">
+          <div className="p-2 bg-primary/10 rounded-lg">
+            <Calendar className="h-6 w-6 text-primary" />
+          </div>
+          <div>
+            <h1 className="text-2xl font-bold">Horarios</h1>
+            <p className="text-muted-foreground">Tu horario académico semanal</p>
+          </div>
+        </div>
+
+        {/* Contenido Pendiente */}
+        <Card>
+          <CardHeader>
+            <CardTitle className="flex items-center gap-2">
+              <Construction className="h-5 w-5 text-yellow-600" />
+              Página en Desarrollo
+            </CardTitle>
+            <CardDescription>
+              Esta funcionalidad está pendiente de implementar
+            </CardDescription>
+          </CardHeader>
+          <CardContent>
+            <div className="flex flex-col items-center justify-center py-12 text-center">
+              <div className="p-4 bg-yellow-100 rounded-full mb-4">
+                <Construction className="h-12 w-12 text-yellow-600" />
+              </div>
+              <h3 className="text-lg font-semibold mb-2">Pendiente de Hacer</h3>
+              <p className="text-muted-foreground max-w-md">
+                La página de "Horarios" está en desarrollo. Aquí podrás ver tu horario semanal de clases, horarios de profesores, y calendario académico.
+              </p>
+            </div>
+          </CardContent>
+        </Card>
+      </div>
+    </DashboardLayout>
+  )
+}

+ 16 - 5
src/components/app-sidebar.tsx

@@ -127,9 +127,24 @@ const teacherMenuItems = [
 const studentMenuItems = [
   {
     title: "Dashboard",
-    url: "/student",
+    url: "/student/dashboard",
     icon: Home,
   },
+  {
+    title: "Mis Clases",
+    url: "/student/classes",
+    icon: BookOpen,
+  },
+  {
+    title: "Mi Asistencia",
+    url: "/student/attendance",
+    icon: ClipboardList,
+  },
+  {
+    title: "Horarios",
+    url: "/student/schedule",
+    icon: Calendar,
+  },
 ]
 
 export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
@@ -195,10 +210,6 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
         <SidebarMenu>
           <SidebarMenuItem>
             <div className="flex items-center gap-2 px-2 py-1.5">
-              <Avatar className="h-8 w-8">
-                <AvatarImage src={session.user.image || ""} />
-                <AvatarFallback>{userInitials}</AvatarFallback>
-              </Avatar>
               <div className="grid flex-1 text-left text-sm leading-tight">
                 <span className="truncate font-semibold">
                   {session.user.firstName} {session.user.lastName}