Matthew Trejo 3 months ago
parent
commit
94d39ec5d6

+ 4 - 4
src/app/api/admin/student-enrollments/[id]/route.ts

@@ -5,7 +5,7 @@ import { db } from '@/lib/db'
 import { studentEnrollments, users, classes, sections } from '@/lib/db/schema'
 import { eq, and, ne } from 'drizzle-orm'
 
-export async function PUT(request: NextRequest, { params }: { params: { id: string } }) {
+export async function PUT(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
   try {
     const session = await getServerSession(authOptions)
 
@@ -16,7 +16,7 @@ export async function PUT(request: NextRequest, { params }: { params: { id: stri
       )
     }
 
-    const { id } = params
+    const { id } = await params
     const { studentId, classId, sectionId } = await request.json()
 
     // Validate required fields
@@ -144,7 +144,7 @@ export async function PUT(request: NextRequest, { params }: { params: { id: stri
   }
 }
 
-export async function DELETE(request: NextRequest, { params }: { params: { id: string } }) {
+export async function DELETE(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
   try {
     const session = await getServerSession(authOptions)
 
@@ -155,7 +155,7 @@ export async function DELETE(request: NextRequest, { params }: { params: { id: s
       )
     }
 
-    const { id } = params
+    const { id } = await params
 
     // Verify enrollment exists
     const existingEnrollment = await db

+ 6 - 6
src/app/api/admin/student-enrollments/route.ts

@@ -3,7 +3,7 @@ import { getServerSession } from 'next-auth'
 import { authOptions } from '@/lib/auth'
 import { db } from '@/lib/db'
 import { studentEnrollments, users, classes, sections, periods } from '@/lib/db/schema'
-import { eq, and, count } from 'drizzle-orm'
+import { eq, and } from 'drizzle-orm'
 
 export async function GET(request: NextRequest) {
   try {
@@ -21,7 +21,7 @@ export async function GET(request: NextRequest) {
     const periodId = searchParams.get('periodId')
 
     // Build the where conditions
-    let whereConditions: any[] = []
+    const whereConditions = []
     if (!includeInactive) {
       whereConditions.push(eq(studentEnrollments.isActive, true))
     }
@@ -30,7 +30,7 @@ export async function GET(request: NextRequest) {
     }
 
     // Get student enrollments with student, class, section, and period information
-    let query = db
+    const baseQuery = db
       .select({
         id: studentEnrollments.id,
         studentId: studentEnrollments.studentId,
@@ -54,9 +54,9 @@ export async function GET(request: NextRequest) {
       .innerJoin(sections, eq(studentEnrollments.sectionId, sections.id))
       .innerJoin(periods, eq(classes.periodId, periods.id))
 
-    if (whereConditions.length > 0) {
-      query = query.where(and(...whereConditions)) as any
-    }
+    const query = whereConditions.length > 0 
+      ? baseQuery.where(and(...whereConditions))
+      : baseQuery
 
     const result = await query.orderBy(studentEnrollments.createdAt)
 

+ 4 - 4
src/app/api/admin/teacher-assignments/[id]/route.ts

@@ -6,10 +6,10 @@ import { eq, and, ne } from 'drizzle-orm';
 // PUT - Actualizar asignación de profesor
 export async function PUT(
   request: NextRequest,
-  { params }: { params: { id: string } }
+  { params }: { params: Promise<{ id: string }> }
 ) {
   try {
-    const { id } = params;
+    const { id } = await params;
     const body = await request.json();
     const { teacherId, classId, sectionId } = body;
 
@@ -126,10 +126,10 @@ export async function PUT(
 // DELETE - Eliminar asignación de profesor
 export async function DELETE(
   request: NextRequest,
-  { params }: { params: { id: string } }
+  { params }: { params: Promise<{ id: string }> }
 ) {
   try {
-    const { id } = params;
+    const { id } = await params;
 
     // Verificar que la asignación existe
     const existingAssignment = await db

+ 26 - 8
src/app/api/teacher/attendance-history/route.ts

@@ -4,11 +4,7 @@ import { authOptions } from '@/lib/auth'
 import { db } from '@/lib/db'
 import { 
   teacherAssignments, 
-  sections, 
-  classes,
-  periods,
   partials,
-  studentEnrollments, 
   users, 
   attendance, 
   eq, 
@@ -92,7 +88,29 @@ export async function GET(request: NextRequest) {
       .orderBy(desc(attendance.date), users.firstName, users.lastName)
 
     // Group records by date
-    const groupedByDate = attendanceRecords.reduce((acc, record) => {
+    const groupedByDate = attendanceRecords.reduce((acc: Record<string, {
+      date: string;
+      records: Array<{
+        id: string;
+        student: {
+          id: string;
+          name: string;
+          email: string;
+        };
+        status: string;
+        reason: string | null;
+        partial: {
+          id: string;
+          name: string;
+        } | null;
+      }>;
+      summary: {
+        total: number;
+        present: number;
+        absent: number;
+        late: number;
+      };
+    }>, record) => {
       const dateKey = record.date
       
       if (!acc[dateKey]) {
@@ -117,7 +135,7 @@ export async function GET(request: NextRequest) {
         },
         status: record.status,
         reason: record.reason,
-        partial: record.partialId ? {
+        partial: record.partialId && record.partialName ? {
           id: record.partialId,
           name: record.partialName
         } : null
@@ -130,11 +148,11 @@ export async function GET(request: NextRequest) {
       else if (record.status === 'late') acc[dateKey].summary.late++
       
       return acc
-    }, {} as Record<string, any>)
+    }, {})
 
     // Convert to array and sort by date (most recent first)
     // Usar comparación de strings directamente para evitar offset de timezone
-    const historyByDate = Object.values(groupedByDate).sort((a: any, b: any) => 
+    const historyByDate = Object.values(groupedByDate).sort((a, b) => 
       b.date.localeCompare(a.date)
     )
 

+ 2 - 4
src/app/api/teacher/export-attendance/route.ts

@@ -3,9 +3,7 @@ import { getServerSession } from 'next-auth'
 import { authOptions } from '@/lib/auth'
 import { db } from '@/lib/db'
 import { attendance, users, sections, classes, teacherAssignments, partials } from '@/lib/db/schema'
-import { eq, and, gte, lte, desc } from 'drizzle-orm'
-import { format } from 'date-fns'
-import { es } from 'date-fns/locale'
+import { eq, and, desc } from 'drizzle-orm'
 
 export async function GET(request: NextRequest) {
   try {
@@ -77,7 +75,7 @@ export async function GET(request: NextRequest) {
     }
 
     // Construir query base con verificación de acceso
-    let whereConditions = [
+    const whereConditions = [
       eq(attendance.date, dateStr),
       // Solo incluir secciones a las que el profesor tiene acceso
       teacherSections.length === 1 

+ 28 - 3
src/app/api/teacher/student-attendance/route.ts

@@ -6,7 +6,6 @@ import {
   teacherAssignments, 
   sections, 
   classes,
-  periods,
   partials,
   studentEnrollments, 
   users, 
@@ -207,7 +206,7 @@ export async function GET(request: NextRequest) {
         date: record.date,
         status: record.status,
         reason: record.reason,
-        partial: record.partialId ? {
+        partial: record.partialId && record.partialName ? {
           id: record.partialId,
           name: record.partialName
         } : null
@@ -220,7 +219,33 @@ export async function GET(request: NextRequest) {
       else if (record.status === 'late') acc[key].summary.late++
       
       return acc
-    }, {} as Record<string, any>)
+    }, {} as Record<string, {
+      classInfo: {
+        id: string;
+        name: string;
+        code: string;
+      };
+      sectionInfo: {
+        id: string;
+        name: string;
+      };
+      records: Array<{
+        id: string;
+        date: string;
+        status: string;
+        reason: string | null;
+        partial: {
+          id: string;
+          name: string;
+        } | null;
+      }>;
+      summary: {
+        total: number;
+        present: number;
+        absent: number;
+        late: number;
+      };
+    }>)
 
     const attendanceByClass = Object.values(groupedRecords)
 

+ 1 - 1
src/app/student/attendance/page.tsx

@@ -51,7 +51,7 @@ export default function StudentAttendancePage() {
               </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.
+                La página de &quot;Mi Asistencia&quot; está en desarrollo. Aquí podrás ver tu historial completo de asistencia, estadísticas por materia, y reportes detallados.
               </p>
             </div>
           </CardContent>

+ 1 - 1
src/app/student/classes/page.tsx

@@ -51,7 +51,7 @@ export default function StudentClassesPage() {
               </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.
+                La página de &quot;Mis Clases&quot; está en desarrollo. Aquí podrás ver información detallada sobre tus materias, horarios de clase, y recursos académicos.
               </p>
             </div>
           </CardContent>

+ 1 - 1
src/app/student/schedule/page.tsx

@@ -51,7 +51,7 @@ export default function StudentSchedulePage() {
               </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.
+                La página de &quot;Horarios&quot; está en desarrollo. Aquí podrás ver tu horario semanal de clases, horarios de profesores, y calendario académico.
               </p>
             </div>
           </CardContent>

+ 1 - 1
src/app/teacher/dashboard/page.tsx

@@ -2,7 +2,7 @@ import { getServerSession } from 'next-auth'
 import { authOptions } from '@/lib/auth'
 import { redirect } from 'next/navigation'
 import { db } from '@/lib/db'
-import { teacherAssignments, sections, classes, periods, studentEnrollments, attendance, eq, and } from '@/lib/db/schema'
+import { teacherAssignments, sections, classes, periods, studentEnrollments, attendance, eq } from '@/lib/db/schema'
 import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
 import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
 import { Badge } from '@/components/ui/badge'

+ 1 - 1
src/app/teacher/page.tsx

@@ -2,7 +2,7 @@ import { getServerSession } from 'next-auth'
 import { authOptions } from '@/lib/auth'
 import { redirect } from 'next/navigation'
 import { db } from '@/lib/db'
-import { teacherAssignments, sections, classes, periods, studentEnrollments, attendance, eq, and } from '@/lib/db/schema'
+import { teacherAssignments, sections, classes, periods, studentEnrollments, attendance, eq } from '@/lib/db/schema'
 import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
 import { BookOpen, Users, ClipboardCheck, Calendar } from 'lucide-react'
 import { DashboardLayout } from '@/components/dashboard-layout'

+ 1 - 1
src/app/teacher/student-attendance/page.tsx

@@ -2,7 +2,7 @@
 
 import { useState, useEffect } from 'react'
 import { DashboardLayout } from '@/components/dashboard-layout'
-import { Button } from '@/components/ui/button'
+// Button import removed as it's not currently used
 import { Input } from '@/components/ui/input'
 import { Label } from '@/components/ui/label'
 import {

+ 1 - 1
src/app/teacher/students/page.tsx

@@ -2,7 +2,7 @@
 
 import { useState, useEffect } from 'react'
 import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
-import { Button } from '@/components/ui/button'
+// Button import removed as it's not currently used
 import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
 import { Input } from '@/components/ui/input'
 import { Badge } from '@/components/ui/badge'

+ 1 - 3
src/components/app-sidebar.tsx

@@ -30,7 +30,7 @@ import {
   SidebarMenuItem,
   SidebarRail,
 } from "@/components/ui/sidebar"
-import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
+// Avatar components removed as they're not currently used
 import { Button } from "@/components/ui/button"
 import { signOut } from "next-auth/react"
 import Link from "next/link"
@@ -216,9 +216,7 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
 
   const isAdmin = session.user.role === "admin"
   const isTeacher = session.user.role === "teacher"
-  const isStudent = session.user.role === "student"
   const menuSections = isAdmin ? adminMenuSections : isTeacher ? teacherMenuSections : studentMenuSections
-  const userInitials = session.user.firstName?.[0] + (session.user.lastName?.[0] || "")
 
   return (
     <Sidebar collapsible="icon" {...props}>

+ 9 - 2
src/lib/auth.ts

@@ -1,11 +1,11 @@
 import { NextAuthOptions } from 'next-auth';
 import CredentialsProvider from 'next-auth/providers/credentials';
 import { DrizzleAdapter } from '@auth/drizzle-adapter';
+import type { Adapter } from 'next-auth/adapters';
 import { db } from './db';
 import { users } from './db/schema';
 import { eq } from 'drizzle-orm';
 import bcrypt from 'bcryptjs';
-import type { Adapter } from 'next-auth/adapters';
 
 export const authOptions: NextAuthOptions = {
   adapter: DrizzleAdapter(db) as Adapter,
@@ -46,6 +46,8 @@ export const authOptions: NextAuthOptions = {
             email: user[0].email,
             name: `${user[0].firstName} ${user[0].lastName}`,
             role: user[0].role,
+            firstName: user[0].firstName,
+            lastName: user[0].lastName,
           };
         } catch (error) {
           console.error('Auth error:', error);
@@ -60,14 +62,19 @@ export const authOptions: NextAuthOptions = {
   callbacks: {
     async jwt({ token, user }) {
       if (user) {
+        token.id = user.id;
         token.role = user.role;
+        token.firstName = user.firstName;
+        token.lastName = user.lastName;
       }
       return token;
     },
     async session({ session, token }) {
       if (token) {
-        session.user.id = token.sub!;
+        session.user.id = token.id as string;
         session.user.role = token.role as string;
+        if (token.firstName) session.user.firstName = token.firstName as string;
+        if (token.lastName) session.user.lastName = token.lastName as string;
       }
       return session;
     },

+ 2 - 2
src/lib/db/index.ts

@@ -5,8 +5,8 @@ import { drizzle } from 'drizzle-orm/postgres-js';
 import postgres from 'postgres';
 import * as schema from './schema';
 
-// Ensure postgres is properly imported
-const postgresClient = postgres || require('postgres');
+// Use postgres client
+const postgresClient = postgres;
 
 if (!process.env.DATABASE_URL) {
   throw new Error('DATABASE_URL is not defined');

+ 7 - 7
src/lib/db/seed.ts

@@ -9,7 +9,7 @@ export async function seedDatabase() {
     // Crear usuario administrador
     const hashedPassword = await bcrypt.hash('admin123', 10);
     
-    const [admin] = await db.insert(users).values({
+    await db.insert(users).values({
       email: 'admin@universidad.edu',
       password: hashedPassword,
       firstName: 'Administrador',
@@ -27,19 +27,19 @@ export async function seedDatabase() {
     }).returning();
 
     // Crear parciales
-    const [partial1] = await db.insert(partials).values({
+    await db.insert(partials).values({
       name: 'Primer Parcial',
       periodId: period.id,
       startDate: '2024-09-01',
       endDate: '2024-11-15',
-    }).returning();
+    });
 
-    const [partial2] = await db.insert(partials).values({
+    await db.insert(partials).values({
       name: 'Segundo Parcial',
       periodId: period.id,
       startDate: '2024-11-16',
       endDate: '2025-02-15',
-    }).returning();
+    });
 
     // Crear clases
     const [class1] = await db.insert(classes).values({
@@ -69,11 +69,11 @@ export async function seedDatabase() {
       maxStudents: 25,
     }).returning();
 
-    const [section2A] = await db.insert(sections).values({
+    await db.insert(sections).values({
       name: 'A',
       classId: class2.id,
       maxStudents: 35,
-    }).returning();
+    });
 
     // Crear profesor
     const teacherPassword = await bcrypt.hash('teacher123', 10);

+ 5 - 2
src/types/next-auth.d.ts

@@ -1,4 +1,4 @@
-import NextAuth from 'next-auth';
+import 'next-auth';
 
 declare module 'next-auth' {
   interface Session {
@@ -26,6 +26,9 @@ declare module 'next-auth' {
 
 declare module 'next-auth/jwt' {
   interface JWT {
-    role: string;
+    id?: string;
+    role?: string;
+    firstName?: string;
+    lastName?: string;
   }
 }