Merge branch 'Carlos' of https://repositorio.acatlan.unam.mx/IO/front-AT into Develop
This commit is contained in:
@@ -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 = {
|
||||
idCuenta: number;
|
||||
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<any[]>([]);
|
||||
const [loadingMesas, setLoadingMesas] = useState(false);
|
||||
const [mesaSeleccionada, setMesaSeleccionada] = useState<any>(null);
|
||||
const [tiempo, setTiempo] = useState<number>(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) {
|
||||
@@ -33,18 +53,17 @@ export default function AsignacionMesas({
|
||||
setPuedeContinuar(true);
|
||||
}, [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");
|
||||
@@ -62,37 +81,77 @@ export default function AsignacionMesas({
|
||||
fetchMesas();
|
||||
}, [puedeContinuar, idCuenta]);
|
||||
|
||||
const submit = async (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
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 (
|
||||
<div className="containerForm">
|
||||
<label style={{ marginTop: "1rem" }}>
|
||||
Seleccionar tiempo
|
||||
</label>
|
||||
<label style={{ marginTop: "1rem" }}>Seleccionar tiempo</label>
|
||||
|
||||
<select>
|
||||
<option>15 minutos</option>
|
||||
<option>30 minutos</option>
|
||||
<option>40 minutos</option>
|
||||
<option>60 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>
|
||||
</select>
|
||||
|
||||
<label style={{ marginTop: "1rem" }}>
|
||||
Seleccione una mesa
|
||||
</label>
|
||||
<label style={{ marginTop: "1rem" }}>Seleccione una mesa</label>
|
||||
|
||||
<div className="groupInput">
|
||||
<select disabled={loadingMesas || mesas.length === 0}>
|
||||
<select
|
||||
disabled={loadingMesas || mesas.length === 0}
|
||||
onChange={(e) => setMesaSeleccionada(e.target.value)}
|
||||
>
|
||||
{loadingMesas && <option>Cargando mesas...</option>}
|
||||
|
||||
{!loadingMesas && mesas.length === 0 && (
|
||||
<option>No hay mesas disponibles</option>
|
||||
)}
|
||||
|
||||
<option value={0}>Selecciona una mesa</option>
|
||||
{!loadingMesas &&
|
||||
mesas.map((mesa) => (
|
||||
<option key={mesa.idMesa} value={mesa.idMesa}>
|
||||
Mesa {mesa.idMesa}
|
||||
<option key={mesa.id_mesa} value={mesa.id_mesa}>
|
||||
Mesa {mesa.id_mesa}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
@@ -100,9 +159,11 @@ export default function AsignacionMesas({
|
||||
<button
|
||||
className="button buttonSearch"
|
||||
disabled={loadingMesas || mesas.length === 0}
|
||||
onClick={submit}
|
||||
>
|
||||
Asignar Mesa
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
+128
-14
@@ -1,23 +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<any>(null);
|
||||
const [tiempoRestante, setTiempoRestante] = useState<string>("");
|
||||
const [minutos, setMinutos] = useState<number>();
|
||||
|
||||
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<HTMLButtonElement>) => {
|
||||
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 (
|
||||
<>
|
||||
@@ -46,10 +146,24 @@ export default function CheckBoxMesa({ numAcount, student }: props) {
|
||||
</div>
|
||||
|
||||
{modo === "Cuenta" && <SearchUser value={numAcount ?? null} />}
|
||||
{modo === "Mesa" && <SearchEquipo value={ null}/>}
|
||||
{modo === "Mesa" && <SearchMesa />}
|
||||
|
||||
{student && (
|
||||
<Information NoCuenta={student.id_cuenta} nombre={student.nombre} carrera={student.carrera?.carrera}/>
|
||||
{bitacora && (
|
||||
<>
|
||||
<Information
|
||||
NoCuenta={bitacora.alumno_inscrito.alumno.id_cuenta}
|
||||
Nombre={bitacora.alumno_inscrito.alumno.nombre}
|
||||
Tiempo={tiempoRestante}
|
||||
Mesa={bitacora.mesa.id_mesa}
|
||||
/>
|
||||
<button
|
||||
className="button buttonSearch"
|
||||
style={{ marginTop: "1rem" }}
|
||||
onClick={handleButton}
|
||||
>
|
||||
Cancelar tiempo
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -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<Alumno | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
// Si el prop cambia, actualizar el input
|
||||
useEffect(() => {
|
||||
if (value) setNumAcount(value);
|
||||
}, [value]);
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
||||
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<Alumno>(`/api/alumnos/${numAcount}`);
|
||||
setAlumno(data);
|
||||
} catch (err: any) {
|
||||
setAlumno(null);
|
||||
setError(err.response?.data?.message || "Alumno no encontrado");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="search-user">
|
||||
<form className="containerForm" onSubmit={handleSubmit}>
|
||||
<label className="label">No. Cuenta</label>
|
||||
<div className="groupInput">
|
||||
<input
|
||||
type="text"
|
||||
value={numAcount}
|
||||
onChange={(e) => {
|
||||
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]*"
|
||||
/>
|
||||
<button className="button buttonSearch" type="submit" disabled={loading}>
|
||||
{loading ? "Buscando..." : "Buscar"}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{error && <p style={{ color: "red", marginTop: "10px" }}>{error}</p>}
|
||||
|
||||
{alumno && (
|
||||
<div className="alumno-info" style={{ marginTop: "15px" }}>
|
||||
<p><strong>Nombre:</strong> {alumno.nombre}</p>
|
||||
<p><strong>Carrera:</strong> {alumno.carrera}</p>
|
||||
<p><strong>Mesa activada:</strong> {alumno.mesaActiva ? "Sí" : "No"}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -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 <div> </div>Buscando mesas para cuenta {id_cuenta}...</div>;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
"use client";
|
||||
import axios from "axios";
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
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<Mesa[]>([]);
|
||||
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 <p>Cargando mesas...</p>;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h3>Mesas asignadas</h3>
|
||||
|
||||
{mesas.length === 0 ? (
|
||||
<p>No hay mesas</p>
|
||||
) : (
|
||||
<ul>
|
||||
{mesas.map((mesa) => (
|
||||
<li key={mesa.id_mesa}>
|
||||
Mesa {mesa.id_mesa} {mesa.nombre && `- ${mesa.nombre}`}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function SearchMesa() {
|
||||
const [inputValue, setInputValue] = useState("");
|
||||
const [idCuenta, setIdCuenta] = useState<number | null>(null);
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
const buscar = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
if (inputValue) {
|
||||
params.set("table", `${inputValue}`);
|
||||
router.push(`${pathname}?${params.toString()}`);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<form className="containerForm" onSubmit={buscar}>
|
||||
<label>Numero de mesa</label>
|
||||
|
||||
<div className="groupInput">
|
||||
<input
|
||||
type="number"
|
||||
placeholder="Coloca el numero de mesa"
|
||||
value={inputValue}
|
||||
onChange={(e) => setInputValue(e.target.value)}
|
||||
/>
|
||||
|
||||
<button type="submit" className="button buttonSearch">
|
||||
Buscar
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user