From bf555f02abea3a1320f4e4f103086168604a265e Mon Sep 17 00:00:00 2001 From: IO420 <320154041@pcpuma.acatlan.unam.mx> Date: Mon, 26 Jan 2026 13:04:50 -0600 Subject: [PATCH 1/6] SearchMesas --- app/(private)/AsignacionMesas/page.tsx | 2 +- app/Components/CheckBoxMesa.tsx | 3 +- .../Global/SearchUser/searchUserTable.tsx | 87 +++++++++++++++++++ app/Components/Mesas | 22 +++++ app/Components/SearchMesa.tsx | 83 ++++++++++++++++++ tsconfig.json | 2 +- 6 files changed, 196 insertions(+), 3 deletions(-) create mode 100644 app/Components/Global/SearchUser/searchUserTable.tsx create mode 100644 app/Components/Mesas create mode 100644 app/Components/SearchMesa.tsx diff --git a/app/(private)/AsignacionMesas/page.tsx b/app/(private)/AsignacionMesas/page.tsx index e624d29..d6366f1 100644 --- a/app/(private)/AsignacionMesas/page.tsx +++ b/app/(private)/AsignacionMesas/page.tsx @@ -103,7 +103,7 @@ export default async function Page(props: { }, { key: "Liberar", - label: "Cancelar mesa", + label: "Liberar mesa", content: , }, ]} diff --git a/app/Components/CheckBoxMesa.tsx b/app/Components/CheckBoxMesa.tsx index 9bcc88a..54975b2 100644 --- a/app/Components/CheckBoxMesa.tsx +++ b/app/Components/CheckBoxMesa.tsx @@ -3,6 +3,7 @@ import { useState } from "react"; import SearchUser from "./Global/SearchUser/searchUser"; import SearchBoxEquipo from "./SearchEquipo"; +import SearchMesa from "./SearchMesa"; export default function CheckBoxMesa({ numAcount, @@ -38,7 +39,7 @@ export default function CheckBoxMesa({ {modo === "Cuenta" && } - {modo === "Mesa" && } + {modo === "Mesa" && } ); } diff --git a/app/Components/Global/SearchUser/searchUserTable.tsx b/app/Components/Global/SearchUser/searchUserTable.tsx new file mode 100644 index 0000000..2de3a56 --- /dev/null +++ b/app/Components/Global/SearchUser/searchUserTable.tsx @@ -0,0 +1,87 @@ +"use client"; + +import { useEffect, useState } from "react"; +import axios from "axios"; + +interface SearchUserProps { + value?: string | null; +} + +type Alumno = { + nombre: string; + carrera: string; + mesaActiva: boolean; +}; + +export default function SearchUserTable({ value }: SearchUserProps) { + const [numAcount, setNumAcount] = useState(value || ""); + const [alumno, setAlumno] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + // Si el prop cambia, actualizar el input + useEffect(() => { + if (value) setNumAcount(value); + }, [value]); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + + if (!numAcount) { + setError("Ingresa un número de cuenta"); + return; + } + + setLoading(true); + setError(null); + setAlumno(null); + + try { + // Llamada a la API con Axios + const { data } = await axios.get(`/api/alumnos/${numAcount}`); + setAlumno(data); + } catch (err: any) { + setAlumno(null); + setError(err.response?.data?.message || "Alumno no encontrado"); + } finally { + setLoading(false); + } + }; + + return ( +
+
+ +
+ { + const value = e.target.value; + // Solo números y máximo 9 dígitos + if (/^\d*$/.test(value) && value.length <= 9) { + setNumAcount(value); + } + }} + placeholder="Coloca un número de cuenta..." + inputMode="numeric" + pattern="[0-9]*" + /> + +
+
+ + {error &&

{error}

} + + {alumno && ( +
+

Nombre: {alumno.nombre}

+

Carrera: {alumno.carrera}

+

Mesa activada: {alumno.mesaActiva ? "Sí" : "No"}

+
+ )} +
+ ); +} diff --git a/app/Components/Mesas b/app/Components/Mesas new file mode 100644 index 0000000..c38d979 --- /dev/null +++ b/app/Components/Mesas @@ -0,0 +1,22 @@ +"use client"; +import axios from 'axios'; +import { useEffect } from 'react'; + +interface Props { + id_cuenta: number; +} + +export function Mesas({ id_cuenta }: Props) { + + useEffect(() => { + if (!id_cuenta) return; + + axios.get(`/cuenta/${id_cuenta}`) + .then(res => { + console.log('Mesas:', res.data); + }) + .catch(err => console.error(err)); + }, [id_cuenta]); + + return
Buscando mesas para cuenta {id_cuenta}...; +} diff --git a/app/Components/SearchMesa.tsx b/app/Components/SearchMesa.tsx new file mode 100644 index 0000000..fa7f550 --- /dev/null +++ b/app/Components/SearchMesa.tsx @@ -0,0 +1,83 @@ +"use client"; +import axios from 'axios'; +import { useEffect, useState } from 'react'; + +interface Mesa { + id_mesa: number; + nombre?: string; +} + +interface Props { + id_cuenta: number; +} + +function Mesas({ id_cuenta }: Props) { + const [mesas, setMesas] = useState([]); + const [loading, setLoading] = useState(false); + + useEffect(() => { + if (!id_cuenta) return; + + setLoading(true); + + axios.get(`/cuenta/${id_cuenta}`) + .then(res => { + setMesas(res.data); + }) + .catch(err => console.error(err)) + .finally(() => setLoading(false)); + }, [id_cuenta]); + + if (loading) return

Cargando mesas...

; + + return ( +
+

Mesas asignadas

+ + {mesas.length === 0 ? ( +

No hay mesas

+ ) : ( +
    + {mesas.map(mesa => ( +
  • + Mesa {mesa.id_mesa} {mesa.nombre && `- ${mesa.nombre}`} +
  • + ))} +
+ )} +
+ ); +} + +export default function SearchMesa() { + const [inputValue, setInputValue] = useState(''); + const [idCuenta, setIdCuenta] = useState(null); + + const buscar = (e: React.FormEvent) => { + e.preventDefault(); + setIdCuenta(Number(inputValue)); + }; + + return ( + <> +
+ + +
+ setInputValue(e.target.value)} + /> + + +
+
+ + {idCuenta && } + + ); +} diff --git a/tsconfig.json b/tsconfig.json index 74f6560..e7ff3a2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,7 +15,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", + "jsx": "react-jsx", "incremental": true, "plugins": [ { From 64737fcab6af968f6ec39caf171713efb8155a38 Mon Sep 17 00:00:00 2001 From: IO420 <320154041@pcpuma.acatlan.unam.mx> Date: Wed, 28 Jan 2026 17:29:07 -0600 Subject: [PATCH 2/6] fixing little things --- app/(private)/AsignacionMesas/page.tsx | 6 ++---- app/Components/AsignacionMesas.tsx | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/app/(private)/AsignacionMesas/page.tsx b/app/(private)/AsignacionMesas/page.tsx index d6366f1..b30e5ff 100644 --- a/app/(private)/AsignacionMesas/page.tsx +++ b/app/(private)/AsignacionMesas/page.tsx @@ -4,7 +4,6 @@ import Information from "@/app/Components/Global/Information/information"; import SearchUser from "@/app/Components/Global/SearchUser/searchUser"; import ShowError from "@/app/Components/Global/ShowError"; import Toggle from "@/app/Components/Global/Toggle/Toggle"; -import Table from "@/app/Components/Global/table"; import { envConfig } from "@/app/lib/config"; import { GetRegisterStudent } from "@/app/lib/getRegisterStudent"; @@ -23,8 +22,6 @@ async function getInscripcion(idCuenta: number) { } } -const headers = ["Inscrito", "Tiempo", "Confirmó"]; - export default async function Page(props: { searchParams?: Promise<{ key?: string; @@ -88,13 +85,14 @@ export default async function Page(props: { - )} diff --git a/app/Components/AsignacionMesas.tsx b/app/Components/AsignacionMesas.tsx index 059511d..18584cd 100644 --- a/app/Components/AsignacionMesas.tsx +++ b/app/Components/AsignacionMesas.tsx @@ -5,8 +5,8 @@ import { envConfig } from "@/app/lib/config"; import toast from "react-hot-toast"; type Props = { - idCuenta: number; inscripcion: any[]; + idCuenta: number; }; export default function AsignacionMesas({ @@ -33,7 +33,6 @@ export default function AsignacionMesas({ setPuedeContinuar(true); }, [inscripcion]); - useEffect(() => { if (!puedeContinuar || !idCuenta) return; From 053cfb29be35ad4a88c67eeb97eaf6eb7da33943 Mon Sep 17 00:00:00 2001 From: IO420 <320154041@pcpuma.acatlan.unam.mx> Date: Wed, 28 Jan 2026 18:19:59 -0600 Subject: [PATCH 3/6] sibmit mesa --- app/(private)/AsignacionMesas/page.tsx | 29 +++---- app/Components/AsignacionMesas.tsx | 109 +++++++++++++++++++------ 2 files changed, 100 insertions(+), 38 deletions(-) diff --git a/app/(private)/AsignacionMesas/page.tsx b/app/(private)/AsignacionMesas/page.tsx index f0203de..322de7d 100644 --- a/app/(private)/AsignacionMesas/page.tsx +++ b/app/(private)/AsignacionMesas/page.tsx @@ -33,31 +33,34 @@ export default async function Page(props: { const numAcount = params?.numAcount ?? null; let student: any = null; + let platica: any = null; let inscripcion: any[] = []; let errorMessage = ""; if (numAcount) { const idCuenta = parseInt(numAcount); - const result = await axios.get(`${envConfig.apiUrl}/bitacora-mesa/cuenta/${idCuenta}`); - student = result.data + const result = await GetRegisterStudent(idCuenta); + if (result.error) { + errorMessage = `${result.error}`; + } else { + student = result[0]?.alumno as Student; + const rawPlatica = result[0]?.platica; + platica = + rawPlatica?.type === "Buffer" + ? Boolean(rawPlatica.data[0]) + : Boolean(rawPlatica); + console.log(result); + } const inscResult = await getInscripcion(idCuenta); if (!inscResult.error && Array.isArray(inscResult)) { inscripcion = inscResult; + } else { + inscripcion = []; } } - const tableData = Array.isArray(inscripcion) - ? inscripcion.map((ins) => ({ - Inscrito: ins.plataforma?.nombre || "—", - Tiempo: ins.tiempo_disponible - ? `${ins.tiempo_disponible} minutos` - : "—", - Confirmó: ins.platica?.data?.[0] === 1 ? "sí" : "no", - })) - : []; - return (
{errorMessage && } @@ -80,14 +83,12 @@ export default async function Page(props: { )} diff --git a/app/Components/AsignacionMesas.tsx b/app/Components/AsignacionMesas.tsx index 5d16bb6..be0852f 100644 --- a/app/Components/AsignacionMesas.tsx +++ b/app/Components/AsignacionMesas.tsx @@ -3,25 +3,45 @@ import { useEffect, useState } from "react"; import { envConfig } from "@/app/lib/config"; import toast from "react-hot-toast"; +import { getEquipoByCount } from "../lib/getEquipoByCount"; type Props = { inscripcion: any[]; idCuenta: number; }; -export default function AsignacionMesas({ - idCuenta, - inscripcion, -}: Props) { +export default function AsignacionMesas({ idCuenta, inscripcion }: Props) { const [puedeContinuar, setPuedeContinuar] = useState(false); const [mesas, setMesas] = useState([]); const [loadingMesas, setLoadingMesas] = useState(false); + const [mesaSeleccionada, setMesaSeleccionada] = useState(null); + const [tiempo, setTiempo] = useState(15); + const [bitacora, setBitacora] = useState<[] | null>(null); + + const fetchByCuenta = async (idCuenta: number) => { + const result = await getEquipoByCount(idCuenta); + + if (result?.error) { + setBitacora(null); + } else { + setBitacora(result); + toast.error("Ya cuentas con un equipo asignado"); + } + }; + + useEffect(() => { + if (!idCuenta) return; + const Cuenta = idCuenta; + if (isNaN(Cuenta)) return; + + fetchByCuenta(Cuenta); + }, [idCuenta]); useEffect(() => { if (!Array.isArray(inscripcion) || inscripcion.length === 0) return; const todasAsistieron = inscripcion.every( - (ins) => ins.platica?.data?.[0] === 1 + (ins) => ins.platica?.data?.[0] === 1, ); if (!todasAsistieron) { @@ -34,16 +54,16 @@ export default function AsignacionMesas({ }, [inscripcion]); useEffect(() => { + console.log(envConfig.apiUrl); + console.log(puedeContinuar, idCuenta); if (!puedeContinuar || !idCuenta) return; const fetchMesas = async () => { try { setLoadingMesas(true); - - const res = await fetch( - `${envConfig.apiUrl}/mesa/activo`, - { cache: "no-store" } - ); + const res = await fetch(`${envConfig.apiUrl}/mesa/activo`, { + cache: "no-store", + }); if (!res.ok) { throw new Error("No se pudieron cargar las mesas"); @@ -61,37 +81,77 @@ export default function AsignacionMesas({ fetchMesas(); }, [puedeContinuar, idCuenta]); + const submit = async (e: React.MouseEvent) => { + e.preventDefault(); + + if (!mesaSeleccionada) { + toast.error("Selecciona un mesa"); + return; + } + + try { + const body = { + tiempo_asignado: tiempo, + id_mesa: Number(mesaSeleccionada), + id_alumno_inscrito: inscripcion[0].id_alumno_inscrito, + }; + + const res = await fetch(`${envConfig.apiUrl}/bitacora-mesa`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + }); + + if (!res.ok) { + throw new Error("Error al asignar mesa"); + } + + setBitacora([]); + toast.success("Mesa asignada correctamente"); + } catch (error) { + toast.error("No se pudo asignar la mesa"); + } + }; + if (!puedeContinuar) return null; + if (bitacora) { + return <>; + } return (
- + - setTiempo(Number(e.target.value))} + > + + + + - +
- setMesaSeleccionada(e.target.value)} + > {loadingMesas && } {!loadingMesas && mesas.length === 0 && ( )} + {!loadingMesas && mesas.map((mesa) => ( - ))} @@ -99,6 +159,7 @@ export default function AsignacionMesas({ From bf8bd209eeb2e99cc1ca412da9cd7550ce545ad5 Mon Sep 17 00:00:00 2001 From: IO420 <320154041@pcpuma.acatlan.unam.mx> Date: Wed, 28 Jan 2026 18:55:25 -0600 Subject: [PATCH 4/6] msj --- app/Components/AsignacionMesas.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Components/AsignacionMesas.tsx b/app/Components/AsignacionMesas.tsx index be0852f..2235ce8 100644 --- a/app/Components/AsignacionMesas.tsx +++ b/app/Components/AsignacionMesas.tsx @@ -163,6 +163,7 @@ export default function AsignacionMesas({ idCuenta, inscripcion }: Props) { > Asignar Mesa +
); From a5435a224f48dd721d88ad653d537ff4bf0c9d85 Mon Sep 17 00:00:00 2001 From: IO420 <320154041@pcpuma.acatlan.unam.mx> Date: Thu, 29 Jan 2026 11:21:12 -0600 Subject: [PATCH 5/6] Table assignment completed --- app/(private)/AsignacionMesas/page.tsx | 6 +- app/Components/CheckBoxMesa.tsx | 140 ++++++++++++++++++++++--- app/Components/SearchMesa.tsx | 27 +++-- app/lib/getTableByCount.ts | 19 ++++ 4 files changed, 166 insertions(+), 26 deletions(-) create mode 100644 app/lib/getTableByCount.ts diff --git a/app/(private)/AsignacionMesas/page.tsx b/app/(private)/AsignacionMesas/page.tsx index 322de7d..9d87bb6 100644 --- a/app/(private)/AsignacionMesas/page.tsx +++ b/app/(private)/AsignacionMesas/page.tsx @@ -7,7 +7,6 @@ import Toggle from "@/app/Components/Global/Toggle/Toggle"; import { envConfig } from "@/app/lib/config"; import { GetRegisterStudent } from "@/app/lib/getRegisterStudent"; -import axios from "axios"; async function getInscripcion(idCuenta: number) { try { @@ -26,11 +25,14 @@ export default async function Page(props: { searchParams?: Promise<{ key?: string; numAcount?: string; + table?:number }>; }) { const params = await props.searchParams; const key = params?.key; const numAcount = params?.numAcount ?? null; + const table = params?.table ?? null; + let student: any = null; let platica: any = null; @@ -98,7 +100,7 @@ export default async function Page(props: { { key: "Liberar", label: "Cancelar mesa", - content: , + content: , }, ]} /> diff --git a/app/Components/CheckBoxMesa.tsx b/app/Components/CheckBoxMesa.tsx index 4fbee81..b285af6 100644 --- a/app/Components/CheckBoxMesa.tsx +++ b/app/Components/CheckBoxMesa.tsx @@ -1,24 +1,123 @@ "use client"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import SearchUser from "./Global/SearchUser/searchUser"; -import SearchEquipo from "./SearchEquipo"; import Information from "./Global/Information/information"; import SearchMesa from "./SearchMesa"; +import { getTableByCount } from "../lib/getTableByCount"; +import toast from "react-hot-toast"; +import axios from "axios"; +import { envConfig } from "../lib/config"; interface props { numAcount: string | null; - student: { - id_cuenta: number; - nombre: string; - carrera:{ - carrera:string; - } - }; + table: number | null; } -export default function CheckBoxMesa({ numAcount, student }: props) { - const [modo, setModo] = useState<"Mesa" | "Cuenta" | null>(null); +async function getEquipoId(idEquipo: number) { + try { + const res = await axios.get( + `${envConfig.apiUrl}/bitacora-mesa/table/${idEquipo}`, + ); + return res.data; + } catch (error: any) { + if (axios.isAxiosError(error)) { + return { + error: error.response?.data?.message || "Error al consultar equipo", + }; + } + + return { error: "Error desconocido" }; + } +} + +export default function CheckBoxMesa({ numAcount, table }: props) { + const [modo, setModo] = useState<"Mesa" | "Cuenta" | null>("Cuenta"); + const [bitacora, setBitacora] = useState(null); + const [tiempoRestante, setTiempoRestante] = useState(""); + const [minutos, setMinutos] = useState(); + + const fetchByCuenta = async (idCuenta: number) => { + const result = await getTableByCount(idCuenta); + + if (result?.error) { + toast.error(result.error); + setBitacora(null); + } else { + setBitacora(result); + } + }; + + const fetchByEquipo = async (idEquipo: number) => { + const result = await getEquipoId(idEquipo); + + if (result?.error) { + toast.error(result.error); + setBitacora(null); + } else { + setBitacora(result); + } + }; + + useEffect(() => { + if (!numAcount) return; + const idCuenta = parseInt(numAcount); + if (isNaN(idCuenta)) return; + + fetchByCuenta(idCuenta); + }, [numAcount]); + + useEffect(() => { + if (!table) return; + const idEquipo = table; + if (isNaN(idEquipo)) return; + + fetchByEquipo(idEquipo); + }, [table]); + + useEffect(() => { + if (!bitacora) return; + + const entrada = new Date(bitacora.tiempo_entrada).getTime(); + const asignadoMs = bitacora.tiempo_asignado * 60 * 1000; + + const interval = setInterval(() => { + const ahora = Date.now(); + const restante = entrada + asignadoMs - ahora; + + if (restante <= 0) { + setTiempoRestante("agotado"); + clearInterval(interval); + } else { + const minutos = Math.floor(restante / 60000); + setMinutos(minutos + 1); + const segundos = Math.floor((restante % 60000) / 1000); + setTiempoRestante(`${minutos} minutos con ${segundos} segundos`); + } + }, 1000); + + return () => clearInterval(interval); + }, [bitacora]); + + + const handleButton = async (e: React.MouseEvent) => { + e.preventDefault(); + + await axios.patch( + `${envConfig.apiUrl}/bitacora-mesa/cancelar/${bitacora.id_bitacora_mesa}`, + { tiempo_asignado: minutos }, + ); + + toast.success("Tiempo cancelado"); + + if (modo === "Cuenta" && numAcount) { + fetchByCuenta(parseInt(numAcount)); + } + + if (modo === "Mesa" && table) { + fetchByEquipo(table); + } + }; return ( <> @@ -48,10 +147,23 @@ export default function CheckBoxMesa({ numAcount, student }: props) { {modo === "Cuenta" && } {modo === "Mesa" && } - {modo === "Mesa" && } - {student && ( - + {bitacora && ( + <> + + + )} ); diff --git a/app/Components/SearchMesa.tsx b/app/Components/SearchMesa.tsx index fa7f550..ecda544 100644 --- a/app/Components/SearchMesa.tsx +++ b/app/Components/SearchMesa.tsx @@ -1,6 +1,7 @@ "use client"; -import axios from 'axios'; -import { useEffect, useState } from 'react'; +import axios from "axios"; +import { usePathname, useRouter, useSearchParams } from "next/navigation"; +import { useEffect, useState } from "react"; interface Mesa { id_mesa: number; @@ -20,11 +21,12 @@ function Mesas({ id_cuenta }: Props) { setLoading(true); - axios.get(`/cuenta/${id_cuenta}`) - .then(res => { + axios + .get(`/cuenta/${id_cuenta}`) + .then((res) => { setMesas(res.data); }) - .catch(err => console.error(err)) + .catch((err) => console.error(err)) .finally(() => setLoading(false)); }, [id_cuenta]); @@ -38,7 +40,7 @@ function Mesas({ id_cuenta }: Props) {

No hay mesas

) : (
    - {mesas.map(mesa => ( + {mesas.map((mesa) => (
  • Mesa {mesa.id_mesa} {mesa.nombre && `- ${mesa.nombre}`}
  • @@ -50,12 +52,19 @@ function Mesas({ id_cuenta }: Props) { } export default function SearchMesa() { - const [inputValue, setInputValue] = useState(''); + const [inputValue, setInputValue] = useState(""); const [idCuenta, setIdCuenta] = useState(null); + const router = useRouter(); + const pathname = usePathname(); + const searchParams = useSearchParams(); const buscar = (e: React.FormEvent) => { e.preventDefault(); - setIdCuenta(Number(inputValue)); + const params = new URLSearchParams(searchParams.toString()); + if (inputValue) { + params.set("table", `${inputValue}`); + router.push(`${pathname}?${params.toString()}`); + } }; return ( @@ -76,8 +85,6 @@ export default function SearchMesa() { - - {idCuenta && } ); } diff --git a/app/lib/getTableByCount.ts b/app/lib/getTableByCount.ts new file mode 100644 index 0000000..debf82a --- /dev/null +++ b/app/lib/getTableByCount.ts @@ -0,0 +1,19 @@ +import axios from "axios"; +import { envConfig } from "./config"; + +export async function getTableByCount(idCuenta: number) { + try { + const res = await axios.get( + `${envConfig.apiUrl}/bitacora-mesa/cuenta/${idCuenta}`, + ); + return res.data; + } catch (error: any) { + if (axios.isAxiosError(error)) { + return { + error: error.response?.data?.message || "Error al consultar equipo", + }; + } + + return { error: "Error desconocido" }; + } +} \ No newline at end of file From b38a5f10401c9e7e82fad70141d73a012ce77485 Mon Sep 17 00:00:00 2001 From: IO420 <320154041@pcpuma.acatlan.unam.mx> Date: Thu, 29 Jan 2026 12:19:38 -0600 Subject: [PATCH 6/6] PROGRAMS 85% --- app/(private)/Programas/page.tsx | 92 ++++++++++++++++++++++---------- 1 file changed, 63 insertions(+), 29 deletions(-) diff --git a/app/(private)/Programas/page.tsx b/app/(private)/Programas/page.tsx index 078d3e4..43aba9e 100644 --- a/app/(private)/Programas/page.tsx +++ b/app/(private)/Programas/page.tsx @@ -1,41 +1,63 @@ "use client"; -import { useState } from "react"; + +import { useState, useEffect } from "react"; import styleprograms from "./programas.module.css"; +import { Interface } from "readline"; + + interface Programa { + id_programa: number; + programa: string; +} export default function Page() { const [modo, setModo] = useState("ver"); - const handleNuevo = () => { - setModo("nuevo"); - }; + const [programaSeleccionado, setProgramaSeleccionado] = useState(""); + const [programas, setProgramas] = useState([]); - const handleEditar = () => { - setModo("editar"); - }; + useEffect(() => { + fetch("http://localhost:5000/programa/") + .then((res) => res.json()) + .then((data) => setProgramas(data)) + .catch((error) => console.error("Error al cargar programas:", error)); + }, []); - const handleCancelar = () => { - setModo("ver"); - }; + const handleNuevo = () => setModo("nuevo"); + const handleEditar = () => setModo("editar"); + const handleCancelar = () => setModo("ver"); return (
    + + {} {modo === "ver" && (

    PROGRAMAS

    - + +

    Programa

    - setProgramaSeleccionado(e.target.value)} + > + + + {programas.map((programa) => ( + + ))} +
    - + + +