diff --git a/.github/workflows/run_test.yml b/.github/workflows/run_test.yml index 5cf94fac..17598f95 100644 --- a/.github/workflows/run_test.yml +++ b/.github/workflows/run_test.yml @@ -4,9 +4,13 @@ on: push: branches: - main + - develop + - staging pull_request: branches: - main + - develop + - staging jobs: test: diff --git a/README.md b/README.md index f1d78cb4..22b5e085 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,7 @@ Para un entorno de producción se requiere una base de datos real provisionada ( 1. Crea y configura el archivo `.env` con las variables reales de producción. 2. Construye el proyecto e inicia el servidor en modo producción: + ```bash npm run prod ``` diff --git a/apps/api/src/assistance-applications/assistance-applications.controller.ts b/apps/api/src/assistance-applications/assistance-applications.controller.ts index e1c1a88d..c08a1a0c 100644 --- a/apps/api/src/assistance-applications/assistance-applications.controller.ts +++ b/apps/api/src/assistance-applications/assistance-applications.controller.ts @@ -71,7 +71,7 @@ export class AssistanceApplicationsController { @Get(':id/document') findOneDocument(@Param('id') id: string) { - return this.assistanceApplicationsService.findOneDocument(id); + return this.assistanceApplicationsService.findOne(id, true); } @Patch(':id') diff --git a/apps/api/src/assistance-applications/assistance-applications.service.ts b/apps/api/src/assistance-applications/assistance-applications.service.ts index 7c713fd7..baa376da 100644 --- a/apps/api/src/assistance-applications/assistance-applications.service.ts +++ b/apps/api/src/assistance-applications/assistance-applications.service.ts @@ -69,7 +69,7 @@ export class AssistanceApplicationsService { return results; } - async findOne(id: string) { + async findOne(id: string, withDocument: boolean = false) { const application = await this.assistanceApplicationRepository.findOne({ where: { id }, relations: { @@ -77,26 +77,7 @@ export class AssistanceApplicationsService { professor: true, }, student: true, - document: true, - }, - }); - if (!application) { - throw new NotFoundException( - `Assistance Application with ID ${id} not found`, - ); - } - return application; - } - - async findOneDocument(id: string) { - const application = await this.assistanceApplicationRepository.findOne({ - where: { id }, - relations: { - graduatedAssistance: { - professor: true, - }, - student: true, - document: true, + document: withDocument, }, }); if (!application) { diff --git a/apps/api/src/billboards/billboards.service.ts b/apps/api/src/billboards/billboards.service.ts index 7261ecec..9fce0c9f 100644 --- a/apps/api/src/billboards/billboards.service.ts +++ b/apps/api/src/billboards/billboards.service.ts @@ -11,6 +11,7 @@ import { CoursesService } from '../courses/courses.service'; import { SectionsService } from '../sections/sections.service'; import { ProfessorsService } from '../professors/professors.service'; import { Professor } from '../professors/entities/professor.entity'; +import { Period } from '../periods/entities/period.entity'; @Injectable() export class BillboardsService { @@ -24,166 +25,190 @@ export class BillboardsService { private readonly professorService: ProfessorsService, ) {} - async create(sectionsDto: CreateSectionDto[]) { - const billboardCoursesMap = new Map(); + async getOrCreatePeriodBySectionDto(sectionDto: CreateSectionDto) { + const mapPeriod = (raw: string) => (raw.startsWith('1') ? '10' : '20'); + const year = Number(sectionDto.period.slice(0, 4)); + const semester = sectionDto.period.slice(4, 5); + const rawPeriod = sectionDto.period.slice(4, 6); + const periodStr = mapPeriod(rawPeriod); - const normalizeName = (name: string) => - name.toLowerCase().trim().replace(/\s+/g, ' '); + let foundPeriod = await this.periodsService.findOneByPeriodAndYear( + periodStr, + year, + ); - const mapPeriod = (raw: string) => (raw.startsWith('1') ? '10' : '20'); + foundPeriod ??= await this.periodsService.create({ + period: periodStr, + year: year, + semester: semester === '1' ? 1 : 2, + }); - for (const section of sectionsDto) { - const year = Number(section.period.slice(0, 4)); - const semester = section.period.slice(4, 5); - const rawPeriod = section.period.slice(4, 6); - const periodStr = mapPeriod(rawPeriod); - - let periodFound = await this.periodsService.findOneByPeriodAndYear( - periodStr, - year, - ); - if (!periodFound) { - periodFound = await this.periodsService.create({ - period: periodStr, - year: year, - semester: semester === '1' ? 1 : 2, - }); - } - if (!periodFound) { - throw new Error('Period not found'); - } + return foundPeriod; + } - let existingCourse = await this.courseService.findByCodeAndPeriod( - section.code, - periodFound, + async getOrCreateSectionBySectionDto( + sectionDto: CreateSectionDto, + period: Period, + foundProfessors: Professor[], + supportProfessors: Professor[], + ) { + const existingSection = await this.sectionService.findByNRCAndPeriod( + sectionDto.NRC, + period, + ); + + let sectionToUse: Section; + if (existingSection != null) { + sectionToUse = await this.sectionService.updateProfessorsSection( + existingSection, + foundProfessors, + supportProfessors, ); - const existingSection = await this.sectionService.findByNRCAndPeriod( - section.NRC, - periodFound, + } else { + const newSectionDto = new CreateSectionDto(); + newSectionDto.NRC = sectionDto.NRC; + newSectionDto.section = sectionDto.section; + if (foundProfessors.length === 0 && supportProfessors.length === 0) { + throw new Error('No professors found for the section'); + } + sectionToUse = await this.sectionService.create( + newSectionDto, + supportProfessors, + foundProfessors, + period, ); + } + return sectionToUse; + } - if (section.professors != null && section.professors !== '') { - const professorsArr = section.professors.split('|'); - const supportProfessors: Professor[] = []; - const findedProfessors: Professor[] = []; - - await Promise.all( - professorsArr.map(async (prof) => { - const cleanedName = cleanName(prof); - const searchProfessor = await this.professorService.findByName( - normalizeName(cleanedName), - ); - if (searchProfessor) { - if (/\(01\)/.test(prof)) { - if ( - !findedProfessors.find( - (p) => p.user.id === searchProfessor.user.id, - ) - ) { - findedProfessors.push(searchProfessor); - } - } else if (/\(02\)/.test(prof)) { - if ( - !supportProfessors.find( - (p) => p.user.id === searchProfessor.user.id, - ) - ) { - supportProfessors.push(searchProfessor); - } - } - } - }), + async getOrCreateCourseBySectionDto( + sectionDto: CreateSectionDto, + period: Period, + sectionToUse: Section, + ) { + let existingCourse = await this.courseService.findByCodeAndPeriod( + sectionDto.code, + period, + ); + if (existingCourse) { + const sectionAlreadyIncluded = existingCourse.sections?.some( + (sec) => sec.NRC === sectionToUse.NRC, + ); + if (!sectionAlreadyIncluded) { + existingCourse = await this.courseService.updateSections( + sectionToUse, + existingCourse, ); + } + } else { + const courseDto = new CreateCourseDto(); + courseDto.code = sectionDto.code; + courseDto.credits = +sectionDto.credits; + courseDto.departament = sectionDto.departament; + courseDto.name = sectionDto.name; + existingCourse = await this.courseService.create(courseDto, sectionToUse); + } + return existingCourse; + } - let sectionToUse: Section; - if (existingSection != null) { - sectionToUse = await this.sectionService.updateProfessorsSection( - existingSection, - findedProfessors, - supportProfessors, - ); - } else { - const newSectionDto = new CreateSectionDto(); - newSectionDto.NRC = section.NRC; - newSectionDto.section = section.section; - if (findedProfessors.length === 0 && supportProfessors.length === 0) { - throw new Error('No professors found for the section'); - } - sectionToUse = await this.sectionService.create( - newSectionDto, - supportProfessors, - findedProfessors, - periodFound, - ); - } + async getProfessors(section: CreateSectionDto) { + const normalizeName = (name: string) => + name.toLowerCase().trim().replace(/\s+/g, ' '); + const professorsArr = section.professors.split('|'); + const supportProfessors: Professor[] = []; + const foundProfessors: Professor[] = []; - if (existingCourse) { - const sectionAlreadyIncluded = existingCourse.sections?.some( - (sec) => sec.NRC === sectionToUse.NRC, - ); - if (!sectionAlreadyIncluded) { - existingCourse = await this.courseService.updateSections( - sectionToUse, - existingCourse, - ); + await Promise.all( + professorsArr.map(async (prof) => { + const cleanedName = cleanName(prof); + const searchProfessor = await this.professorService.findByName( + normalizeName(cleanedName), + ); + if (searchProfessor) { + if (/\(01\)/.test(prof)) { + if ( + !foundProfessors.find( + (p) => p.user.id === searchProfessor.user.id, + ) + ) { + foundProfessors.push(searchProfessor); + } + } else if (/\(02\)/.test(prof)) { + if ( + !supportProfessors.find( + (p) => p.user.id === searchProfessor.user.id, + ) + ) { + supportProfessors.push(searchProfessor); + } } - billboardCoursesMap.set(existingCourse.code, existingCourse); - } else { - const courseDto = new CreateCourseDto(); - courseDto.code = section.code; - courseDto.credits = +section.credits; - courseDto.departament = section.departament; - courseDto.name = section.name; - existingCourse = await this.courseService.create( - courseDto, - sectionToUse, - ); - billboardCoursesMap.set(section.code, existingCourse); } + }), + ); + return [supportProfessors, foundProfessors]; + } + + async mergeCourses(billboardExisting: Billboard, billboard: Billboard) { + const combinedCourses = [ + ...billboardExisting.courses, + ...billboard.courses, + ]; + const uniqueCoursesMap = new Map( + combinedCourses.map((course) => [course.code, course]), + ); + billboardExisting.courses = Array.from(uniqueCoursesMap.values()); + + billboardExisting.period = billboard.period; + billboardExisting.publicated = true; + await this.billboardRepository.save(billboardExisting); + return billboardExisting; + } + + async getBillboardFromSectionsDto(sectionsDto: CreateSectionDto[]) { + const billboard: Billboard = new Billboard(); + const billboardCoursesMap = new Map(); + + for (const section of sectionsDto) { + const foundPeriod = await this.getOrCreatePeriodBySectionDto(section); + if (section.professors != null && section.professors !== '') { + const [supportProfessors, foundProfessors] = + await this.getProfessors(section); + + const sectionToUse = await this.getOrCreateSectionBySectionDto( + section, + foundPeriod, + foundProfessors, + supportProfessors, + ); + + const existingCourse = await this.getOrCreateCourseBySectionDto( + section, + foundPeriod, + sectionToUse, + ); + + billboardCoursesMap.set(existingCourse.code, existingCourse); } } - const firstsection = sectionsDto[0]; - const billboardYear = Number(firstsection.period.slice(0, 4)); - const firstRawPeriod = firstsection.period.slice(4, 6); - const firstPeriodStr = mapPeriod(firstRawPeriod); - - let periodForBillboard = await this.periodsService.findOneByPeriodAndYear( - firstPeriodStr, - billboardYear, + const periodForBillboard = await this.getOrCreatePeriodBySectionDto( + sectionsDto[0], ); - if (!periodForBillboard) { - periodForBillboard = await this.periodsService.create({ - period: firstPeriodStr, - year: billboardYear, - semester: firstsection.period.slice(4, 5) === '1' ? 1 : 2, - }); - } - const billboard: Billboard = new Billboard(); billboard.publicated = true; billboard.period = periodForBillboard; billboard.courses = Array.from(billboardCoursesMap.values()); + return billboard; + } - const billboardExisting = await this.findOne( + async create(sectionsDto: CreateSectionDto[]) { + const billboard = await this.getBillboardFromSectionsDto(sectionsDto); + const existingBillboard = await this.findOne( billboard.period.year + billboard.period.period, ); - if (billboardExisting) { - const combinedCourses = [ - ...billboardExisting.courses, - ...billboard.courses, - ]; - const uniqueCoursesMap = new Map( - combinedCourses.map((course) => [course.code, course]), - ); - billboardExisting.courses = Array.from(uniqueCoursesMap.values()); - - billboardExisting.period = billboard.period; - billboardExisting.publicated = true; - await this.billboardRepository.save(billboardExisting); - return billboardExisting; + if (existingBillboard) { + return await this.mergeCourses(existingBillboard, billboard); } - return await this.billboardRepository.save(billboard); } diff --git a/apps/api/src/graduated-assistances/graduated-assistances.service.ts b/apps/api/src/graduated-assistances/graduated-assistances.service.ts index f430b9f9..e7b9178f 100644 --- a/apps/api/src/graduated-assistances/graduated-assistances.service.ts +++ b/apps/api/src/graduated-assistances/graduated-assistances.service.ts @@ -2,7 +2,7 @@ import { Injectable, NotFoundException } from '@nestjs/common'; import { CreateGraduatedAssistanceDto } from './dto/create-graduated-assistance.dto'; import { UpdateGraduatedAssistanceDto } from './dto/update-graduated-assistance.dto'; import { GraduatedAssistance } from './entities/graduated-assistance.entity'; -import { In, Repository } from 'typeorm'; +import { Repository } from 'typeorm'; import { InjectRepository } from '@nestjs/typeorm'; import { PeriodsService } from '../periods/periods.service'; import { RequirementsService } from '../requirements/requirements.service'; diff --git a/apps/api/src/periods/periods.service.ts b/apps/api/src/periods/periods.service.ts index bef66e19..58409e5e 100644 --- a/apps/api/src/periods/periods.service.ts +++ b/apps/api/src/periods/periods.service.ts @@ -51,7 +51,6 @@ export class PeriodsService { async findCurrentPeriod(): Promise { const periods = await this.periodRepository.find(); - if (periods.length === 0) { throw new Error('No periods found'); } @@ -71,13 +70,19 @@ export class PeriodsService { return current; } return prev; - }); + }, periods[0]); return currentPeriod; } async findOneByPeriodAndYear(period: string, year: number) { - return await this.periodRepository.findOne({ where: { period, year } }); + const periodFound = await this.periodRepository.findOne({ + where: { period, year }, + }); + if (!periodFound) { + throw new PreconditionFailedException('Periodo no encontrado'); + } + return periodFound; } async findOneByPeriodAndYearString(periodStr: string) { @@ -86,11 +91,7 @@ export class PeriodsService { } const yearInt = Number(periodStr.slice(0, 4)); const periodInt = periodStr.slice(4); - const period = await this.findOneByPeriodAndYear(periodInt, yearInt); - if (!period) { - throw new PreconditionFailedException('Periodo no encontrado'); - } - return period; + return await this.findOneByPeriodAndYear(periodInt, yearInt); } update(id: number, updatePeriodDto: UpdatePeriodDto) { diff --git a/apps/api/src/project-applications/project-applications.service.ts b/apps/api/src/project-applications/project-applications.service.ts index 74643603..7f93afec 100644 --- a/apps/api/src/project-applications/project-applications.service.ts +++ b/apps/api/src/project-applications/project-applications.service.ts @@ -53,14 +53,13 @@ export class ProjectApplicationsService { `Estudiante con documento ${studentId} no encontrado`, ); } - const hasActive = await this.projectApplicationRepository.exist({ + const hasActive = await this.projectApplicationRepository.exists({ where: { student: { id: studentId }, period: { id: period.id }, status: Not(ProjecStatusEnum.REJECTED), }, }); - if (hasActive) { throw new ConflictException( 'El estudiante ya tiene una aplicación activa en este periodo', @@ -78,11 +77,11 @@ export class ProjectApplicationsService { let coordinator; - coordinators.map((c) => { + for (const c of coordinators) { if (c.isActive) { coordinator = c; } - }); + } const task = await this.tasksService.create(TaskType.SEND_APPROVE, { flow: 'proyectoPregrado', diff --git a/apps/api/src/projects/projects.service.ts b/apps/api/src/projects/projects.service.ts index 3fed96e2..760507b8 100644 --- a/apps/api/src/projects/projects.service.ts +++ b/apps/api/src/projects/projects.service.ts @@ -111,7 +111,6 @@ export class ProjectsService { if (!project) { throw new NotFoundException(`Project with id ${id} not found`); } - console.debug(JSON.stringify(project)); return project; } diff --git a/apps/api/src/tasks/factory/tasks.factory.ts b/apps/api/src/tasks/factory/tasks.factory.ts index 70625cb8..6c9b7ab1 100644 --- a/apps/api/src/tasks/factory/tasks.factory.ts +++ b/apps/api/src/tasks/factory/tasks.factory.ts @@ -50,13 +50,13 @@ export class TaskFactory { dto.documentId = ''; return dto; - case TaskType.SEND_APPROVE || - TaskType.VIEW_COMMENTS || - TaskType.SEND_COMMENTS: + case TaskType.SEND_APPROVE: + case TaskType.VIEW_COMMENTS: + case TaskType.SEND_COMMENTS: return dto; default: - throw new BadRequestException(`Tipo de tarea desconocido: ${type}`); + throw new BadRequestException(`Tipo de tarea desconocido`); } } } diff --git a/apps/web/src/app/auth/session/route.ts b/apps/web/src/app/auth/session/route.ts index 695f8d5f..363f41ec 100644 --- a/apps/web/src/app/auth/session/route.ts +++ b/apps/web/src/app/auth/session/route.ts @@ -34,8 +34,8 @@ export async function POST(request: NextRequest) { const userData = await response.json(); const token = userData.access_token; // Use the backend JWT token - console.log("ACCESS TOKEN" + token.toString()); + /* Set the token as an HTTP-only cookie */ (await cookies()).set({ name: "auth-token", diff --git a/apps/web/src/app/inicio/administrador/incidencia/page.tsx b/apps/web/src/app/inicio/administrador/incidencia/page.tsx index c7484c93..3dc0a2d6 100644 --- a/apps/web/src/app/inicio/administrador/incidencia/page.tsx +++ b/apps/web/src/app/inicio/administrador/incidencia/page.tsx @@ -104,7 +104,7 @@ function ActionCell({ incidence }: { readonly incidence: Incidence }) { const [isClosing, setIsClosing] = useState(false); const queryClient = useQueryClient(); - const completed = incidence.isClosed || isClosing; + const completed = incidence.isClosed? true: isClosing; const handleClose = async () => { setIsClosing(true); diff --git a/apps/web/src/app/inicio/administrador/lider/page.tsx b/apps/web/src/app/inicio/administrador/lider/page.tsx index 0ef9befe..f153bc64 100644 --- a/apps/web/src/app/inicio/administrador/lider/page.tsx +++ b/apps/web/src/app/inicio/administrador/lider/page.tsx @@ -59,11 +59,11 @@ export default function CourseList() { oldData?.map((course) => course.courseId === row.original.courseId ? { - ...course, - professorId: newProfessor.id, - professorName: newProfessor.name, - email: newProfessor.email, - } + ...course, + professorId: newProfessor.id, + professorName: newProfessor.name, + email: newProfessor.email, + } : course ) ?? [] ); @@ -75,7 +75,6 @@ export default function CourseList() { if (isFetching) return ; if (isError) return ; - return (
@@ -93,7 +92,6 @@ function ProfessorListPopover({ onAssigned, }: { readonly courseId: string; - readonly currentProfessorId?: string; readonly onAssigned?: (newProfessor: User) => void; }) { const [open, setOpen] = useState(false); @@ -108,7 +106,7 @@ function ProfessorListPopover({ const filtered = data?.filter((prof: User) => prof.name.toLowerCase().includes(search.toLowerCase()) - ); + ) ?? []; const handleAssign = async (professor: User) => { try { @@ -142,13 +140,14 @@ function ProfessorListPopover({ No se encontraron profesores. ) : ( - filtered?.map((prof: User) => ( -
  • handleAssign(prof)} - className="cursor-pointer hover:bg-core-highlight px-2 py-1 rounded-md text-sm" - > - {prof.name} + filtered.map((prof: User) => ( +
  • +
  • )) )} diff --git a/apps/web/src/app/inicio/administrador/usuario/page.tsx b/apps/web/src/app/inicio/administrador/usuario/page.tsx index abe84b89..045d3290 100644 --- a/apps/web/src/app/inicio/administrador/usuario/page.tsx +++ b/apps/web/src/app/inicio/administrador/usuario/page.tsx @@ -49,7 +49,7 @@ const columns: ColumnDef[] = [ return (
    {(roles ?? []).map((role: string) => { - const colorClasses = roleColorMap[role] || "bg-gray-100 text-gray-800 border border-gray-800"; + const colorClasses = roleColorMap[role] ?? "bg-gray-100 text-gray-800 border border-gray-800"; return ( state.userId); diff --git a/apps/web/src/app/inicio/components/information-section.tsx b/apps/web/src/app/inicio/components/information-section.tsx index 070cb120..821a7bba 100644 --- a/apps/web/src/app/inicio/components/information-section.tsx +++ b/apps/web/src/app/inicio/components/information-section.tsx @@ -105,7 +105,7 @@ export function InformationCard({
    {/* Icon container */}
    -
    {/* Title and description */}
    diff --git a/apps/web/src/app/inicio/components/professor-features.tsx b/apps/web/src/app/inicio/components/professor-features.tsx index af2590f5..3ba73b6c 100644 --- a/apps/web/src/app/inicio/components/professor-features.tsx +++ b/apps/web/src/app/inicio/components/professor-features.tsx @@ -25,7 +25,7 @@ export default function ProfessorFeatures({ }) { // List of professor-related feature titles to be displayed const professorFeatures = [ - "Proyecto de pregrado", + "Proyecto de grado", "Proyecto de maestría", "Asistencias graduadas", "Monitores", diff --git a/apps/web/src/app/inicio/coordinador/cartelera/page.tsx b/apps/web/src/app/inicio/coordinador/cartelera/page.tsx index 4a5b974c..e00c6667 100644 --- a/apps/web/src/app/inicio/coordinador/cartelera/page.tsx +++ b/apps/web/src/app/inicio/coordinador/cartelera/page.tsx @@ -44,7 +44,6 @@ export default function UploadBillboard() { if (!worksheet) { setLoadError(true); - return; } }; const handlePeriodChange = (value: string) => { diff --git a/apps/web/src/app/inicio/coordinador/programas/lista/page.tsx b/apps/web/src/app/inicio/coordinador/programas/lista/page.tsx index c0b0e6b9..39e46261 100644 --- a/apps/web/src/app/inicio/coordinador/programas/lista/page.tsx +++ b/apps/web/src/app/inicio/coordinador/programas/lista/page.tsx @@ -76,7 +76,7 @@ export default function ProgramsList() {
    - Listado de Programas + Listado de Programas
    diff --git a/apps/web/src/app/inicio/estudiante/asistencia/lista/[id]/page.tsx b/apps/web/src/app/inicio/estudiante/asistencia/lista/[id]/page.tsx index 40894470..332dd37c 100644 --- a/apps/web/src/app/inicio/estudiante/asistencia/lista/[id]/page.tsx +++ b/apps/web/src/app/inicio/estudiante/asistencia/lista/[id]/page.tsx @@ -535,19 +535,18 @@ function UploadCV({

    -
    { if (event.key === "Enter" || event.key === " ") { - event.preventDefault(); + event.preventDefault(); // opcional con
    )} -
    +
    ); } diff --git a/apps/web/src/app/inicio/estudiante/asistencia/lista_aplicadas/[id]/page.tsx b/apps/web/src/app/inicio/estudiante/asistencia/lista_aplicadas/[id]/page.tsx index 8102ec48..432556c9 100644 --- a/apps/web/src/app/inicio/estudiante/asistencia/lista_aplicadas/[id]/page.tsx +++ b/apps/web/src/app/inicio/estudiante/asistencia/lista_aplicadas/[id]/page.tsx @@ -5,7 +5,7 @@ import { StatusInformation } from "@/app/types/entities/graduated-assistance.typ import TabStatus, { SectionProps } from "@/components/shared/tab-status"; import { useRouter } from "next/navigation"; import SpinnerPage from "@/components/shared/spinner-page"; -import { getAssistanceStatusById } from "@/app/services/assistance.service"; +import { getAssistanceStatusByIdWithDocument } from "@/app/services/assistance.service"; /** * AssistanceStatus Component @@ -78,7 +78,7 @@ export default function AssistanceStatus({ const fetchData = async () => { if (!id) return router.push("/404"); try { - const data = await getAssistanceStatusById(id); + const data = await getAssistanceStatusByIdWithDocument(id); setStatusInformation(data); setIsLoading(false); } catch { diff --git a/apps/web/src/app/inicio/estudiante/asistencia/lista_aplicadas/page.tsx b/apps/web/src/app/inicio/estudiante/asistencia/lista_aplicadas/page.tsx index c16f99b8..b3fdd48e 100644 --- a/apps/web/src/app/inicio/estudiante/asistencia/lista_aplicadas/page.tsx +++ b/apps/web/src/app/inicio/estudiante/asistencia/lista_aplicadas/page.tsx @@ -1,51 +1,19 @@ "use client"; import * as React from "react"; -import { - ColumnDef, - SortingState, - flexRender, - getCoreRowModel, - getFilteredRowModel, - getPaginationRowModel, - getSortedRowModel, - useReactTable, -} from "@tanstack/react-table"; -import { Search } from "lucide-react"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; -import { StatusInformation } from "@/app/types/entities/graduated-assistance.type"; import Link from "next/link"; -import { ROUTES } from "@/app/routes"; -import SpinnerPage from "@/components/shared/spinner-page"; -import { getAssistanceApplications } from "@/app/services/assistance.service"; -import { useEffect } from "react"; -import { useAuth } from "@/hooks/use-auth"; +import { useEffect, useMemo, useState } from "react"; +import { Search } from "lucide-react"; import { useQuery } from "@tanstack/react-query"; +import { getAssistanceApplications } from "@/app/services/assistance.service"; import { getPeriods } from "@/app/services/period.service"; +import { useAuth } from "@/hooks/use-auth"; +import SpinnerPage from "@/components/shared/spinner-page"; +import { ROUTES } from "@/app/routes"; +import { StatusInformation } from "@/app/types/entities/graduated-assistance.type"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { DataTable } from "@/components/data-table"; +import type { ColumnDef } from "@tanstack/react-table"; -/** - * Column definitions for the AssistanceAppliedList table - * - * Defines the structure and behavior of each column in the table, - * including custom cell rendering for dates and the "Ver" (View) column. - * - * @type {ColumnDef[]} - */ const columns: ColumnDef[] = [ { id: "title", @@ -54,7 +22,7 @@ const columns: ColumnDef[] = [ }, { accessorKey: "graduatedAssistance.category", - header: "Clasificacion", + header: "Clasificación", }, { accessorKey: "graduatedAssistance.professor.user.name", @@ -62,7 +30,7 @@ const columns: ColumnDef[] = [ }, { accessorKey: "graduatedAssistance.startDate", - header: "Fecha de Inscripcion", + header: "Fecha de Inscripción", cell: ({ getValue }) => { const dateStr = getValue() as string; const date = new Date(dateStr); @@ -76,41 +44,23 @@ const columns: ColumnDef[] = [ { id: "ver", header: "Ver", - cell: ({ row }) => { - return ( - - - - ); - }, + cell: ({ row }) => ( + + + + ), }, ]; -/** - * AssistanceAppliedList Component - * - * Displays a table of applied graduate assistances with filtering, sorting, and pagination capabilities. - * - * Features: - * - Fetches and displays assistance application data - * - Allows filtering by semester - * - Provides search functionality by assistance name - * - Supports column visibility toggling - * - Implements table sorting and pagination - * - * @returns {JSX.Element} A div containing the assistance applied list table and its controls - */ export default function AssistanceAppliedList() { - const [isLoading, setIsLoading] = React.useState(true); - const [sorting, setSorting] = React.useState([]); - const [data, setData] = React.useState([]); - const [selectedSemester, setSelectedSemester] = React.useState(""); + const [isLoading, setIsLoading] = useState(true); + const [data, setData] = useState([]); + const [selectedSemester, setSelectedSemester] = useState(""); const { user, isLoading: isAuthLoading } = useAuth(); - const { data: semesters, isLoading: isLoadingSemesters } = useQuery({ queryKey: ["undergraduate-semesters"], queryFn: getPeriods, @@ -118,11 +68,10 @@ export default function AssistanceAppliedList() { useEffect(() => { const fetchData = async () => { + if (!user?.id) return; try { - if (!user?.id) return; - const userId = user?.id; - const assistanceData = await getAssistanceApplications(userId); - setData(assistanceData); + const result = await getAssistanceApplications(user.id); + setData(result); } catch (error) { console.error("Error fetching assistance data:", error); } finally { @@ -130,12 +79,10 @@ export default function AssistanceAppliedList() { } }; - if (!isAuthLoading) { - fetchData(); - } + if (!isAuthLoading) fetchData(); }, [isAuthLoading, user]); - const filteredData = React.useMemo(() => { + const filteredData = useMemo(() => { if (!selectedSemester) return data; return data.filter((item) => { @@ -143,25 +90,10 @@ export default function AssistanceAppliedList() { const year = date.getFullYear(); const month = date.getMonth() + 1; const semester = month <= 6 ? "10" : "20"; - const formattedSemester = `${year}${semester}`; - - return formattedSemester === selectedSemester; + return `${year}${semester}` === selectedSemester; }); }, [selectedSemester, data]); - const table = useReactTable({ - data: filteredData, - columns, - onSortingChange: setSorting, - getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), - getSortedRowModel: getSortedRowModel(), - getFilteredRowModel: getFilteredRowModel(), - state: { - sorting, - }, - }); - if (isLoading || isLoadingSemesters) { return ; } @@ -169,120 +101,26 @@ export default function AssistanceAppliedList() { return (
    -
    -
    -
    - -
    -
    -
    - - - table.getColumn("title")?.setFilterValue(event.target.value) - } - /> -
    -
    -
    - -
    - - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef.header, - header.getContext() - )} - - ); - })} - +
    +
    -
    -
    -
    - - -
    -
    + +
    + +
    ); diff --git a/apps/web/src/app/inicio/maestria/page.tsx b/apps/web/src/app/inicio/maestria/page.tsx index 70d9564a..9d926781 100644 --- a/apps/web/src/app/inicio/maestria/page.tsx +++ b/apps/web/src/app/inicio/maestria/page.tsx @@ -82,7 +82,7 @@ export default function StudyPlanForm() { if (!student) return

    student not found

    ; return ( -
    +
    diff --git a/apps/web/src/app/inicio/page.tsx b/apps/web/src/app/inicio/page.tsx index 10850501..62005da4 100644 --- a/apps/web/src/app/inicio/page.tsx +++ b/apps/web/src/app/inicio/page.tsx @@ -87,8 +87,8 @@ export default function Home() { return { ...task, step: stepNumber, - title: stepInfo?.title || "Sin título", - description: stepInfo?.description || "Sin descripción", + title: stepInfo?.title ?? "Sin título", + description: stepInfo?.description ?? "Sin descripción", date: task.date ? new Date(task.date) : new Date(), }; }); diff --git a/apps/web/src/app/inicio/posgrado/tesis/lista/[id]/page.tsx b/apps/web/src/app/inicio/posgrado/tesis/lista/[id]/page.tsx index 0ff05dd0..c0562c7e 100644 --- a/apps/web/src/app/inicio/posgrado/tesis/lista/[id]/page.tsx +++ b/apps/web/src/app/inicio/posgrado/tesis/lista/[id]/page.tsx @@ -147,7 +147,6 @@ function ThesisApplying({ thesis }: { readonly thesis: Thesis }) { const userApplications = await getPostgraduateThesisStatus(); if (userApplications) { setHasExistingApplication(true); - return; } else { await postThesisApplication(thesisId); @@ -311,7 +310,7 @@ function MotivationTextArea({ }) { return (
    -