modified machine

This commit is contained in:
2026-01-27 16:11:17 -06:00
parent fd97c21740
commit 608ce4b11a
5 changed files with 246 additions and 52 deletions
+132 -34
View File
@@ -4,21 +4,48 @@ import { useEffect, useState } from "react";
import { envConfig } from "@/app/lib/config";
import toast from "react-hot-toast";
import "./asignacion.css";
import { getEquipoByCount } from "@/app/lib/getEquipoByCount";
type Props = {
inscripcion: any[];
idCuenta: number;
numAcount: number;
};
export default function PlaticaGate({ inscripcion, idCuenta }: Props) {
export default function PlaticaGate({ inscripcion, numAcount }: Props) {
const [puedeContinuar, setPuedeContinuar] = useState(false);
const [equipos, setEquipos] = useState<any[]>([]);
const [loadingEquipos, setLoadingEquipos] = useState(false);
const [equipoSeleccionado, setEquipoSeleccionado] = useState<any>(null);
const [open, setOpen] = useState(false);
const [tiempo, setTiempo] = useState<number>(15);
const [bitacora, setBitacora] = useState(null);
const fetchByCuenta = async (idCuenta: number) => {
const result = await getEquipoByCount(idCuenta);
if (result?.error) {
toast.error(result.error);
setBitacora(null);
} else {
setBitacora(result);
toast.error("Ya cuentas con un equipo asignado");
}
};
useEffect(() => {
if (!numAcount) return;
const idCuenta = numAcount;
if (isNaN(idCuenta)) return;
fetchByCuenta(idCuenta);
}, [numAcount]);
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) {
@@ -31,17 +58,17 @@ export default function PlaticaGate({ inscripcion, idCuenta }: Props) {
}, [inscripcion]);
useEffect(() => {
if (!puedeContinuar || !idCuenta) return;
if (!puedeContinuar || !numAcount) return;
const fetchEquipos = async () => {
try {
setLoadingEquipos(true);
const res = await fetch(
`${envConfig.apiUrl}/equipo/student/${idCuenta}`,
`${envConfig.apiUrl}/equipo/student/${numAcount}`,
{
cache: "no-store",
}
},
);
if (!res.ok) {
@@ -58,49 +85,120 @@ export default function PlaticaGate({ inscripcion, idCuenta }: Props) {
};
fetchEquipos();
}, [puedeContinuar, idCuenta]);
}, [puedeContinuar, numAcount]);
if (!puedeContinuar) return null;
const submit = async (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
if (!equipoSeleccionado) {
toast.error("Selecciona un equipo");
return;
}
try {
const body = {
tiempo_asignado: tiempo,
ubicacion: equipoSeleccionado.ubicacion ?? null,
id_equipo: equipoSeleccionado.id_equipo,
id_alumno_inscrito: inscripcion[0].id_alumno_inscrito,
};
const res = await fetch(`${envConfig.apiUrl}/bitacora`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (!res.ok) {
throw new Error("Error al asignar equipo");
}
toast.success("Equipo asignado correctamente");
} catch (error) {
toast.error("No se pudo asignar el equipo");
}
};
if (bitacora) {
return (<></>
);
}
return (
<div className="containerForm">
<label style={{ marginTop: "1rem" }}>
Seleccionar tiempo
</label>
<label>Seleccionar tiempo</label>
<select>
<option>15 minutos</option>
<option>30 minutos</option>
<option>40 minutos</option>
<option>60 minutos</option>
<option>90 minutos</option>
<select
value={tiempo}
onChange={(e) => setTiempo(Number(e.target.value))}
>
<option value={15}>15 minutos</option>
<option value={30}>30 minutos</option>
<option value={40}>40 minutos</option>
<option value={60}>60 minutos</option>
<option value={90}>90 minutos</option>
</select>
<label style={{ marginTop: "1rem" }}>
Seleccione un equipo
</label>
<label style={{ marginTop: "1rem" }}>Seleccione un equipo</label>
<div className="groupInput">
<select disabled={loadingEquipos || equipos.length === 0}>
{loadingEquipos && (
<option>Cargando equipos...</option>
)}
<div
className={`customSelect ${open ? "open" : ""} ${loadingEquipos ? "disabled" : ""}`}
>
<div
className={`selectHeader ${equipoSeleccionado && equipoSeleccionado.plataforma?.nombre?.toUpperCase()}`}
onClick={() => !loadingEquipos && setOpen(!open)}
>
{equipoSeleccionado ? (
<span
className={equipoSeleccionado?.plataforma?.nombre?.toUpperCase()}
>
{equipoSeleccionado.ubicacion}{" "}
{equipoSeleccionado.nombre_equipo}
</span>
) : (
<span className="placeholder">
{loadingEquipos
? "Cargando equipos..."
: "Seleccione un equipo"}
</span>
)}
{!loadingEquipos && equipos.length === 0 && (
<option>No hay equipos disponibles</option>
)}
<span className="arrow">{open ? "▲" : "▼"}</span>
</div>
{!loadingEquipos &&
equipos.map((eq) => (
<option key={eq.id_equipo} value={eq.id_equipo}>
{eq.ubicacion} {eq.nombre_equipo} ({eq.plataforma?.nombre})
</option>
))}
</select>
{open && (
<div className="options">
{equipos.length === 0 && (
<div className="option disabled">
No hay equipos disponibles
</div>
)}
{equipos.map((eq) => (
<div
key={eq.id_equipo}
className={`option ${eq.plataforma?.nombre?.toUpperCase()}`}
onClick={() => {
setEquipoSeleccionado(eq);
setOpen(false);
}}
>
{eq.ubicacion} {eq.nombre_equipo}
</div>
))}
</div>
)}
</div>
<button
className="button buttonSearch"
disabled={loadingEquipos || equipos.length === 0}
disabled={!equipoSeleccionado || loadingEquipos}
onClick={submit}
>
Asignar Equipo
</button>
@@ -0,0 +1,93 @@
.customSelect {
border: 1px solid #ccc;
border-radius: 6px;
position: relative;
flex: 1;
width: 100%;
font-size: 14px;
}
.customSelect.disabled {
opacity: 0.6;
pointer-events: none;
}
.option {
padding: 10px 12px;
cursor: pointer;
display: flex;
align-items: center;
gap: 8px;
background: #fff;
}
.option:not(.disabled):hover {
background-color: #f0f0f0;
}
.option.disabled {
cursor: not-allowed;
color: #999;
}
.option.active {
background-color: #e6f0ff;
font-weight: 600;
}
.option:hover {
background-color: #f0f0f0;
}
/* ICONOS */
.WINDOWS::before {
content: "";
width: 20px;
height: 20px;
background: url("/windows.png") no-repeat center / contain;
}
.MACINTOSH::before {
content: "";
width: 20px;
height: 20px;
background: url("/apple.png") no-repeat center / contain;
}
.PROFESORES::before {
content: "";
width: 20px;
height: 20px;
background: url("/teacher.png") no-repeat center / contain;
}
.selectHeader {
border-radius: 6px;
padding: 8px 12px;
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
background: #fff;
}
.placeholder {
color: #999;
}
.arrow {
font-size: 12px;
}
.options {
position: absolute;
bottom: 105%;
left: 0;
right: 0;
border: 1px solid #ccc;
border-radius: 6px;
background: #fff;
z-index: 10;
max-height: 250px;
overflow-y: auto;
}
+1 -1
View File
@@ -112,7 +112,7 @@ export default async function Page(props: {
<PlaticaGate
inscripcion={inscripcion}
idCuenta={student.id_cuenta}
numAcount={student.id_cuenta}
/>
</>
)}
+1 -17
View File
@@ -7,23 +7,7 @@ import axios from "axios";
import Information from "./Global/Information/information";
import toast from "react-hot-toast";
import { useRouter } from "next/navigation";
async function getEquipoByCount(idCuenta: number) {
try {
const res = await axios.get(
`${envConfig.apiUrl}/bitacora/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" };
}
}
import { getEquipoByCount } from "../lib/getEquipoByCount";
async function getEquipoId(idEquipo: number) {
try {
+19
View File
@@ -0,0 +1,19 @@
import axios from "axios";
import { envConfig } from "./config";
export async function getEquipoByCount(idCuenta: number) {
try {
const res = await axios.get(
`${envConfig.apiUrl}/bitacora/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" };
}
}