Compare commits
92 Commits
ad09efaef6
...
d1bf9f6086
| Author | SHA1 | Date | |
|---|---|---|---|
| d1bf9f6086 | |||
| 9752ccce6b | |||
| 4ff4349fa7 | |||
| 7155f8c7b1 | |||
| b4eb945b40 | |||
| 59f8fa673d | |||
| c69aa009b7 | |||
| 6c80ecf3db | |||
| 1de700902a | |||
| 32bbfe107f | |||
| c229b819d5 | |||
| 34677f2d82 | |||
| 1a632f15b9 | |||
| 9fea87e62f | |||
| 5fbe8982f6 | |||
| 5af56f4a12 | |||
| 7c92ef6415 | |||
| 55f700f20a | |||
| eb5f6b77c4 | |||
| 46357ee7e0 | |||
| 805f4835a3 | |||
| c2aba808ad | |||
| 552353f4d7 | |||
| 1027bd0673 | |||
| 3c44aa833e | |||
| 0ddb17a23f | |||
| 08386f7ae5 | |||
| 80be76f410 | |||
| f19b0d1e11 | |||
| 649ebe6ab9 | |||
| c0cf9ecda0 | |||
| b7aa2fa66b | |||
| 6b687a8be2 | |||
| 9315bdcb22 | |||
| b0d186784f | |||
| edb2fd2664 | |||
| 01eafd4038 | |||
| 0d37fb3536 | |||
| ee4a4be907 | |||
| ea83311f4d | |||
| 1caafbc597 | |||
| 6c7c477d6a | |||
| f3d19962b9 | |||
| 661121a69d | |||
| 6cf361f281 | |||
| bce1d473a2 | |||
| d53561e339 | |||
| d0b8cc3062 | |||
| a0cd2da717 | |||
| 8f99440207 | |||
| 080ce4137f | |||
| 8c6ca40a23 | |||
| e4082c274c | |||
| d4b18b372e | |||
| 01e463d560 | |||
| 68f05fb517 | |||
| d3e59e63f7 | |||
| 39a10ce46f | |||
| 960769ea33 | |||
| 57714ff36c | |||
| b7bee2d1fd | |||
| ebc718daf2 | |||
| 4743eec697 | |||
| 65fcf5eaff | |||
| b185a96eee | |||
| b4222f7d9a | |||
| 3e85cb862d | |||
| 8b803cbf81 | |||
| 6071f38af2 | |||
| f568bb307c | |||
| 6ab123c87b | |||
| 30de190e22 | |||
| ff08c85a50 | |||
| d24b0bebb4 | |||
| 608800f8fb | |||
| 8688bb028c | |||
| 6abbe700d6 | |||
| 9f64f1305f | |||
| 13be8d9c35 | |||
| 54a2046d06 | |||
| e2c4734306 | |||
| 4de5a7d27d | |||
| 45d60d87ec | |||
| 90bdb482cd | |||
| 62afe827dc | |||
| fc91b0a822 | |||
| 6e15f279b0 | |||
| c989b54fdc | |||
| 05b766afe1 | |||
| 0582269c31 | |||
| 812c8fbbe1 | |||
| 5af0385352 |
@@ -76,7 +76,7 @@
|
||||
.checkbox-grid label {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-size: 13px;
|
||||
font-size: 1.4rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,17 +2,19 @@ import Areas from "@/app/Components/ActivosMantenimiento/Areas";
|
||||
import MesasDisponibles from "@/app/Components/ActivosMantenimiento/MesasDisponibles";
|
||||
import TableEquipos from "@/app/Components/Equipos/tableequipos";
|
||||
import Toggle from "@/app/Components/Global/Toggle/Toggle";
|
||||
import { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "ActivosMantenimiento",
|
||||
};
|
||||
|
||||
export default async function Page(props: {
|
||||
searchParams?: Promise<{
|
||||
key?: string;
|
||||
numAcount?: string;
|
||||
machine?: string;
|
||||
}>;
|
||||
}) {
|
||||
const params = await props.searchParams;
|
||||
const key = params?.key && params.key;
|
||||
const numAcount = params?.numAcount ? params.numAcount : null;
|
||||
|
||||
return (
|
||||
<section className="containerSection">
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
|
||||
import SelectionCo from "@/app/Components/Selection/SelectionCo";
|
||||
import axios from "axios";
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
import Cookies from "js-cookie";
|
||||
import Swal from "sweetalert2";
|
||||
|
||||
import "./addTime.css";
|
||||
|
||||
const PLATAFORMA_MAP: Record<string, number> = {
|
||||
@@ -35,7 +35,7 @@ export default function AddTime({
|
||||
const [folio, setFolio] = useState("");
|
||||
const [amount, setAmount] = useState("");
|
||||
const [lock, setLock] = useState<boolean>(true);
|
||||
const todayISO = new Date().toISOString().split("T")[0];
|
||||
const todayISO = new Date().toLocaleDateString("en-CA");
|
||||
const [date, setDate] = useState(todayISO);
|
||||
|
||||
const day = new Date();
|
||||
@@ -43,32 +43,62 @@ export default function AddTime({
|
||||
const month = day.getMonth();
|
||||
const today = day.getDate();
|
||||
|
||||
const minFecha = new Date(year, month, 1).toISOString().split("T")[0];
|
||||
let minMount = month
|
||||
if (!lock) {
|
||||
minMount = month - 1
|
||||
}
|
||||
|
||||
const minFecha = new Date(year, minMount, 1).toISOString().split("T")[0];
|
||||
const maxFecha = new Date(year, month, today).toISOString().split("T")[0];
|
||||
|
||||
const handleSaveReceipt = async () => {
|
||||
if (!numAcount) {
|
||||
toast.error("Busca de nuevo al estudiante");
|
||||
if (numAcount == null) {
|
||||
|
||||
Swal.fire({
|
||||
title: "Busca de nuevo al estudiante!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!plataformaSeleccionada) {
|
||||
toast.error("Selecciona una plataforma");
|
||||
|
||||
Swal.fire({
|
||||
title: "Selecciona una plataforma!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!folio) {
|
||||
toast.error("Ingresa el folio del ticket");
|
||||
|
||||
Swal.fire({
|
||||
title: "Ingresa el folio del ticket!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!amount) {
|
||||
toast.error("Coloca el monto a depositar");
|
||||
|
||||
Swal.fire({
|
||||
title: "Coloca el monto a depositar!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!date) {
|
||||
toast.error("Coloca la fecha");
|
||||
|
||||
Swal.fire({
|
||||
title: "Coloca la fecha!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -90,19 +120,27 @@ export default function AddTime({
|
||||
{ headers },
|
||||
);
|
||||
|
||||
toast.success("Tiempo Guardado");
|
||||
|
||||
Swal.fire({
|
||||
title: "Tiempo Guardado!",
|
||||
title: "Tiempo Guardado Correctamente!",
|
||||
icon: "success",
|
||||
draggable: true
|
||||
draggable: true,
|
||||
});
|
||||
|
||||
setFolio("");
|
||||
setAmount("");
|
||||
setDate(todayISO);
|
||||
router.refresh();
|
||||
} catch (err: any) {
|
||||
toast.error(err.message || "Error al guardar");
|
||||
} catch (error: any) {
|
||||
const msg =
|
||||
error.response?.data?.message ||
|
||||
error.message ||
|
||||
"Error desconocido al crear recibo";
|
||||
Swal.fire({
|
||||
title: msg,
|
||||
icon: "error",
|
||||
draggable: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -148,7 +186,23 @@ export default function AddTime({
|
||||
const numericValue = parseFloat(value);
|
||||
|
||||
if (lock && numericValue > 1000) {
|
||||
toast.error("El monto no puede superar $1000.00");
|
||||
|
||||
Swal.fire({
|
||||
title:
|
||||
"El monto no puede superar $1000.00 Desbloquea el candado !",
|
||||
icon: "error",
|
||||
draggable: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (numericValue > 10000) {
|
||||
|
||||
Swal.fire({
|
||||
title: "El monto no puede superar $10000.00 pesos",
|
||||
icon: "error",
|
||||
draggable: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -171,7 +225,7 @@ export default function AddTime({
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="containerButton" style={{ position: 'relative' }}>
|
||||
<div className="containerButton" style={{ position: "relative" }}>
|
||||
<button className="button buttonSearch" type="submit">
|
||||
Guardar
|
||||
</button>
|
||||
@@ -181,15 +235,14 @@ export default function AddTime({
|
||||
className={`button buttonCancel ${lock ? "buttonLock" : "buttonOpenLock"
|
||||
}`}
|
||||
onClick={() => {
|
||||
setLock((prev) => !prev)
|
||||
setAmount('');
|
||||
setLock((prev) => !prev);
|
||||
setAmount("");
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
//IO
|
||||
//IO
|
||||
|
||||
@@ -23,21 +23,21 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.buttonLock{
|
||||
.buttonLock {
|
||||
padding: 0.8rem;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
right: 100px;
|
||||
background-color: #d32f2f;
|
||||
}
|
||||
|
||||
.buttonOpenLock{
|
||||
.buttonOpenLock {
|
||||
padding: 0.8rem;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
right: 100px;
|
||||
background-color: #8cd32f;
|
||||
}
|
||||
|
||||
.buttonOpenLock:hover{
|
||||
.buttonOpenLock:hover {
|
||||
background-color: #78b32c;
|
||||
}
|
||||
|
||||
@@ -63,6 +63,24 @@
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
@media(max-height:800px) {
|
||||
.addTime {
|
||||
margin-top: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
max-width: 320px;
|
||||
}
|
||||
|
||||
.firstPartInformationTime {
|
||||
max-width: 320px;
|
||||
}
|
||||
}
|
||||
|
||||
@media(max-height:800px) {
|
||||
.buttonLock {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
.containeInformationTime {
|
||||
flex-direction: column;
|
||||
|
||||
@@ -4,12 +4,18 @@ import ShowError from "@/app/Components/Global/ShowError";
|
||||
|
||||
import { GetRegisterStudent } from "@/app/lib/getRegisterStudent";
|
||||
|
||||
import "./addTime.css";
|
||||
import AddTime from "./Addtime";
|
||||
import Table from "@/app/Components/Global/table";
|
||||
|
||||
import "./addTime.css";
|
||||
import { Metadata } from "next";
|
||||
|
||||
const headers = ["Inscrito", "Tiempo", "Confirmó"];
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "AgregarTiempo",
|
||||
};
|
||||
|
||||
export default async function Page(props: {
|
||||
searchParams?: Promise<{ numAcount: string }>;
|
||||
}) {
|
||||
@@ -46,7 +52,7 @@ export default async function Page(props: {
|
||||
|
||||
return (
|
||||
<section className="containerSection">
|
||||
{errorMessage && <ShowError message={errorMessage} />}
|
||||
{errorMessage && <ShowError key={Date.now()} message={errorMessage} />}
|
||||
|
||||
<h2 className="title">AGREGAR TIEMPO</h2>
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import RegisterAlta from "@/app/Components/Alta/registerAlta";
|
||||
|
||||
import "./style.css";
|
||||
import { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Alta",
|
||||
};
|
||||
|
||||
export default async function Page(props: {
|
||||
searchParams?: Promise<{
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
import toast from "react-hot-toast";
|
||||
|
||||
import { getEquipoByCount } from "@/app/lib/getEquipoByCount";
|
||||
import { getMesaByCount } from "@/app/lib/getMesaByCount";
|
||||
|
||||
import "./asignacion.css";
|
||||
import Swal from "sweetalert2";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
import "./asignacion.css";
|
||||
|
||||
type Props = {
|
||||
inscripcion: any[];
|
||||
@@ -23,6 +25,10 @@ export default function PlaticaGate({ inscripcion, numAcount }: Props) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [tiempo, setTiempo] = useState<number>(15);
|
||||
const [bitacora, setBitacora] = useState<[] | null>([]);
|
||||
const [error, setError] = useState<string>("Equipo");
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
const fetchByCuenta = async (idCuenta: number) => {
|
||||
const [result, resultMesa] = await Promise.all([
|
||||
@@ -34,17 +40,23 @@ export default function PlaticaGate({ inscripcion, numAcount }: Props) {
|
||||
setBitacora(null);
|
||||
} else {
|
||||
setBitacora([]);
|
||||
if (!result?.error) toast.error("Ya cuentas con un equipo asignado");
|
||||
if (!resultMesa?.error) toast.error("Ya cuentas con una mesa asignada");
|
||||
if (!result?.error) {
|
||||
setError("Equipo");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!resultMesa?.error) {
|
||||
setError("Mesa");
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!numAcount) return;
|
||||
const idCuenta = numAcount;
|
||||
if (isNaN(idCuenta)) return;
|
||||
if (isNaN(numAcount)) return;
|
||||
|
||||
fetchByCuenta(idCuenta);
|
||||
fetchByCuenta(numAcount);
|
||||
}, [numAcount]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -55,7 +67,11 @@ export default function PlaticaGate({ inscripcion, numAcount }: Props) {
|
||||
);
|
||||
|
||||
if (!todasAsistieron) {
|
||||
toast.error("El alumno no asistió a todas las pláticas");
|
||||
Swal.fire({
|
||||
title: "El alumno no asistió a todas las pláticas!",
|
||||
icon: "error",
|
||||
draggable: true,
|
||||
});
|
||||
setPuedeContinuar(false);
|
||||
return;
|
||||
}
|
||||
@@ -64,27 +80,25 @@ export default function PlaticaGate({ inscripcion, numAcount }: Props) {
|
||||
}, [inscripcion]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!puedeContinuar || !numAcount) return;
|
||||
if (!puedeContinuar || !numAcount || !(error === "Equipo" || error === "Mesa")) return;
|
||||
|
||||
const fetchEquipos = async () => {
|
||||
try {
|
||||
|
||||
setLoadingEquipos(true);
|
||||
|
||||
const res = await fetch(
|
||||
const res = await axios.get(
|
||||
`${envConfig.apiUrl}/equipo/student/${numAcount}`,
|
||||
{
|
||||
cache: "no-store",
|
||||
},
|
||||
{ headers },
|
||||
);
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error("No se pudieron cargar los equipos");
|
||||
}
|
||||
|
||||
const data = await res.json();
|
||||
setEquipos(data);
|
||||
} catch (error) {
|
||||
toast.error("Error al cargar equipos disponibles");
|
||||
setEquipos(res.data);
|
||||
} catch (err) {
|
||||
Swal.fire({
|
||||
title: "Error al cargar equipos disponibles!",
|
||||
icon: "error",
|
||||
draggable: true,
|
||||
});
|
||||
} finally {
|
||||
setLoadingEquipos(false);
|
||||
}
|
||||
@@ -99,7 +113,11 @@ export default function PlaticaGate({ inscripcion, numAcount }: Props) {
|
||||
e.preventDefault();
|
||||
|
||||
if (!equipoSeleccionado) {
|
||||
toast.error("Selecciona un equipo");
|
||||
Swal.fire({
|
||||
title: "Selecciona un equipo!",
|
||||
icon: "error",
|
||||
draggable: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -111,32 +129,31 @@ export default function PlaticaGate({ inscripcion, numAcount }: Props) {
|
||||
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),
|
||||
await axios.post(`${envConfig.apiUrl}/bitacora`, body, { headers }
|
||||
);
|
||||
|
||||
setBitacora([]);
|
||||
|
||||
Swal.fire({
|
||||
title: "Equipo asignado correctamente!",
|
||||
icon: "success",
|
||||
draggable: true,
|
||||
});
|
||||
} catch (err) {
|
||||
Swal.fire({
|
||||
title: "No se pudo asignar el equipo!",
|
||||
icon: "error",
|
||||
draggable: true,
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error("Error al asignar equipo");
|
||||
}
|
||||
|
||||
setBitacora([])
|
||||
toast.success("Equipo asignado correctamente");
|
||||
Swal.fire({
|
||||
title: "Equipo asignado correctamente!",
|
||||
icon: "success",
|
||||
draggable: true,
|
||||
});
|
||||
} catch (error) {
|
||||
toast.error("No se pudo asignar el equipo");
|
||||
}
|
||||
};
|
||||
|
||||
if (bitacora) {
|
||||
return <></>;
|
||||
return error === "Mesa"
|
||||
? <p style={{ margin: "1rem", color: "red" }}>Ya cuentas con una mesa asignada</p>
|
||||
: error === "Equipo"
|
||||
? <p style={{ margin: "1rem", color: "red" }}>Ya cuentas con un equipo asignado</p>
|
||||
: null;
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -152,6 +169,8 @@ export default function PlaticaGate({ inscripcion, numAcount }: Props) {
|
||||
<option value={40}>40 minutos</option>
|
||||
<option value={60}>60 minutos</option>
|
||||
<option value={90}>90 minutos</option>
|
||||
<option value={120}>120 minutos</option>
|
||||
|
||||
</select>
|
||||
|
||||
<label>Seleccione un equipo</label>
|
||||
@@ -165,8 +184,7 @@ export default function PlaticaGate({ inscripcion, numAcount }: Props) {
|
||||
onClick={() => !loadingEquipos && setOpen(!open)}
|
||||
>
|
||||
{equipoSeleccionado ? (
|
||||
<span
|
||||
>
|
||||
<span>
|
||||
{equipoSeleccionado.ubicacion}{" "}
|
||||
{equipoSeleccionado.nombre_equipo}
|
||||
</span>
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
position: relative;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
margin-bottom: 1rem;
|
||||
font-size: 1.4rem;
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.customSelect.disabled {
|
||||
|
||||
@@ -6,33 +6,18 @@ import Information from "@/app/Components/Global/Information/information";
|
||||
import ShowError from "@/app/Components/Global/ShowError";
|
||||
import Table from "@/app/Components/Global/table";
|
||||
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
import { GetRegisterStudent } from "@/app/lib/getRegisterStudent";
|
||||
import PlaticaGate from "./PlaticaGate";
|
||||
import "@/app/globals.css";
|
||||
|
||||
async function getInscripcion(idCuenta: number) {
|
||||
try {
|
||||
const res = await fetch(`${envConfig.apiUrl}/alumno-inscrito/${idCuenta}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
cache: "no-store",
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`Error ${res.status}: ${res.statusText}`);
|
||||
}
|
||||
|
||||
return await res.json();
|
||||
} catch (error: any) {
|
||||
return { error: error.message || "No se pudo cargar la inscripción" };
|
||||
}
|
||||
}
|
||||
import { GetRegisterStudentSancion } from "@/app/lib/GetRegisterStudentSancion";
|
||||
import { Metadata } from "next";
|
||||
|
||||
const headers = ["Inscrito", "Tiempo", "Confirmó"];
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "AsignacionEquipo",
|
||||
};
|
||||
|
||||
export default async function Page(props: {
|
||||
searchParams?: Promise<{
|
||||
key?: string;
|
||||
@@ -53,7 +38,7 @@ export default async function Page(props: {
|
||||
if (numAcount) {
|
||||
const idCuenta = parseInt(numAcount);
|
||||
|
||||
const result = await GetRegisterStudent(idCuenta);
|
||||
const result = await GetRegisterStudentSancion(idCuenta);
|
||||
if (result.error) {
|
||||
errorMessage = `${result.error}`;
|
||||
} else {
|
||||
@@ -63,10 +48,9 @@ export default async function Page(props: {
|
||||
rawPlatica?.type === "Buffer"
|
||||
? Boolean(rawPlatica.data[0])
|
||||
: Boolean(rawPlatica);
|
||||
console.log(result);
|
||||
}
|
||||
|
||||
const inscResult = await getInscripcion(idCuenta);
|
||||
const inscResult = await GetRegisterStudent(idCuenta);
|
||||
if (!inscResult.error && Array.isArray(inscResult)) {
|
||||
inscripcion = inscResult;
|
||||
} else {
|
||||
@@ -124,7 +108,7 @@ export default async function Page(props: {
|
||||
label: "Cancelar tiempo",
|
||||
content: (
|
||||
<>
|
||||
<CheckBoxEquipo numAcount={params?.numAcount} machine={params?.machine} />
|
||||
<CheckBoxEquipo numAcount={numAcount} machine={machine} />
|
||||
</>
|
||||
),
|
||||
},
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import styles from "../Monitor/Page.module.css";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
type Mesa = {
|
||||
id_mesa: number;
|
||||
ocupado: number;
|
||||
};
|
||||
|
||||
export default function TableMesas() {
|
||||
const [mesas, setMesas] = useState<Mesa[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
const fetchMesas = async () => {
|
||||
try {
|
||||
const res = await axios.get(
|
||||
`${process.env.NEXT_PUBLIC_API_URL}/mesa/usoWhitout`,
|
||||
{ headers },
|
||||
);
|
||||
|
||||
setMesas(res.data);
|
||||
} catch (error) {
|
||||
console.error("Error cargando mesas:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchMesas();
|
||||
}, []);
|
||||
|
||||
if (loading) {
|
||||
return <div className={styles.tableContainer}>
|
||||
<table className={styles.machineTable}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Cargando mesas...</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.tableContainer}>
|
||||
<table className={styles.machineTable}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID Mesa</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{mesas.map((mesa) => (
|
||||
<tr key={mesa.id_mesa} className={!mesa.ocupado ? '' : styles.ocupado}>
|
||||
<td>{mesa.id_mesa}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
.tableTable{
|
||||
margin: 0.1rem;
|
||||
width: 100%;
|
||||
max-width: 250px;
|
||||
}
|
||||
.asignacion{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
}
|
||||
@@ -4,28 +4,23 @@ 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 TableMesas from "./TableMesas";
|
||||
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
import { GetRegisterStudent } from "@/app/lib/getRegisterStudent";
|
||||
import { GetRegisterStudentSancion } from "@/app/lib/GetRegisterStudentSancion";
|
||||
import { Metadata } from "next";
|
||||
|
||||
async function getInscripcion(idCuenta: number) {
|
||||
try {
|
||||
const res = await fetch(`${envConfig.apiUrl}/alumno-inscrito/${idCuenta}`, {
|
||||
cache: "no-store",
|
||||
});
|
||||
import './asignacion.css'
|
||||
|
||||
if (!res.ok) throw new Error("Error al cargar inscripción");
|
||||
return await res.json();
|
||||
} catch (error: any) {
|
||||
return { error: error.message };
|
||||
}
|
||||
}
|
||||
export const metadata: Metadata = {
|
||||
title: "AsignacionMesas",
|
||||
};
|
||||
|
||||
export default async function Page(props: {
|
||||
searchParams?: Promise<{
|
||||
key?: string;
|
||||
numAcount?: string;
|
||||
table?:number
|
||||
table?: string
|
||||
}>;
|
||||
}) {
|
||||
const params = await props.searchParams;
|
||||
@@ -33,7 +28,6 @@ export default async function Page(props: {
|
||||
const numAcount = params?.numAcount ?? null;
|
||||
const table = params?.table ?? null;
|
||||
|
||||
|
||||
let student: any = null;
|
||||
let platica: any = null;
|
||||
let inscripcion: any[] = [];
|
||||
@@ -42,7 +36,7 @@ export default async function Page(props: {
|
||||
if (numAcount) {
|
||||
const idCuenta = parseInt(numAcount);
|
||||
|
||||
const result = await GetRegisterStudent(idCuenta);
|
||||
const result = await GetRegisterStudentSancion(idCuenta);
|
||||
if (result.error) {
|
||||
errorMessage = `${result.error}`;
|
||||
} else {
|
||||
@@ -52,11 +46,10 @@ export default async function Page(props: {
|
||||
rawPlatica?.type === "Buffer"
|
||||
? Boolean(rawPlatica.data[0])
|
||||
: Boolean(rawPlatica);
|
||||
console.log(result);
|
||||
}
|
||||
|
||||
|
||||
const inscResult = await getInscripcion(idCuenta);
|
||||
|
||||
const inscResult = await GetRegisterStudent(idCuenta);
|
||||
if (!inscResult.error && Array.isArray(inscResult)) {
|
||||
inscripcion = inscResult;
|
||||
} else {
|
||||
@@ -66,45 +59,50 @@ export default async function Page(props: {
|
||||
|
||||
return (
|
||||
<section className="containerSection">
|
||||
{errorMessage && <ShowError message={errorMessage} />}
|
||||
{errorMessage && <ShowError key={Date.now()} message={errorMessage} />}
|
||||
|
||||
<h2 className="title"> ASIGNACIÓN DE MESAS </h2>
|
||||
|
||||
<Toggle
|
||||
defaultView={key}
|
||||
options={[
|
||||
{
|
||||
key: "Asignar",
|
||||
label: "Asignar mesa",
|
||||
content: (
|
||||
<>
|
||||
<SearchUser value={numAcount} />
|
||||
<div className="asignacion">
|
||||
<Toggle
|
||||
defaultView={key}
|
||||
options={[
|
||||
{
|
||||
key: "Asignar",
|
||||
label: "Asignar mesa",
|
||||
content: (
|
||||
<>
|
||||
<SearchUser value={numAcount} />
|
||||
|
||||
{student && (
|
||||
<>
|
||||
<div>
|
||||
<Information
|
||||
NoCuenta={student.id_cuenta}
|
||||
nombre={student.nombre}
|
||||
{student && (
|
||||
<>
|
||||
<div>
|
||||
<Information
|
||||
NoCuenta={student.id_cuenta}
|
||||
nombre={student.nombre}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<AsignacionMesas
|
||||
idCuenta={student.id_cuenta}
|
||||
inscripcion={inscripcion}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<AsignacionMesas
|
||||
idCuenta={student.id_cuenta}
|
||||
inscripcion={inscripcion}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "Liberar",
|
||||
label: "Cancelar mesa",
|
||||
content: <CheckBoxMesa numAcount={numAcount} table={table} />,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "Liberar",
|
||||
label: "Cancelar mesa",
|
||||
content: <CheckBoxMesa numAcount={numAcount} table={table} />,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<div className="tableTable">
|
||||
<TableMesas key={Date.now()}/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,24 +7,31 @@ import SearchUserWithDate from "@/app/Components/Global/SearchUser/SearchUserWit
|
||||
import ShowError from "@/app/Components/Global/ShowError";
|
||||
import Toggle from "@/app/Components/Global/Toggle/Toggle";
|
||||
import QuitarSancion from "@/app/Components/QuitarSancion/QuitarSancion";
|
||||
import { GetStudent } from "@/app/lib/getStudent";
|
||||
import { GetSancionByStudent } from "@/app/lib/getStudent copy";
|
||||
import { GetStudentWhitoutSancion } from "@/app/lib/getStudentWhitoutSancion";
|
||||
import { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "BitacoraSanciones",
|
||||
};
|
||||
|
||||
export default async function Page(props: {
|
||||
searchParams?: Promise<{
|
||||
key?: string;
|
||||
numAcount?: string;
|
||||
date?: string;
|
||||
}>;
|
||||
}) {
|
||||
const params = await props.searchParams;
|
||||
const key = params?.key && params.key;
|
||||
const numAcount = params?.numAcount ? params.numAcount : null;
|
||||
const date = params?.date ? params.date : null;
|
||||
|
||||
|
||||
let student: any = null;
|
||||
let errorMessage = "";
|
||||
|
||||
if (numAcount) {
|
||||
const result = await GetStudent(parseInt(numAcount));
|
||||
const result = await GetStudentWhitoutSancion(parseInt(numAcount));
|
||||
|
||||
if (result.error) {
|
||||
errorMessage = `${result.error}`;
|
||||
@@ -47,7 +54,7 @@ export default async function Page(props: {
|
||||
label: "Bitácora equipo",
|
||||
content: (
|
||||
<>
|
||||
<BitacoraEquipo />
|
||||
<BitacoraEquipo date={date}/>
|
||||
</>
|
||||
),
|
||||
},
|
||||
@@ -57,7 +64,12 @@ export default async function Page(props: {
|
||||
content: (
|
||||
<>
|
||||
<SearchUserWithDate value={numAcount} />
|
||||
<BitacoraAlumno />
|
||||
<BitacoraAlumno
|
||||
key={`${numAcount}-${date}`}
|
||||
numAcount={numAcount}
|
||||
date={date}
|
||||
/>
|
||||
|
||||
</>
|
||||
),
|
||||
},
|
||||
@@ -75,6 +87,7 @@ export default async function Page(props: {
|
||||
label: "Sanciones",
|
||||
content: (
|
||||
<>
|
||||
<SearchUser value={numAcount} />
|
||||
<Sanciones student={student} />
|
||||
</>
|
||||
),
|
||||
@@ -86,7 +99,7 @@ export default async function Page(props: {
|
||||
<>
|
||||
<div className="containerSection">
|
||||
<SearchUser value={numAcount} />
|
||||
{/* <QuitarSancion data={student} /> */}
|
||||
<QuitarSancion id_cuenta={Number(numAcount)} />
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import ChangePassword from "@/app/Components/auth/ChangePassword/changePassword";
|
||||
import { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "CambiarPass",
|
||||
};
|
||||
|
||||
export default async function Page(props: {
|
||||
searchParams?: Promise<{
|
||||
|
||||
@@ -5,9 +5,16 @@ import Information from "../../Components/Global/Information/information";
|
||||
import Impressions from "@/app/Components/Impressions/impressions";
|
||||
import ShowError from "@/app/Components/Global/ShowError";
|
||||
|
||||
import { GetStudent } from "@/app/lib/getStudent";
|
||||
import { cookies } from "next/headers";
|
||||
import { getCost } from "@/app/lib/getCost";
|
||||
import { GetStudentWhitoutSancion } from "@/app/lib/getStudentWhitoutSancion";
|
||||
|
||||
import "@/app/globals.css";
|
||||
import { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Impresiones",
|
||||
};
|
||||
|
||||
export default async function Page(props: {
|
||||
searchParams?: Promise<{
|
||||
@@ -19,12 +26,16 @@ export default async function Page(props: {
|
||||
const key = params?.key && params.key;
|
||||
const numAcount = params?.numAcount ? params.numAcount : null;
|
||||
|
||||
const cookieStore = await cookies();
|
||||
const role = cookieStore.get("role")?.value || "";
|
||||
const roleNumber = parseInt(role);
|
||||
|
||||
let student: any = null;
|
||||
let errorMessage = "";
|
||||
let costos: any[] = [];
|
||||
|
||||
if (numAcount) {
|
||||
const result = await GetStudent(parseInt(numAcount));
|
||||
|
||||
const result = await GetStudentWhitoutSancion(parseInt(numAcount));
|
||||
if (result.error) {
|
||||
errorMessage = `${result.error}`;
|
||||
} else {
|
||||
@@ -32,6 +43,110 @@ export default async function Page(props: {
|
||||
}
|
||||
}
|
||||
|
||||
let id_servicio: number;
|
||||
|
||||
switch (key) {
|
||||
case "B/N":
|
||||
id_servicio = 1;
|
||||
break;
|
||||
|
||||
case "color":
|
||||
id_servicio = 2;
|
||||
break;
|
||||
|
||||
case "Plotter":
|
||||
id_servicio = 3;
|
||||
break;
|
||||
|
||||
case "Escaner":
|
||||
id_servicio = 6;
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const response = await getCost();
|
||||
costos = response;
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error obteniendo costos:", error);
|
||||
}
|
||||
|
||||
const getCostsByService = (id_servicio: number) => {
|
||||
return costos
|
||||
.filter((c) => c.id_servicio === id_servicio)
|
||||
.map((c) => ({
|
||||
value: Number(c.costo),
|
||||
id_costo: c.id_costo,
|
||||
fecha_registro: c.fecha_registro,
|
||||
}));
|
||||
};
|
||||
|
||||
let options: any[] = [];
|
||||
|
||||
if (student) {
|
||||
options = [
|
||||
{
|
||||
key: "Recibo",
|
||||
label: "Recibo",
|
||||
content: <Receipt numAcount={student.id_cuenta} />,
|
||||
},
|
||||
{
|
||||
key: "B/N",
|
||||
label: "Impresiones B/N",
|
||||
content: (
|
||||
<Impressions
|
||||
costs={getCostsByService(1)}
|
||||
numAcount={student.id_cuenta}
|
||||
id_servicio={1}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "color",
|
||||
label: "Impresiones color",
|
||||
content: (
|
||||
<Impressions
|
||||
key={2}
|
||||
costs={getCostsByService(2)}
|
||||
numAcount={student.id_cuenta}
|
||||
id_servicio={2}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "Plotter",
|
||||
label: "Plotter",
|
||||
content: (
|
||||
<Impressions
|
||||
key={3}
|
||||
costs={getCostsByService(3)}
|
||||
numAcount={student.id_cuenta}
|
||||
id_servicio={3}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "Escaner",
|
||||
label: "Escaner",
|
||||
content: (
|
||||
<Impressions
|
||||
costs={getCostsByService(6)}
|
||||
numAcount={student.id_cuenta}
|
||||
id_servicio={6}
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
const optionsToUse =
|
||||
roleNumber === 5
|
||||
? options.filter(
|
||||
(option) => option.key === "Recibo" || option.key === "B/N"
|
||||
)
|
||||
: options;
|
||||
|
||||
return (
|
||||
<section className="containerSection">
|
||||
{errorMessage && <ShowError key={Date.now()} message={errorMessage} />}
|
||||
@@ -47,92 +162,9 @@ export default async function Page(props: {
|
||||
Carrera={student.carrera.carrera}
|
||||
Credito={student.credito}
|
||||
/>
|
||||
<div style={{ height: "10px" }}></div>
|
||||
|
||||
<Toggle
|
||||
defaultView={key}
|
||||
options={[
|
||||
{
|
||||
key: "Recibo",
|
||||
label: "Recibo",
|
||||
content: <Receipt numAcount={student.id_cuenta} />,
|
||||
},
|
||||
{
|
||||
key: "B/N",
|
||||
label: "Impresiones B/N",
|
||||
content: (
|
||||
<Impressions
|
||||
key={1}
|
||||
costs={[{ value: 1 }, { value: 2 }]}
|
||||
numAcount={student.id_cuenta}
|
||||
id_servicio={1}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "color",
|
||||
label: "Impresiones color",
|
||||
content: (
|
||||
<Impressions
|
||||
key={2}
|
||||
costs={[
|
||||
{ value: 4 },
|
||||
{ value: 5 },
|
||||
{ value: 6 },
|
||||
{ value: 7 },
|
||||
{ value: 8 },
|
||||
{ value: 10 },
|
||||
{ value: 12 },
|
||||
{ value: 14 },
|
||||
]}
|
||||
numAcount={student.id_cuenta}
|
||||
id_servicio={2}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "Plotter",
|
||||
label: "Plotter",
|
||||
content: (
|
||||
<Impressions
|
||||
key={3}
|
||||
costs={[
|
||||
{ value: 15 },
|
||||
{ value: 18 },
|
||||
{ value: 20 },
|
||||
{ value: 25 },
|
||||
{ value: 30 },
|
||||
{ value: 40 },
|
||||
{ value: 45 },
|
||||
{ value: 50 },
|
||||
{ value: 60 },
|
||||
{ value: 70 },
|
||||
{ value: 80 },
|
||||
{ value: 90 },
|
||||
{ value: 100 },
|
||||
{ value: 110 },
|
||||
{ value: 120 },
|
||||
{ value: 150 },
|
||||
{ value: 200 },
|
||||
]}
|
||||
numAcount={student.id_cuenta}
|
||||
id_servicio={3}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "Escaner",
|
||||
label: "Escaner",
|
||||
content: (
|
||||
<Impressions
|
||||
key={4}
|
||||
costs={[{ value: 1 }, { value: 2 }, { value: 5 }]}
|
||||
numAcount={student.id_cuenta}
|
||||
id_servicio={6}
|
||||
/>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Toggle defaultView={key} options={optionsToUse} />
|
||||
</>
|
||||
)}
|
||||
</section>
|
||||
|
||||
@@ -15,17 +15,18 @@
|
||||
|
||||
.form-container {
|
||||
gap: 10px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.form-container label {
|
||||
font-size: 14px;
|
||||
font-size: 1.4rem;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.form-container select {
|
||||
font-size: 13px;
|
||||
padding: 4px 8px;
|
||||
font-size: 1.4rem;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 6px;
|
||||
outline: none;
|
||||
@@ -47,7 +48,8 @@
|
||||
|
||||
.checkbox-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 240px); /* ancho fijo por columna */
|
||||
grid-template-columns: repeat(3, 240px);
|
||||
grid-template-rows: repeat(13, auto);
|
||||
gap: 10px 20px;
|
||||
flex-wrap: wrap;
|
||||
justify-content: start;
|
||||
@@ -56,7 +58,7 @@
|
||||
.checkbox-grid label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 13px;
|
||||
font-size: 1.4rem;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
width: fit-content;
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import { Metadata } from "next";
|
||||
import InformacionEquipo from "./InformacionEquipo";
|
||||
|
||||
import "./informacionequipo.css";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "InformacionEquipo",
|
||||
};
|
||||
|
||||
export default async function Page(props: {
|
||||
searchParams?: Promise<{
|
||||
key?: string;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
top: 0;
|
||||
background-color: #ffffff;
|
||||
width: 100%;
|
||||
max-width: 700px;
|
||||
max-width: 600px;
|
||||
border-radius: 4px;
|
||||
padding: 1rem;
|
||||
margin-top: 1rem;
|
||||
@@ -23,18 +23,35 @@
|
||||
max-width: 450px;
|
||||
}
|
||||
|
||||
.restarPass{
|
||||
margin-top: 2rem;
|
||||
.restarPass {
|
||||
margin-top: 3rem;
|
||||
height: fit-content;
|
||||
}
|
||||
|
||||
@media(max-height:800px) {
|
||||
.firstPartInformation {
|
||||
max-width: 320px;
|
||||
}
|
||||
|
||||
.inscripcion {
|
||||
max-width: 400px;
|
||||
padding: 0.5rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.restarPass {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
.containeInformation {
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.restarPass{
|
||||
|
||||
.restarPass {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
@@ -3,38 +3,20 @@ import Information from "@/app/Components/Global/Information/information";
|
||||
import ShowError from "@/app/Components/Global/ShowError";
|
||||
import Table from "@/app/Components/Global/table";
|
||||
import Inscripcion from "@/app/Components/Receipt/Inscripcion";
|
||||
import { GetStudent } from "@/app/lib/getStudent";
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
|
||||
import Link from "next/link";
|
||||
import { GetRegisterStudent } from "@/app/lib/getRegisterStudent";
|
||||
import { GetStudentWhitoutSancion } from "@/app/lib/getStudentWhitoutSancion";
|
||||
|
||||
import "./inscripcion.css";
|
||||
import Link from "next/link";
|
||||
|
||||
if (!envConfig.apiUrl) {
|
||||
console.error("API URL is not defined in envConfig");
|
||||
}
|
||||
|
||||
async function getInscripcion(idCuenta: number) {
|
||||
try {
|
||||
const res = await fetch(`${envConfig.apiUrl}/alumno-inscrito/${idCuenta}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
cache: "no-store",
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`Error ${res.status}: ${res.statusText}`);
|
||||
}
|
||||
|
||||
return await res.json();
|
||||
} catch (error: any) {
|
||||
return { error: error.message || "No se pudo cargar la inscripción" };
|
||||
}
|
||||
}
|
||||
import { Metadata } from "next";
|
||||
|
||||
const headers = ["Inscrito", "Tiempo", "Confirmó"];
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Inscripcion",
|
||||
};
|
||||
|
||||
export default async function Page(props: {
|
||||
searchParams?: Promise<{
|
||||
numAcount: string;
|
||||
@@ -46,18 +28,24 @@ export default async function Page(props: {
|
||||
let student: any = null;
|
||||
let inscripcion: any = null;
|
||||
let errorMessage = "";
|
||||
let isSancionado = false;
|
||||
|
||||
if (numAcount) {
|
||||
const idCuenta = parseInt(numAcount);
|
||||
|
||||
const studentResult = await GetStudent(idCuenta);
|
||||
const studentResult = await GetStudentWhitoutSancion(idCuenta);
|
||||
if (studentResult.error) {
|
||||
errorMessage = `${studentResult.error}`;
|
||||
|
||||
if (studentResult.status === 403) {
|
||||
isSancionado = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
student = studentResult;
|
||||
}
|
||||
|
||||
const inscResult = await getInscripcion(idCuenta);
|
||||
const inscResult = await GetRegisterStudent(idCuenta);
|
||||
if (!inscResult.error && Array.isArray(inscResult)) {
|
||||
inscripcion = inscResult;
|
||||
} else {
|
||||
@@ -67,12 +55,12 @@ export default async function Page(props: {
|
||||
|
||||
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",
|
||||
}))
|
||||
Inscrito: ins.plataforma?.nombre || "—",
|
||||
Tiempo: ins.tiempo_disponible
|
||||
? `${ins.tiempo_disponible} minutos`
|
||||
: "—",
|
||||
Confirmó: ins.platica.data?.[0] === 1 ? "sí" : "no",
|
||||
}))
|
||||
: [];
|
||||
|
||||
const plataformasInscritas = Array.isArray(inscripcion)
|
||||
@@ -99,7 +87,7 @@ export default async function Page(props: {
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{!student && numAcount && (
|
||||
{!student && numAcount && !isSancionado && (
|
||||
<Link href={`/Alta?numAcount=${numAcount}`}>
|
||||
<button
|
||||
className="button buttonSearch"
|
||||
|
||||
@@ -1,79 +1,157 @@
|
||||
"use client"
|
||||
"use client";
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
import axios from "axios";
|
||||
import { useEffect, useState } from "react";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
interface Periodo{
|
||||
semestre:string,
|
||||
import "./inscripciones.css"
|
||||
|
||||
interface Periodo {
|
||||
id_periodo: number;
|
||||
semestre: string;
|
||||
}
|
||||
|
||||
export default function Inscripciones() {
|
||||
const [periodo,setPeriodo]= useState<Periodo[]>([])
|
||||
interface ApiResponse {
|
||||
carrera: string;
|
||||
genero: string | null;
|
||||
profesor: string;
|
||||
total: string;
|
||||
}
|
||||
|
||||
useEffect(()=>{
|
||||
const getPeriodo = async()=>{
|
||||
const response = await axios.get(`${envConfig.apiUrl}/periodo`)
|
||||
setPeriodo(response.data)
|
||||
}
|
||||
getPeriodo()
|
||||
},[])
|
||||
interface TablaRow {
|
||||
carrera: string;
|
||||
genero: string | null;
|
||||
WINDOWS: number;
|
||||
MACINTOSH: number;
|
||||
LINUX: number;
|
||||
PROFESORES: number;
|
||||
TOTAL: number;
|
||||
}
|
||||
|
||||
type TipoConteo = "WINDOWS" | "MACINTOSH" | "LINUX" | "PROFESORES";
|
||||
|
||||
export default function Inscripciones() {
|
||||
const [periodo, setPeriodo] = useState<Periodo[]>([]);
|
||||
const [selectedPeriodo, setSelectedPeriodo] = useState<number | null>(null);
|
||||
const [tablaData, setTablaData] = useState<TablaRow[]>([]);
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
useEffect(() => {
|
||||
const getPeriodo = async () => {
|
||||
const response = await axios.get(`${envConfig.apiUrl}/periodo`, { headers }
|
||||
);
|
||||
setPeriodo(response.data);
|
||||
};
|
||||
getPeriodo();
|
||||
}, []);
|
||||
|
||||
const handleBuscar = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (!selectedPeriodo) return;
|
||||
|
||||
const response = await axios.get(
|
||||
`${envConfig.apiUrl}/alumno-inscrito/inscritos/${selectedPeriodo}`,
|
||||
{ headers }
|
||||
|
||||
);
|
||||
|
||||
const data: ApiResponse[] = response.data;
|
||||
|
||||
const agrupado: Record<string, TablaRow> = {};
|
||||
|
||||
data.forEach((item) => {
|
||||
const generoNormalizado =
|
||||
item.genero === "F" || item.genero === "Femenino"
|
||||
? "Femenino"
|
||||
: item.genero === "M" || item.genero === "Masculino"
|
||||
? "Masculino"
|
||||
: "-";
|
||||
|
||||
const key = `${item.carrera}_${generoNormalizado}`;
|
||||
|
||||
if (!agrupado[key]) {
|
||||
agrupado[key] = {
|
||||
carrera: item.carrera,
|
||||
genero: generoNormalizado,
|
||||
WINDOWS: 0,
|
||||
MACINTOSH: 0,
|
||||
LINUX: 0,
|
||||
PROFESORES: 0,
|
||||
TOTAL: 0,
|
||||
};
|
||||
}
|
||||
|
||||
const tipo = item.profesor as TipoConteo;
|
||||
const cantidad = Number(item.total);
|
||||
|
||||
agrupado[key][tipo] += cantidad;
|
||||
agrupado[key].TOTAL += cantidad;
|
||||
});
|
||||
|
||||
setTablaData(Object.values(agrupado));
|
||||
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="containerSection">
|
||||
<h2 className="title"> INSCRITOS </h2>
|
||||
<h2 className="title">INSCRITOS</h2>
|
||||
|
||||
<form className="containerForm">
|
||||
<form className="containerForm" onSubmit={handleBuscar}>
|
||||
<label>Seleccione el periodo</label>
|
||||
<div className="groupInput">
|
||||
<select>
|
||||
{periodo.map((p,index)=>(
|
||||
<option key={index}>
|
||||
{p.semestre}
|
||||
</option>))}
|
||||
<select
|
||||
onChange={(e) => setSelectedPeriodo(Number(e.target.value))}
|
||||
defaultValue=""
|
||||
>
|
||||
<option value="" disabled>
|
||||
Seleccione
|
||||
</option>
|
||||
|
||||
{periodo.map((p) => (
|
||||
<option key={p.id_periodo} value={p.id_periodo}>
|
||||
{p.semestre}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
<button className="button buttonSearch" type="submit">
|
||||
Buscar
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div>
|
||||
<div className="containerTable">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Carrera</th>
|
||||
<th>Genero</th>
|
||||
<th>WINDOWS</th>
|
||||
<th>MACINTOSH</th>
|
||||
<th>LINUX</th>
|
||||
<th>Profesores</th>
|
||||
<th>Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Impresione B/N</th>
|
||||
<th>Impresiones Color</th>
|
||||
<th>Plotteo</th>
|
||||
<th>Escaner</th>
|
||||
<th>Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>5,000</td>
|
||||
<td>10,000</td>
|
||||
<td>10,000</td>
|
||||
<td>20,000</td>
|
||||
<td>45,000</td>
|
||||
</tr>
|
||||
{tablaData.map((row, index) => (
|
||||
<tr key={index}>
|
||||
<td className="textLeft">{row.carrera}</td>
|
||||
<td>{row.genero ?? "-"}</td>
|
||||
<td>{row.WINDOWS}</td>
|
||||
<td>{row.MACINTOSH}</td>
|
||||
<td>{row.LINUX}</td>
|
||||
<td>{row.PROFESORES}</td>
|
||||
<td>{row.TOTAL}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
//IO
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
.containerTable{
|
||||
overflow: auto;
|
||||
scrollbar-width: none;
|
||||
background-color:rgba(84, 84, 84, 0.1) ;
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.textLeft{
|
||||
padding-left: 20px;
|
||||
text-align: start;
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -1,5 +1,10 @@
|
||||
import { Metadata } from "next";
|
||||
import Inscripciones from "./Inscripciones";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Inscritos",
|
||||
};
|
||||
|
||||
export default async function Page(props: {
|
||||
searchParams?: Promise<{
|
||||
period: string;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 10px;
|
||||
font-size: 14px;
|
||||
font-size: 1.4rem;
|
||||
cursor: pointer;
|
||||
transition: 0.3s;
|
||||
color: #333;
|
||||
@@ -48,7 +48,7 @@
|
||||
}
|
||||
|
||||
.formGroup label {
|
||||
font-size: 14px;
|
||||
font-size: 1.4rem;
|
||||
margin-bottom: 6px;
|
||||
color: #444;
|
||||
font-weight: 500;
|
||||
@@ -59,7 +59,7 @@
|
||||
padding: 8px 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
font-size: 1.4rem;
|
||||
transition: border 0.3s, box-shadow 0.3s;
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
.btn {
|
||||
padding: 8px 16px;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
font-size: 1.4rem;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
transition: 0.3s;
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import EnviarMensaje from "@/app/Components/EviarMensaje/EnviarMensaje";
|
||||
import EnviarMensajeSala from "@/app/Components/EviarMensaje/EnviarMensajeSala";
|
||||
import Toggle from "@/app/Components/Global/Toggle/Toggle";
|
||||
import { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Mensajes",
|
||||
};
|
||||
|
||||
export default async function Page(props: {
|
||||
searchParams?: Promise<{
|
||||
|
||||
+133
-74
@@ -1,85 +1,144 @@
|
||||
'use client';
|
||||
|
||||
type EstadoPC = 'libre' | 'ocupada' | 'fallo';
|
||||
|
||||
const colores: Record<EstadoPC, string> = {
|
||||
libre: '#22c55e', // verde
|
||||
ocupada: '#ef4444', // rojo
|
||||
fallo: '#facc15', // amarillo
|
||||
};
|
||||
|
||||
const pcs = [
|
||||
{
|
||||
id: 'PC-01',
|
||||
x: 120,
|
||||
y: 180,
|
||||
width: 40,
|
||||
height: 40,
|
||||
estado: 'libre' as EstadoPC,
|
||||
},
|
||||
{
|
||||
id: 'PC-02',
|
||||
x: 170,
|
||||
y: 180,
|
||||
width: 40,
|
||||
height: 40,
|
||||
estado: 'ocupada' as EstadoPC,
|
||||
},
|
||||
{
|
||||
id: 'PC-03',
|
||||
x: 220,
|
||||
y: 180,
|
||||
width: 40,
|
||||
height: 40,
|
||||
estado: 'fallo' as EstadoPC,
|
||||
},
|
||||
];
|
||||
|
||||
export default function DSC() {
|
||||
return (
|
||||
<svg viewBox="0 0 1500 900" width="100%" height="auto">
|
||||
<svg viewBox="0 0 1600 1000">
|
||||
|
||||
{/* FONDO */}
|
||||
<image
|
||||
href="/plano.svg"
|
||||
width="100%"
|
||||
height="100%"
|
||||
preserveAspectRatio="xMidYMid meet"
|
||||
pointerEvents="none"
|
||||
{/* CONTORNO EXTERIOR */}
|
||||
<rect
|
||||
x="20"
|
||||
y="20"
|
||||
width="1560"
|
||||
height="960"
|
||||
fill="none"
|
||||
stroke="black"
|
||||
strokeWidth="4"
|
||||
/>
|
||||
|
||||
{/* CAPA INTERACTIVA */}
|
||||
<g>
|
||||
{pcs.map(pc => (
|
||||
<g key={pc.id}>
|
||||
{/* CUADRO */}
|
||||
<rect
|
||||
x={pc.x}
|
||||
y={pc.y}
|
||||
width={pc.width}
|
||||
height={pc.height}
|
||||
fill={colores[pc.estado]}
|
||||
stroke="#bb4242"
|
||||
strokeWidth={1}
|
||||
rx={4}
|
||||
style={{ cursor: 'pointer' }}
|
||||
onClick={() => console.log(pc.id)}
|
||||
/>
|
||||
{/* ===== BLOQUE SUPERIOR IZQUIERDO (AULAS Y SALAS) ===== */}
|
||||
|
||||
{/* NÚMERO */}
|
||||
<text
|
||||
x={pc.x + pc.width / 2}
|
||||
y={pc.y + pc.height / 2 + 5}
|
||||
textAnchor="middle"
|
||||
fontSize={12}
|
||||
fill="#000"
|
||||
pointerEvents="none"
|
||||
>
|
||||
{pc.id.replace('PC-', '')}
|
||||
</text>
|
||||
</g>
|
||||
))}
|
||||
</g>
|
||||
<rect x="40" y="40" width="400" height="180"
|
||||
fill="none" stroke="black" strokeWidth="2" />
|
||||
<text x="240" y="30" textAnchor="middle" fontSize="18" fontWeight="bold">
|
||||
AULA 5
|
||||
</text>
|
||||
|
||||
<rect x="40" y="220" width="400" height="150"
|
||||
fill="none" stroke="black" strokeWidth="2" />
|
||||
<text x="240" y="210" textAnchor="middle" fontSize="16">
|
||||
SALA USOS MÚLTIPLES
|
||||
</text>
|
||||
|
||||
<rect x="40" y="370" width="400" height="150"
|
||||
fill="none" stroke="black" strokeWidth="2" />
|
||||
<text x="240" y="360" textAnchor="middle" fontSize="16">
|
||||
SALA DE ENTRENAMIENTO
|
||||
</text>
|
||||
|
||||
{/* ===== BLOQUE CENTRAL WINDOWS ===== */}
|
||||
|
||||
<rect x="460" y="40" width="700" height="450"
|
||||
fill="none" stroke="black" strokeWidth="3" />
|
||||
<text x="810" y="30" textAnchor="middle" fontSize="22" fontWeight="bold">
|
||||
ÁREA WINDOWS
|
||||
</text>
|
||||
|
||||
{/* División interna Windows */}
|
||||
<line x1="460" y1="260" x2="1160" y2="260"
|
||||
stroke="black" strokeWidth="2" />
|
||||
|
||||
{/* ===== BLOQUE DERECHO MAC ===== */}
|
||||
|
||||
<rect x="1200" y="40" width="350" height="300"
|
||||
fill="none" stroke="black" strokeWidth="3" />
|
||||
<text x="1375" y="30" textAnchor="middle" fontSize="22" fontWeight="bold">
|
||||
ÁREA MAC
|
||||
</text>
|
||||
|
||||
{/* ===== ROBÓTICA ===== */}
|
||||
|
||||
<rect x="1200" y="360" width="350" height="200"
|
||||
fill="none" stroke="black" strokeWidth="3" />
|
||||
<text x="1375" y="350" textAnchor="middle" fontSize="18" fontWeight="bold">
|
||||
ROBÓTICA
|
||||
</text>
|
||||
|
||||
{/* ===== ADMINISTRACIÓN Y OFICINAS ===== */}
|
||||
|
||||
<rect x="460" y="520" width="300" height="150"
|
||||
fill="none" stroke="black" strokeWidth="2" />
|
||||
<text x="610" y="510" textAnchor="middle" fontSize="16">
|
||||
ADMINISTRACIÓN
|
||||
</text>
|
||||
|
||||
<rect x="780" y="520" width="200" height="150"
|
||||
fill="none" stroke="black" strokeWidth="2" />
|
||||
<text x="880" y="510" textAnchor="middle" fontSize="16">
|
||||
ASIGNACIÓN
|
||||
</text>
|
||||
|
||||
<rect x="1000" y="520" width="200" height="150"
|
||||
fill="none" stroke="black" strokeWidth="2" />
|
||||
<text x="1100" y="510" textAnchor="middle" fontSize="16">
|
||||
IMPRESIÓN
|
||||
</text>
|
||||
|
||||
{/* ===== CUBÍCULOS ===== */}
|
||||
|
||||
{Array.from({ length: 8 }).map((_, i) => (
|
||||
<rect
|
||||
key={i}
|
||||
x={460 + i * 90}
|
||||
y={700}
|
||||
width="80"
|
||||
height="120"
|
||||
fill="none"
|
||||
stroke="black"
|
||||
strokeWidth="2"
|
||||
/>
|
||||
))}
|
||||
|
||||
<text x="460" y="690" fontSize="14">
|
||||
CUBÍCULOS 1–8
|
||||
</text>
|
||||
|
||||
{/* ===== SANITARIOS ===== */}
|
||||
|
||||
<rect x="40" y="600" width="200" height="200"
|
||||
fill="none" stroke="black" strokeWidth="2" />
|
||||
<text x="140" y="590" textAnchor="middle" fontSize="16">
|
||||
SANITARIO HOMBRES
|
||||
</text>
|
||||
|
||||
<rect x="260" y="600" width="200" height="200"
|
||||
fill="none" stroke="black" strokeWidth="2" />
|
||||
<text x="360" y="590" textAnchor="middle" fontSize="16">
|
||||
SANITARIO MUJERES
|
||||
</text>
|
||||
|
||||
{/* ===== SALIDA EMERGENCIA ===== */}
|
||||
|
||||
<text
|
||||
x="1530"
|
||||
y="900"
|
||||
transform="rotate(-90 1530,900)"
|
||||
fontSize="16"
|
||||
fontWeight="bold"
|
||||
>
|
||||
SALIDA DE EMERGENCIA
|
||||
</text>
|
||||
|
||||
{/* ===== ENTRADA PRINCIPAL ===== */}
|
||||
|
||||
<text
|
||||
x="800"
|
||||
y="960"
|
||||
textAnchor="middle"
|
||||
fontSize="20"
|
||||
fontWeight="bold"
|
||||
>
|
||||
ENTRADA Y SALIDA PRINCIPAL
|
||||
</text>
|
||||
|
||||
</svg>
|
||||
);
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import styles from "./Page.module.css";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
type AreaUbicacion = {
|
||||
id_area_ubicacion: number;
|
||||
@@ -23,21 +25,36 @@ export default function MachineTable() {
|
||||
const [selectedArea, setSelectedArea] = useState("Todo");
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
const fetchMachines = async () => {
|
||||
const res = await fetch(
|
||||
`${process.env.NEXT_PUBLIC_API_URL}/equipo/disable`,
|
||||
{ cache: "no-store" },
|
||||
);
|
||||
setMachines(await res.json());
|
||||
setLoading(false);
|
||||
try {
|
||||
|
||||
const res = await axios.get(
|
||||
`${process.env.NEXT_PUBLIC_API_URL}/equipo/disable`,
|
||||
{ headers },
|
||||
);
|
||||
|
||||
setMachines(res.data);
|
||||
} catch (error) {
|
||||
console.error("Error cargando equipos:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchAreas = async () => {
|
||||
const res = await fetch(
|
||||
`${process.env.NEXT_PUBLIC_API_URL}/area-ubicacion`,
|
||||
{ cache: "no-store" },
|
||||
);
|
||||
setAreas(await res.json());
|
||||
try {
|
||||
const res = await axios.get(
|
||||
`${process.env.NEXT_PUBLIC_API_URL}/area-ubicacion`,
|
||||
{ headers },
|
||||
);
|
||||
|
||||
setAreas(res.data);
|
||||
} catch (error) {
|
||||
console.error("Error cargando áreas:", error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@@ -53,10 +70,8 @@ export default function MachineTable() {
|
||||
selectedArea === "Todo"
|
||||
? machines
|
||||
: machines.filter(
|
||||
(machine) => machine.areaUbicacion.area === selectedArea,
|
||||
);
|
||||
|
||||
if (loading) return <p>Cargando equipos...</p>;
|
||||
(machine) => machine.areaUbicacion.area === selectedArea,
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={styles.tableContainer}>
|
||||
@@ -108,3 +123,4 @@ export default function MachineTable() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
//IO
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import styles from "./Page.module.css";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
type AreaUbicacion = {
|
||||
id_area_ubicacion: number;
|
||||
@@ -14,31 +16,46 @@ type Equipo = {
|
||||
ubicacion: string;
|
||||
plataforma: string;
|
||||
area: string;
|
||||
ocupado:boolean;
|
||||
ocupado: boolean;
|
||||
};
|
||||
|
||||
|
||||
export default function MachineTableActive() {
|
||||
const [machines, setMachines] = useState<Equipo[]>([]);
|
||||
const [areas, setAreas] = useState<AreaUbicacion[]>([]);
|
||||
const [selectedArea, setSelectedArea] = useState("Todo");
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
const fetchMachines = async () => {
|
||||
const res = await fetch(
|
||||
`${process.env.NEXT_PUBLIC_API_URL}/equipo/active`,
|
||||
{ cache: "no-store" },
|
||||
);
|
||||
setMachines(await res.json());
|
||||
setLoading(false);
|
||||
try {
|
||||
|
||||
const res = await axios.get(
|
||||
`${process.env.NEXT_PUBLIC_API_URL}/equipo/active`,
|
||||
{ headers },
|
||||
);
|
||||
|
||||
setMachines(res.data);
|
||||
} catch (error) {
|
||||
console.error("Error cargando equipos:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchAreas = async () => {
|
||||
const res = await fetch(
|
||||
`${process.env.NEXT_PUBLIC_API_URL}/area-ubicacion`,
|
||||
{ cache: "no-store" },
|
||||
);
|
||||
setAreas(await res.json());
|
||||
try {
|
||||
const res = await axios.get(
|
||||
`${process.env.NEXT_PUBLIC_API_URL}/area-ubicacion`,
|
||||
{ headers },
|
||||
|
||||
);
|
||||
|
||||
setAreas(res.data);
|
||||
} catch (error) {
|
||||
console.error("Error cargando áreas:", error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@@ -50,8 +67,8 @@ export default function MachineTableActive() {
|
||||
selectedArea === "Todo"
|
||||
? machines
|
||||
: machines.filter(
|
||||
(machine) => machine.area === selectedArea,
|
||||
);
|
||||
(machine) => machine.area === selectedArea,
|
||||
);
|
||||
|
||||
if (loading) return <p>Cargando equipos...</p>;
|
||||
|
||||
@@ -66,7 +83,7 @@ export default function MachineTableActive() {
|
||||
<th>Área</th>
|
||||
<th>Disponible</th>
|
||||
</tr>
|
||||
<tr style={{position:"relative", zIndex:"0"}}>
|
||||
<tr style={{ position: "relative", zIndex: "0" }}>
|
||||
<th />
|
||||
<th />
|
||||
<th />
|
||||
@@ -90,7 +107,7 @@ export default function MachineTableActive() {
|
||||
|
||||
<tbody>
|
||||
{filteredMachines.map((machine) => (
|
||||
<tr key={machine.id_equipo} className={!machine.ocupado ? '':styles.ocupado}>
|
||||
<tr key={machine.id_equipo} className={!machine.ocupado ? '' : styles.ocupado}>
|
||||
<td>{machine.ubicacion}</td>
|
||||
<td>{machine.nombre_equipo}</td>
|
||||
<td className={styles[machine.plataforma]}>
|
||||
@@ -105,3 +122,4 @@ export default function MachineTableActive() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
//IO
|
||||
@@ -17,7 +17,7 @@
|
||||
}
|
||||
|
||||
.ocupado {
|
||||
background-color: rgb(173, 233, 253);
|
||||
background-color: #54bbfc !important;
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import styles from "./Page.module.css";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
type Mesa = {
|
||||
id_mesa: number;
|
||||
ocupado: number;
|
||||
};
|
||||
|
||||
export default function TableTable() {
|
||||
const [mesas, setMesas] = useState<Mesa[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
const fetchMesas = async () => {
|
||||
try {
|
||||
const res = await axios.get(
|
||||
`${process.env.NEXT_PUBLIC_API_URL}/mesa/uso`,
|
||||
{ headers },
|
||||
);
|
||||
|
||||
setMesas(res.data);
|
||||
} catch (error) {
|
||||
console.error("Error cargando mesas:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchMesas();
|
||||
}, []);
|
||||
|
||||
if (loading) {
|
||||
return <p>Cargando mesas...</p>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.tableContainer}>
|
||||
<table className={styles.machineTable}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID Mesa</th>
|
||||
<th>Disponible</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{mesas.map((mesa) => (
|
||||
<tr key={mesa.id_mesa} className={!mesa.ocupado ? '' : styles.ocupado}>
|
||||
<td>{mesa.id_mesa}</td>
|
||||
<td>
|
||||
{mesa.ocupado === 1 ? "No" : "Si"}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,29 +1,34 @@
|
||||
import Toggle from "@/app/Components/Global/Toggle/Toggle";
|
||||
import MachineTable from "./MachineTable";
|
||||
import styles from "./Page.module.css";
|
||||
import MachineTableActive from "./MachineTableActive";
|
||||
import DSC from "./DSC";
|
||||
import ToggleTable from "@/app/Components/Global/Toggle/ToggleTable";
|
||||
import TableTable from "./TableTable";
|
||||
import { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Monitor",
|
||||
};
|
||||
|
||||
export default async function Page(props: {
|
||||
searchParams?: Promise<{ numAcount: string; key: string }>;
|
||||
}) {
|
||||
const params = await props.searchParams;
|
||||
const numAcount = params?.numAcount ?? null;
|
||||
const key = params?.key ?? "active";
|
||||
const key = params?.key ?? "Equipos";
|
||||
|
||||
return (
|
||||
<section className="containerSection">
|
||||
<h2 className="title">MONITOR DE MÁQUINAS</h2>
|
||||
<h2 className="title">MONITOR</h2>
|
||||
|
||||
<div className={styles.actions}>
|
||||
<button className={styles.resetButton}>Actualizar información</button>
|
||||
</div>
|
||||
<Toggle
|
||||
<ToggleTable
|
||||
defaultView={key}
|
||||
options={[
|
||||
{
|
||||
key: "active",
|
||||
label: "Disponibles",
|
||||
key: "Equipos",
|
||||
label: "Equipos",
|
||||
content: (
|
||||
<>
|
||||
<MachineTableActive />
|
||||
@@ -31,11 +36,11 @@ export default async function Page(props: {
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "disable",
|
||||
label: "No Disponibles",
|
||||
key: "Mesas",
|
||||
label: "Mesas",
|
||||
content: (
|
||||
<>
|
||||
<MachineTable />
|
||||
<TableTable />
|
||||
</>
|
||||
),
|
||||
},
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
import { Metadata } from "next";
|
||||
|
||||
interface TotalServicioPeriodo {
|
||||
nombre_servicio: string;
|
||||
periodo: string;
|
||||
monto_total: number;
|
||||
}
|
||||
|
||||
interface Servicio {
|
||||
id_servicio: number;
|
||||
servicio: string;
|
||||
}
|
||||
|
||||
interface Periodo {
|
||||
id_periodo: number;
|
||||
semestre: string;
|
||||
}
|
||||
|
||||
export default function ReporteTotalesPage() {
|
||||
const [totales, setTotales] = useState<TotalServicioPeriodo[]>([]);
|
||||
const [servicios, setServicios] = useState<Servicio[]>([]);
|
||||
const [periodos, setPeriodos] = useState<Periodo[]>([]);
|
||||
const [cargando, setCargando] = useState(true);
|
||||
|
||||
const [periodoInicio, setPeriodoInicio] = useState<string>("");
|
||||
const [periodoFin, setPeriodoFin] = useState<string>("");
|
||||
const [servicioId, setServicioId] = useState<string>("");
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const [serviciosRes, periodosRes] = await Promise.all([
|
||||
axios.get(`${envConfig.apiUrl}/servicio`, { headers }),
|
||||
axios.get(`${envConfig.apiUrl}/periodo`, { headers }),
|
||||
]);
|
||||
setServicios(serviciosRes.data);
|
||||
setPeriodos(periodosRes.data);
|
||||
} catch (error) {
|
||||
console.error("Error al cargar servicios o periodos", error);
|
||||
}
|
||||
};
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
const obtenerTotales = async () => {
|
||||
setCargando(true);
|
||||
try {
|
||||
// Construir query params
|
||||
const params = new URLSearchParams();
|
||||
if (periodoInicio) params.append("periodoInicio", periodoInicio);
|
||||
if (periodoFin) params.append("periodoFin", periodoFin);
|
||||
if (servicioId) params.append("servicioId", servicioId);
|
||||
|
||||
const url = `${envConfig.apiUrl}/detalle-servicio/totales-por-periodo?${params.toString()}`;
|
||||
const res = await axios.get(url, { headers });
|
||||
setTotales(res.data);
|
||||
} catch (error) {
|
||||
console.error("Error al obtener totales", error);
|
||||
} finally {
|
||||
setCargando(false);
|
||||
}
|
||||
};
|
||||
|
||||
const aplicarFiltros = () => {
|
||||
obtenerTotales();
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1 style={{ color: "rgb(3, 1, 72)" }}>REPORTE DE TOTALES POR SERVICIO Y PERIODO</h1>
|
||||
|
||||
<div style={{ marginBottom: "20px", display: "flex", gap: "10px", flexWrap: "wrap" }}>
|
||||
<select
|
||||
value={periodoInicio}
|
||||
onChange={(e) => setPeriodoInicio(e.target.value)}
|
||||
>
|
||||
<option value="">Periodo inicio (todos)</option>
|
||||
{periodos.map((p) => (
|
||||
<option key={p.id_periodo} value={p.id_periodo}>
|
||||
{p.semestre}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
<select
|
||||
value={periodoFin}
|
||||
onChange={(e) => setPeriodoFin(e.target.value)}
|
||||
>
|
||||
<option value="">Periodo fin (todos)</option>
|
||||
{periodos.map((p) => (
|
||||
<option key={p.id_periodo} value={p.id_periodo}>
|
||||
{p.semestre}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
<select
|
||||
value={servicioId}
|
||||
onChange={(e) => setServicioId(e.target.value)}
|
||||
>
|
||||
<option value="">Todos los servicios</option>
|
||||
{servicios.map((s) => (
|
||||
<option key={s.id_servicio} value={s.id_servicio}>
|
||||
{s.servicio}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
<button onClick={aplicarFiltros}>Filtrar</button>
|
||||
</div>
|
||||
|
||||
{cargando ? (
|
||||
<p>Cargando...</p>
|
||||
) : (
|
||||
<div style={{ overflow: "auto", maxHeight: "500px" }}>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Servicio</th>
|
||||
<th>Periodo</th>
|
||||
<th>Monto Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{totales.map((item, index) => (
|
||||
<tr key={index}>
|
||||
<td>{item.nombre_servicio}</td>
|
||||
<td>{item.periodo}</td>
|
||||
<td>${item.monto_total.toFixed(2)}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
import { Metadata } from "next";
|
||||
|
||||
interface Periodo {
|
||||
id_periodo: number;
|
||||
semestre: string;
|
||||
fecha_inicio_servicio: string;
|
||||
fecha_fin_servicio: string;
|
||||
activo: {
|
||||
type: string;
|
||||
data: number[];
|
||||
};
|
||||
}
|
||||
|
||||
export default function PeriodoPage() {
|
||||
|
||||
const [periodos, setPeriodos] = useState<Periodo[]>([]);
|
||||
const [semestre, setSemestre] = useState("");
|
||||
const [fechaInicio, setFechaInicio] = useState("");
|
||||
const [fechaFin, setFechaFin] = useState("");
|
||||
const [modoEdicion, setModoEdicion] = useState(false);
|
||||
const [idEditar, setIdEditar] = useState<number | null>(null);
|
||||
|
||||
const API = `${envConfig.apiUrl}/periodo`;
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
const obtenerPeriodos = async () => {
|
||||
try {
|
||||
const res = await axios.get(API, { headers });
|
||||
setPeriodos(res.data);
|
||||
} catch (error) {
|
||||
console.error("Error al obtener periodos", error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
obtenerPeriodos();
|
||||
}, []);
|
||||
|
||||
const handleSemestreChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const valor = e.target.value;
|
||||
|
||||
if (/^\d{0,6}$/.test(valor)) {
|
||||
setSemestre(valor);
|
||||
}
|
||||
};
|
||||
|
||||
const crearPeriodo = async () => {
|
||||
if (semestre.length !== 6) {
|
||||
alert("El semestre debe tener exactamente 6 dígitos.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await axios.post(
|
||||
API,
|
||||
{
|
||||
semestre,
|
||||
fecha_inicio_servicio: fechaInicio,
|
||||
fecha_fin_servicio: fechaFin,
|
||||
activo: true,
|
||||
},
|
||||
{ headers }
|
||||
);
|
||||
|
||||
limpiarFormulario();
|
||||
obtenerPeriodos();
|
||||
} catch (error) {
|
||||
console.error("Error al crear periodo", error);
|
||||
}
|
||||
};
|
||||
|
||||
const cargarPeriodo = (p: Periodo) => {
|
||||
setModoEdicion(true);
|
||||
setIdEditar(p.id_periodo);
|
||||
setSemestre(p.semestre);
|
||||
setFechaInicio(p.fecha_inicio_servicio);
|
||||
setFechaFin(p.fecha_fin_servicio);
|
||||
};
|
||||
|
||||
|
||||
const modificarPeriodo = async () => {
|
||||
if (semestre.length !== 6) {
|
||||
alert("El semestre debe tener exactamente 6 dígitos.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await axios.put(
|
||||
`${API}/${idEditar}`,
|
||||
{
|
||||
semestre,
|
||||
fecha_inicio_servicio: fechaInicio,
|
||||
fecha_fin_servicio: fechaFin,
|
||||
},
|
||||
{ headers }
|
||||
);
|
||||
|
||||
limpiarFormulario();
|
||||
obtenerPeriodos();
|
||||
} catch (error) {
|
||||
console.error("Error al modificar periodo", error);
|
||||
}
|
||||
};
|
||||
|
||||
const limpiarFormulario = () => {
|
||||
setSemestre("");
|
||||
setFechaInicio("");
|
||||
setFechaFin("");
|
||||
setModoEdicion(false);
|
||||
setIdEditar(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1 style={{ color: "rgb(3, 1, 72)" }}>PERIODO ESCOLAR</h1>
|
||||
|
||||
<div style={{ marginBottom: "10px" }}>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Periodo (6 dígitos)"
|
||||
value={semestre}
|
||||
maxLength={6}
|
||||
onChange={handleSemestreChange}
|
||||
/>
|
||||
|
||||
<label style={{ color: "rgb(3, 1, 72)" }}>
|
||||
Elige la fecha de inicio de Periodo
|
||||
</label>
|
||||
<input
|
||||
type="date"
|
||||
value={fechaInicio}
|
||||
onChange={(e) => setFechaInicio(e.target.value)}
|
||||
/>
|
||||
|
||||
<label style={{ color: "rgb(3, 1, 72)" }}>
|
||||
Elige la fecha de fin de Periodo
|
||||
</label>
|
||||
<input
|
||||
type="date"
|
||||
value={fechaFin}
|
||||
onChange={(e) => setFechaFin(e.target.value)}
|
||||
/>
|
||||
|
||||
{modoEdicion ? (
|
||||
<>
|
||||
<button
|
||||
className="button buttonSearch"
|
||||
onClick={modificarPeriodo}
|
||||
>
|
||||
Guardar Cambios
|
||||
</button>
|
||||
|
||||
<button
|
||||
className="button buttonCancel"
|
||||
onClick={limpiarFormulario}
|
||||
>
|
||||
Cancelar
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
<button
|
||||
className="button buttonSearch"
|
||||
onClick={crearPeriodo}
|
||||
>
|
||||
Crear Periodo
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div style={{ overflow: "auto", maxHeight: "350px" }}>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>PERIODO</th>
|
||||
<th>Inicio</th>
|
||||
<th>Fin</th>
|
||||
<th>Activo</th>
|
||||
<th>Acción</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{periodos.map((p) => (
|
||||
<tr key={p.id_periodo}>
|
||||
<td>{p.id_periodo}</td>
|
||||
<td>{p.semestre}</td>
|
||||
<td>{p.fecha_inicio_servicio}</td>
|
||||
<td>{p.fecha_fin_servicio}</td>
|
||||
<td>{p.activo.data[0] === 1 ? "Sí" : "No"}</td>
|
||||
<td>
|
||||
<button
|
||||
className="button buttonSearch"
|
||||
onClick={() => cargarPeriodo(p)}
|
||||
>
|
||||
Modificar
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
//IO
|
||||
@@ -1,8 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import styleprograms from "./programas.module.css";
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
import styleprograms from "./programas.module.css";
|
||||
import axios from "axios";
|
||||
import Swal from "sweetalert2";
|
||||
import Cookies from "js-cookie";
|
||||
import { Metadata } from "next";
|
||||
|
||||
interface Programa {
|
||||
id_programa: number;
|
||||
@@ -11,66 +15,93 @@ interface Programa {
|
||||
|
||||
export default function Page() {
|
||||
const [modo, setModo] = useState("ver");
|
||||
|
||||
const [programaSeleccionado, setProgramaSeleccionado] = useState("");
|
||||
const [programas, setProgramas] = useState<Programa[]>([]);
|
||||
const [nombrePrograma, setNombrePrograma] = useState("");
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
const cargarProgramas = async () => {
|
||||
try {
|
||||
const response = await axios.get(`${envConfig.apiUrl}/programa/`, { headers }
|
||||
);
|
||||
setProgramas(response.data);
|
||||
} catch (error: any) {
|
||||
console.error("Error al cargar programas:", error);
|
||||
Swal.fire({
|
||||
title: "Error al cargar programas",
|
||||
text: error.response?.data?.message || error.message,
|
||||
icon: "error",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetch(`${envConfig.apiUrl}/programa/`)
|
||||
.then((res) => res.json())
|
||||
.then((data) => setProgramas(data))
|
||||
.catch((error) => console.error("Error al cargar programas:", error));
|
||||
cargarProgramas();
|
||||
}, []);
|
||||
|
||||
const handleInsertar = async () => {
|
||||
if (!nombrePrograma) return;
|
||||
if (!nombrePrograma) return;
|
||||
|
||||
await fetch(`${envConfig.apiUrl}/programa`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
programa: nombrePrograma,
|
||||
}),
|
||||
});
|
||||
try {
|
||||
await axios.post(`${envConfig.apiUrl}/programa`, {
|
||||
programa: nombrePrograma,
|
||||
}, { headers }
|
||||
);
|
||||
|
||||
const res = await fetch(`${envConfig.apiUrl}/programa/`);
|
||||
const data = await res.json();
|
||||
setProgramas(data);
|
||||
await cargarProgramas();
|
||||
|
||||
setNombrePrograma("");
|
||||
setModo("ver");
|
||||
};
|
||||
setNombrePrograma("");
|
||||
setModo("ver");
|
||||
|
||||
Swal.fire({
|
||||
title: "Programa creado correctamente",
|
||||
icon: "success",
|
||||
});
|
||||
} catch (error: any) {
|
||||
Swal.fire({
|
||||
title: "Error al insertar",
|
||||
text: error.response?.data?.message || error.message,
|
||||
icon: "error",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleGuardar = async () => {
|
||||
if (!programaSeleccionado) return;
|
||||
try {
|
||||
|
||||
await fetch(`${envConfig.apiUrl}/programa/${programaSeleccionado}`, {
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
programa: nombrePrograma,
|
||||
}),
|
||||
});
|
||||
await axios.patch(
|
||||
`${envConfig.apiUrl}/programa/${programaSeleccionado}`,
|
||||
{
|
||||
programa: nombrePrograma,
|
||||
},
|
||||
{ headers },
|
||||
);
|
||||
|
||||
const res = await fetch(`${envConfig.apiUrl}/programa/`);
|
||||
const data = await res.json();
|
||||
setProgramas(data);
|
||||
await cargarProgramas();
|
||||
setModo("ver");
|
||||
|
||||
setModo("ver");
|
||||
Swal.fire({
|
||||
title: "Programa actualizado correctamente",
|
||||
icon: "success",
|
||||
});
|
||||
} catch (error: any) {
|
||||
Swal.fire({
|
||||
title: "Error al actualizar",
|
||||
text: error.response?.data?.message || error.message,
|
||||
icon: "error",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleNuevo = () => setModo("nuevo");
|
||||
|
||||
const handleCancelar = () => setModo("ver");
|
||||
|
||||
const handleEditar = () => {
|
||||
const programa = programas.find(
|
||||
(p) => p.id_programa === Number(programaSeleccionado),
|
||||
(p) => p.id_programa === Number(programaSeleccionado)
|
||||
);
|
||||
|
||||
if (programa) {
|
||||
@@ -79,13 +110,39 @@ export default function Page() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelete = async () => {
|
||||
if (!programaSeleccionado) return;
|
||||
|
||||
try {
|
||||
await axios.delete(
|
||||
`${envConfig.apiUrl}/programa/${programaSeleccionado}`,
|
||||
{ headers },
|
||||
);
|
||||
|
||||
await cargarProgramas();
|
||||
setProgramaSeleccionado("");
|
||||
|
||||
Swal.fire({
|
||||
title: "Programa eliminado exitosamente",
|
||||
icon: "success",
|
||||
});
|
||||
} catch (error: any) {
|
||||
Swal.fire({
|
||||
title: "Error al eliminar",
|
||||
text: error.response?.data?.message || error.message,
|
||||
icon: "error",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="containerSection">
|
||||
{}
|
||||
{modo === "ver" && (
|
||||
<section className="containersection">
|
||||
<h3 className="title">PROGRAMAS</h3>
|
||||
<label className="label">Selecciona el programa que quieres editar</label>
|
||||
<label className="label">
|
||||
Selecciona el programa que quieres editar
|
||||
</label>
|
||||
|
||||
<select
|
||||
value={programaSeleccionado}
|
||||
@@ -106,7 +163,8 @@ export default function Page() {
|
||||
</button>
|
||||
|
||||
<button
|
||||
className={`button buttonSearch ${styleprograms.button}`}
|
||||
className="button buttonCharge"
|
||||
style={{ margin: "5px" }}
|
||||
onClick={handleNuevo}
|
||||
>
|
||||
Nuevo
|
||||
@@ -115,11 +173,9 @@ export default function Page() {
|
||||
</section>
|
||||
)}
|
||||
|
||||
{}
|
||||
{modo === "editar" && (
|
||||
<section className="containersection">
|
||||
<h2 className="title">Editar Programa</h2>
|
||||
<label className="label"> {programaSeleccionado}</label>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
@@ -129,11 +185,9 @@ export default function Page() {
|
||||
/>
|
||||
|
||||
<div className="margin">
|
||||
<button className="button buttonSearch" onClick={handleGuardar}>
|
||||
Guardar
|
||||
</button>
|
||||
|
||||
|
||||
<button className="button buttonSearch" onClick={handleGuardar}>
|
||||
Guardar
|
||||
</button>
|
||||
|
||||
<button
|
||||
className={`button buttonCancel ${styleprograms.button}`}
|
||||
@@ -141,29 +195,32 @@ export default function Page() {
|
||||
>
|
||||
Cancelar
|
||||
</button>
|
||||
|
||||
<button
|
||||
className={`button buttonCancel ${styleprograms.button}`}
|
||||
onClick={handleDelete}
|
||||
>
|
||||
Eliminar
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{}
|
||||
{modo === "nuevo" && (
|
||||
<section className="containersection">
|
||||
<h2 className="title">Nuevo Programa</h2>
|
||||
|
||||
<label className="label">Programa</label>
|
||||
<input
|
||||
type="text"
|
||||
value={nombrePrograma}
|
||||
onChange={(e) => setNombrePrograma(e.target.value)}
|
||||
placeholder="Coloca el programa"
|
||||
/>
|
||||
|
||||
type="text"
|
||||
value={nombrePrograma}
|
||||
onChange={(e) => setNombrePrograma(e.target.value)}
|
||||
placeholder="Coloca el programa"
|
||||
/>
|
||||
|
||||
<div className="margin">
|
||||
<button className="button buttonSearch" onClick={handleInsertar}>
|
||||
Insertar
|
||||
</button>
|
||||
|
||||
Insertar
|
||||
</button>
|
||||
|
||||
<button
|
||||
className={`button buttonCancel ${styleprograms.button}`}
|
||||
@@ -177,3 +234,4 @@ export default function Page() {
|
||||
</section>
|
||||
);
|
||||
}
|
||||
//IO
|
||||
@@ -6,8 +6,4 @@
|
||||
}
|
||||
.margin {
|
||||
margin: 10px 10px;
|
||||
}
|
||||
.button {
|
||||
margin-left: 20px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
import SearchUser from "@/app/Components/Global/SearchUser/searchUser";
|
||||
import ShowError from "@/app/Components/Global/ShowError";
|
||||
import QuitarSancion from "@/app/Components/QuitarSancion/QuitarSancion";
|
||||
import { GetSancionByStudent } from "@/app/lib/getStudent copy";
|
||||
import { GetSancionByStudent } from "@/app/lib/getSancionByStudent";
|
||||
import { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "QuitarSancion",
|
||||
};
|
||||
|
||||
export default async function Page(props: {
|
||||
searchParams?: Promise<{
|
||||
|
||||
@@ -5,7 +5,6 @@ import Toggle from "@/app/Components/Global/Toggle/Toggle";
|
||||
import SearchDateBetween from "@/app/Components/SearchDateBetween/SearchDateBetween";
|
||||
import PorServicios from "@/app/Components/Reportes/porServicio";
|
||||
import PorRecibos from "@/app/Components/Reportes/porRecibo";
|
||||
import DownloadReporteXLSX from "@/app/Components/Dowload/Reporte";
|
||||
|
||||
export default function ReportesClient({
|
||||
defaultKey,
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import { Metadata } from 'next';
|
||||
import ReportesClient from './ReportesClient';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Reportes",
|
||||
};
|
||||
|
||||
export default async function Page(props: {
|
||||
searchParams?: Promise<{
|
||||
key: string;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { ReactNode } from "react";
|
||||
import Logout from "../Components/auth/Logout/Logout";
|
||||
import BackgroundRotator from "../Components/layout/BackgroundRotator/BackgroundRotator";
|
||||
|
||||
export default async function PrivateLayout({
|
||||
children,
|
||||
}: {
|
||||
@@ -9,7 +11,7 @@ export default async function PrivateLayout({
|
||||
<div className="mainContainer">
|
||||
<div className="container">
|
||||
<Logout />
|
||||
<div className="img"></div>
|
||||
<BackgroundRotator/>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
"use client";
|
||||
import { useEffect, useState } from "react";
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
|
||||
import axios from "axios";
|
||||
import Swal from "sweetalert2";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
import "@/app/globals.css";
|
||||
import axios from "axios";
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
import toast from "react-hot-toast";
|
||||
|
||||
export default function Areas() {
|
||||
const [areas, setAreas] = useState([]);
|
||||
@@ -14,9 +16,15 @@ export default function Areas() {
|
||||
"Mantenimiento",
|
||||
);
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
axios
|
||||
.get(`${envConfig.apiUrl}/area-ubicacion`)
|
||||
.get(`${envConfig.apiUrl}/area-ubicacion`,
|
||||
{ headers }
|
||||
)
|
||||
.then((data) => {
|
||||
setAreas(data.data);
|
||||
})
|
||||
@@ -29,12 +37,22 @@ export default function Areas() {
|
||||
e.preventDefault();
|
||||
|
||||
if (!selectedArea) {
|
||||
toast.error("Selecciona un área antes de actualizar");
|
||||
|
||||
Swal.fire({
|
||||
title: "Selecciona un área antes de actualizar!",
|
||||
icon: "error",
|
||||
draggable: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!modo) {
|
||||
toast.error("Selecciona un modo");
|
||||
|
||||
Swal.fire({
|
||||
title: "Selecciona un modo!",
|
||||
icon: "error",
|
||||
draggable: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -44,13 +62,23 @@ export default function Areas() {
|
||||
{
|
||||
id_area_ubicacion: Number(selectedArea),
|
||||
activo: modo === "Activo",
|
||||
}
|
||||
}, { headers }
|
||||
);
|
||||
|
||||
toast.success("Equipos actualizados correctamente");
|
||||
|
||||
Swal.fire({
|
||||
title: "Equipos actualizados correctamente!",
|
||||
icon: "success",
|
||||
draggable: true,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
toast.error("Error al actualizar los equipos");
|
||||
|
||||
Swal.fire({
|
||||
title: "Error al actualizar los equipos!",
|
||||
icon: "error",
|
||||
draggable: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -111,4 +139,3 @@ export default function Areas() {
|
||||
</form>
|
||||
);
|
||||
}
|
||||
//IO
|
||||
@@ -2,18 +2,33 @@
|
||||
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
import { useEffect, useState } from "react";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
function Equipos() {
|
||||
export default function Equipos() {
|
||||
const [cuenta, setCuenta] = useState("");
|
||||
const [equipoId, setEquipoId] = useState("");
|
||||
const [equipos, setEquipos] = useState<any[]>([]);
|
||||
const [mensaje, setMensaje] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
fetch(`${envConfig.apiUrl}/equipo`)
|
||||
.then((res) => res.json())
|
||||
.then((data) => setEquipos(data))
|
||||
.catch(() => setMensaje("Error al cargar equipos"));
|
||||
const fetchEquipos = async () => {
|
||||
try {
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
const response = await axios.get(`${envConfig.apiUrl}/equipo`,
|
||||
{ headers },
|
||||
);
|
||||
setEquipos(response.data);
|
||||
} catch (error: any) {
|
||||
setMensaje(
|
||||
error.response?.data?.message || "Error al cargar equipos"
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
fetchEquipos();
|
||||
}, []);
|
||||
|
||||
const handleBuscar = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
@@ -63,5 +78,4 @@ function Equipos() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Equipos;
|
||||
//IO
|
||||
@@ -3,7 +3,7 @@ import { useState } from "react";
|
||||
|
||||
import "@/app/globals.css"
|
||||
|
||||
function Mesas() {
|
||||
export default function Mesas() {
|
||||
const [mesa, setMesa] = useState(""); // Mesa seleccionada
|
||||
const [mantenimiento, setMantenimiento] = useState(false); // Checkbox Mantenimiento
|
||||
const [mensaje, setMensaje] = useState(""); // Mensaje dinámico
|
||||
@@ -18,11 +18,6 @@ function Mesas() {
|
||||
|
||||
const estado = mantenimiento ? "en mantenimiento" : "disponible";
|
||||
setMensaje(`Mesa ${mesa} confirmada como ${estado}`);
|
||||
|
||||
console.log({
|
||||
mesa,
|
||||
mantenimiento,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -60,5 +55,4 @@ function Mesas() {
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
export default Mesas;
|
||||
//IO
|
||||
@@ -1,8 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import axios from "axios";
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
import axios from "axios";
|
||||
import Swal from "sweetalert2";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
interface Mesa {
|
||||
id_mesa: number;
|
||||
@@ -13,13 +15,16 @@ export default function MesasDisponibles() {
|
||||
const [mesas, setMesas] = useState<Mesa[]>();
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
useEffect(() => {
|
||||
obtenerMesas();
|
||||
}, []);
|
||||
|
||||
const obtenerMesas = async () => {
|
||||
try {
|
||||
const response = await axios.get(`${envConfig.apiUrl}/mesa`);
|
||||
const response = await axios.get(`${envConfig.apiUrl}/mesa`,{ headers });
|
||||
setMesas(response.data);
|
||||
} catch (error) {
|
||||
console.error("Error al obtener mesas:", error);
|
||||
@@ -30,9 +35,12 @@ export default function MesasDisponibles() {
|
||||
|
||||
const toggleEquipo = async (id_mesa: number) => {
|
||||
try {
|
||||
await fetch(`${envConfig.apiUrl}/mesa/${id_mesa}/activo`, {
|
||||
method: "PATCH",
|
||||
});
|
||||
|
||||
await axios.patch(
|
||||
`${envConfig.apiUrl}/mesa/${id_mesa}/activo`,
|
||||
{},
|
||||
{ headers },
|
||||
);
|
||||
|
||||
setMesas((prev) =>
|
||||
prev
|
||||
@@ -42,12 +50,16 @@ export default function MesasDisponibles() {
|
||||
...e,
|
||||
activo: e.activo === 1 ? 0 : 1,
|
||||
}
|
||||
: e,
|
||||
: e
|
||||
)
|
||||
: prev,
|
||||
: prev
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Error al cambiar estado del equipo", error);
|
||||
} catch (error: any) {
|
||||
Swal.fire({
|
||||
title: "Error al cambiar estado",
|
||||
text: error.response?.data?.message || error.message,
|
||||
icon: "error",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import Swal from "sweetalert2";
|
||||
|
||||
|
||||
function AlertSwet(){
|
||||
|
||||
Swal.fire("SweetAlert2 is working!");
|
||||
}
|
||||
|
||||
export default AlertSwet
|
||||
@@ -3,8 +3,8 @@ import { useEffect, useState } from "react";
|
||||
import apiClient from "@/app/lib/apiClient";
|
||||
|
||||
import "./registerAlta.css";
|
||||
import toast from "react-hot-toast";
|
||||
import { useRouter } from "next/navigation";
|
||||
import Swal from "sweetalert2";
|
||||
|
||||
type Carrera = {
|
||||
id_carrera: number;
|
||||
@@ -72,10 +72,22 @@ export default function RegisterAlta(props: urlProp) {
|
||||
await apiClient.post("/student", payload);
|
||||
|
||||
setSaved(true);
|
||||
toast.success("Alumno registrado correctamente");
|
||||
|
||||
Swal.fire({
|
||||
title: "Alumno registrado correctamente!",
|
||||
icon: "success",
|
||||
draggable: true,
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error al guardar alumno:", error);
|
||||
toast.error("Error al guardar alumno");
|
||||
|
||||
Swal.fire({
|
||||
title: "Error al guardar alumno:!",
|
||||
icon: "error",
|
||||
draggable: true,
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -2,10 +2,13 @@
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
import toast from "react-hot-toast";
|
||||
import { getEquipoByCount } from "../lib/getEquipoByCount";
|
||||
import { getMesaByCount } from "../lib/getMesaByCount";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
import Swal from "sweetalert2";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
type Props = {
|
||||
inscripcion: any[];
|
||||
@@ -19,6 +22,9 @@ export default function AsignacionMesas({ idCuenta, inscripcion }: Props) {
|
||||
const [mesaSeleccionada, setMesaSeleccionada] = useState<any>(null);
|
||||
const [tiempo, setTiempo] = useState<number>(15);
|
||||
const [bitacora, setBitacora] = useState<[] | null>([]);
|
||||
const [error, setError] = useState<string>();
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const fetchByCuenta = async (idCuenta: number) => {
|
||||
const [result, resultMesa] = await Promise.all([
|
||||
@@ -30,28 +36,35 @@ export default function AsignacionMesas({ idCuenta, inscripcion }: Props) {
|
||||
setBitacora(null);
|
||||
} else {
|
||||
setBitacora([]);
|
||||
if (!result?.error) toast.error("Ya cuentas con un equipo asignado");
|
||||
if (!resultMesa?.error) toast.error("Ya cuentas con una mesa asignada");
|
||||
|
||||
if (!result?.error) {
|
||||
setError("Equipo")
|
||||
}
|
||||
|
||||
if (!resultMesa?.error) {
|
||||
setError("Mesa")
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!idCuenta) return;
|
||||
const Cuenta = idCuenta;
|
||||
if (isNaN(Cuenta)) return;
|
||||
|
||||
fetchByCuenta(Cuenta);
|
||||
if (!idCuenta || isNaN(idCuenta)) return;
|
||||
fetchByCuenta(idCuenta);
|
||||
}, [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) {
|
||||
toast.error("El alumno no asistió a todas las pláticas");
|
||||
Swal.fire({
|
||||
title: "El alumno no asistió a todas las pláticas!",
|
||||
icon: "error",
|
||||
});
|
||||
|
||||
setPuedeContinuar(false);
|
||||
return;
|
||||
}
|
||||
@@ -64,19 +77,23 @@ export default function AsignacionMesas({ idCuenta, inscripcion }: Props) {
|
||||
|
||||
const fetchMesas = async () => {
|
||||
try {
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
setLoadingMesas(true);
|
||||
const res = await fetch(`${envConfig.apiUrl}/mesa/activo`, {
|
||||
cache: "no-store",
|
||||
|
||||
const response = await axios.get(
|
||||
`${envConfig.apiUrl}/mesa/activo`,
|
||||
{ headers },
|
||||
);
|
||||
|
||||
setMesas(response.data);
|
||||
} catch (error: any) {
|
||||
Swal.fire({
|
||||
title: "Error al cargar mesas disponibles!",
|
||||
text: error.response?.data?.message || error.message,
|
||||
icon: "error",
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error("No se pudieron cargar las mesas");
|
||||
}
|
||||
|
||||
const data = await res.json();
|
||||
setMesas(data);
|
||||
} catch (error) {
|
||||
toast.error("Error al cargar mesas disponibles");
|
||||
} finally {
|
||||
setLoadingMesas(false);
|
||||
}
|
||||
@@ -88,48 +105,60 @@ export default function AsignacionMesas({ idCuenta, inscripcion }: Props) {
|
||||
const submit = async (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (!mesaSeleccionada) {
|
||||
toast.error("Selecciona un mesa");
|
||||
if (!mesaSeleccionada || Number(mesaSeleccionada) === 0) {
|
||||
Swal.fire({
|
||||
title: "Seleccione una mesa!",
|
||||
icon: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
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");
|
||||
}
|
||||
await axios.post(
|
||||
`${envConfig.apiUrl}/bitacora-mesa`,
|
||||
body,
|
||||
{ headers },
|
||||
);
|
||||
|
||||
setBitacora([]);
|
||||
toast.success("Mesa asignada correctamente");
|
||||
router.refresh();
|
||||
setError("Mesa")
|
||||
Swal.fire({
|
||||
title: "Mesa asignada correctamente!",
|
||||
icon: "success",
|
||||
draggable: true
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
toast.error("No se pudo asignar la mesa");
|
||||
} catch (error: any) {
|
||||
Swal.fire({
|
||||
title: "No se pudo asignar la mesa!",
|
||||
text: error.response?.data?.message || error.message,
|
||||
icon: "error",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (!puedeContinuar) return null;
|
||||
|
||||
if (bitacora) {
|
||||
return <></>;
|
||||
return error === "Mesa" ? (
|
||||
<p style={{ margin: "1rem", color: "red" }}>
|
||||
Ya cuentas con una mesa asignada
|
||||
</p>
|
||||
) : error === "Equipo" ? (
|
||||
<p style={{ margin: "1rem", color: "red" }}>
|
||||
Ya cuentas con un equipo asignado
|
||||
</p>
|
||||
) : null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="containerForm">
|
||||
<label style={{ marginTop: "1rem" }}>Seleccionar tiempo</label>
|
||||
@@ -142,6 +171,8 @@ export default function AsignacionMesas({ idCuenta, inscripcion }: Props) {
|
||||
<option value={30}>30 minutos</option>
|
||||
<option value={40}>40 minutos</option>
|
||||
<option value={60}>60 minutos</option>
|
||||
<option value={90}>90 minutos</option>
|
||||
<option value={120}>120 minutos</option>
|
||||
</select>
|
||||
|
||||
<label style={{ marginTop: "1rem" }}>Seleccione una mesa</label>
|
||||
@@ -158,6 +189,7 @@ export default function AsignacionMesas({ idCuenta, inscripcion }: Props) {
|
||||
)}
|
||||
|
||||
<option value={0}>Selecciona una mesa</option>
|
||||
|
||||
{!loadingMesas &&
|
||||
mesas.map((mesa) => (
|
||||
<option key={mesa.id_mesa} value={mesa.id_mesa}>
|
||||
@@ -173,7 +205,6 @@ export default function AsignacionMesas({ idCuenta, inscripcion }: Props) {
|
||||
>
|
||||
Asignar Mesa
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
import { Alumno, AlumnoSancion, Sancion } from "@/app/types/sanction";
|
||||
import { GetSancionByStudent } from "@/app/lib/getSancionByStudent";
|
||||
import TableSanction from "./TableSanction";
|
||||
import axios from "axios";
|
||||
import Swal from "sweetalert2";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
if (!envConfig.apiUrl) {
|
||||
console.error("API URL is not defined in envConfig");
|
||||
}
|
||||
|
||||
export default function ApplySanction({ idCuenta }: { idCuenta: number }) {
|
||||
const [sanciones, setSanciones] = useState<Sancion[]>([]);
|
||||
const [alumno, setAlumno] = useState<Alumno>();
|
||||
const [alumnoSanciones, setAlumnoSanciones] = useState<AlumnoSancion[]>([]);
|
||||
const [selectedSancion, setSelectedSancion] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [loadingTable, setLoadingTable] = useState(false);
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
const fetchAlumnoSanciones = async () => {
|
||||
|
||||
const res = await GetSancionByStudent(idCuenta);
|
||||
|
||||
setAlumno(res.student ?? null);
|
||||
setAlumnoSanciones(res.alusancion ?? []);
|
||||
setLoadingTable(true)
|
||||
|
||||
if (res.error) {
|
||||
setLoadingTable(false)
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!idCuenta) return;
|
||||
|
||||
fetchAlumnoSanciones();
|
||||
|
||||
axios
|
||||
.get(`${envConfig.apiUrl}/sancion`, { headers })
|
||||
.then((res) => setSanciones(res.data))
|
||||
.catch(() =>
|
||||
|
||||
Swal.fire({
|
||||
title: "Error al obtener el catálogo de sanciones!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
})
|
||||
);
|
||||
|
||||
}, [idCuenta]);
|
||||
|
||||
const handleButton = async (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (!selectedSancion) {
|
||||
|
||||
Swal.fire({
|
||||
title: "Selecciona una sanción!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
await axios.post(`${envConfig.apiUrl}/alumno-sancion/`, {
|
||||
id_sancion: Number(selectedSancion),
|
||||
id_cuenta: idCuenta,
|
||||
}, { headers });
|
||||
|
||||
await fetchAlumnoSanciones();
|
||||
setSelectedSancion("");
|
||||
|
||||
Swal.fire({
|
||||
title: "Sanción aplicada correctamente!",
|
||||
icon: "success",
|
||||
draggable: true
|
||||
});
|
||||
} catch {
|
||||
|
||||
Swal.fire({
|
||||
title: "Error al aplicar la sanción!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableSanction alumnoSanciones={alumnoSanciones} alumno={alumno} />
|
||||
|
||||
{loadingTable && alumnoSanciones.length === 0 && (
|
||||
<>
|
||||
<form className="containerForm">
|
||||
<div className="groupInput">
|
||||
<select
|
||||
value={selectedSancion}
|
||||
onChange={(e) => setSelectedSancion(e.target.value)}
|
||||
>
|
||||
<option value="">-- Selecciona una sanción --</option>
|
||||
{sanciones.map((sancion) => (
|
||||
<option key={sancion.id_sancion} value={sancion.id_sancion}>
|
||||
{sancion.sancion} ({sancion.duracion} semana/s)
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<button
|
||||
className="button buttonSearch"
|
||||
style={{ margin: "1rem 0" }}
|
||||
onClick={handleButton}
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? "Aplicando..." : "Aplicar sanción"}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,36 +1,73 @@
|
||||
"use client";
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import axios from "axios";
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
interface alumnos {
|
||||
interface AlumnoBitacora {
|
||||
tiempo_entrada: string;
|
||||
tiempo_asignado: string;
|
||||
Ubicacion_equipo: number;
|
||||
tiempo_asignado: number;
|
||||
equipo: {
|
||||
ubicacion: string;
|
||||
nombre_equipo: string;
|
||||
};
|
||||
}
|
||||
|
||||
function BitacoraAlumno() {
|
||||
const [alumnos, setAlumnos] = useState<alumnos[]>([]);
|
||||
interface BitacoraAlumnoProps {
|
||||
numAcount: string | null;
|
||||
date: string | null;
|
||||
}
|
||||
|
||||
export default function BitacoraAlumno({ numAcount, date }: BitacoraAlumnoProps) {
|
||||
const [alumnos, setAlumnos] = useState<AlumnoBitacora[]>([]);
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
useEffect(() => {
|
||||
if (!numAcount) return;
|
||||
if (!date) return;
|
||||
|
||||
axios.post(`${envConfig.apiUrl}/bitacora/equipos-por-dia`, {
|
||||
numero_cuenta: numAcount,
|
||||
fecha: date,
|
||||
}, { headers })
|
||||
.then(res => {
|
||||
setAlumnos(res.data);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
}, [numAcount, date]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Tiempo Entrada</th>
|
||||
<th>Tiempo Asignado</th>
|
||||
<th>Ubicacion del equipo</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{alumnos.map((alumno, index) => (
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Tiempo Entrada</th>
|
||||
<th>Tiempo Asignado</th>
|
||||
<th>Ubicación del equipo</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{alumnos.length > 0 ? (
|
||||
alumnos.map((alumno, index) => (
|
||||
<tr key={index}>
|
||||
<td>{alumno.tiempo_entrada}</td>
|
||||
<td>{new Date(alumno.tiempo_entrada).toLocaleString()}</td>
|
||||
<td>{alumno.tiempo_asignado}</td>
|
||||
<td>{alumno.Ubicacion_equipo}</td>
|
||||
<td>{alumno.equipo.ubicacion}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
))
|
||||
) : (
|
||||
<tr>
|
||||
<td colSpan={3} style={{ textAlign: "center" }}>
|
||||
No tuvo equipos asignados
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
);
|
||||
}
|
||||
|
||||
export default BitacoraAlumno;
|
||||
//IO
|
||||
@@ -1,7 +1,12 @@
|
||||
"use client";
|
||||
import SearchDate from "../SearchDate/SearchDate";
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
|
||||
import SearchDate from "../SearchDate/SearchDate";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
import "../../(private)/AsignacionEquipo/asignacion.css"
|
||||
interface equipos {
|
||||
hora_entrada: string;
|
||||
min_utilizados: number;
|
||||
@@ -9,25 +14,101 @@ interface equipos {
|
||||
cuenta_asociada: number;
|
||||
}
|
||||
|
||||
function BitacoraEquipo() {
|
||||
export default function BitacoraEquipo({ date }: { date: string | null }) {
|
||||
const [equipo, setEquipo] = useState<equipos[]>([]);
|
||||
const [ubicacion_equipo, setUbicacionEquipo] = useState("");
|
||||
const [open, setOpen] = useState(false);
|
||||
const [loadingEquipos, setLoadingEquipos] = useState(false);
|
||||
const [equipoSeleccionado, setEquipoSeleccionado] = useState<any>(null);
|
||||
const [equipos, setEquipos] = useState<any[]>([]);
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
setLoadingEquipos(true);
|
||||
const response = await axios.get(`${envConfig.apiUrl}/equipo`, { headers },
|
||||
);
|
||||
setEquipos(response.data);
|
||||
setLoadingEquipos(false);
|
||||
};
|
||||
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!equipoSeleccionado?.id_equipo) return;
|
||||
if (!date) return;
|
||||
|
||||
axios.post(`${envConfig.apiUrl}/bitacora/equipos-por-equipo`, {
|
||||
id_equipo: equipoSeleccionado.id_equipo,
|
||||
fecha: date,
|
||||
}, { headers })
|
||||
.then(res => {
|
||||
setEquipo(res.data);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
}, [equipoSeleccionado, date]);
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<form className="containerForm">
|
||||
<label className="label">Ubicacion de equipo</label>
|
||||
<label>Seleccione un equipo</label>
|
||||
<div className="containerForm">
|
||||
|
||||
<div className="groupInput">
|
||||
<select
|
||||
value={ubicacion_equipo}
|
||||
onChange={(e) => setUbicacionEquipo(e.target.value)}
|
||||
<div
|
||||
className={`customSelect ${open ? "open" : ""} ${loadingEquipos ? "disabled" : ""}`}
|
||||
>
|
||||
<option value="">-- Selecciona un equipo --</option>
|
||||
<option value="255">Equipo 255</option>
|
||||
</select>
|
||||
<div
|
||||
className={`selectHeader ${equipoSeleccionado && equipoSeleccionado.plataforma?.nombre?.toUpperCase()}`}
|
||||
onClick={() => !loadingEquipos && setOpen(!open)}
|
||||
>
|
||||
{equipoSeleccionado ? (
|
||||
<span
|
||||
>
|
||||
{equipoSeleccionado.ubicacion}{" "}
|
||||
{equipoSeleccionado.nombre_equipo}
|
||||
</span>
|
||||
) : (
|
||||
<span className="placeholder">
|
||||
{loadingEquipos
|
||||
? "Cargando equipos..."
|
||||
: "Seleccione un equipo"}
|
||||
</span>
|
||||
)}
|
||||
|
||||
<span className="arrow">{open ? "▲" : "▼"}</span>
|
||||
</div>
|
||||
|
||||
{open && (
|
||||
<div className="options" style={{ bottom: "auto" }}>
|
||||
{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>
|
||||
</div>
|
||||
</form>
|
||||
<SearchDate />
|
||||
<SearchDate />
|
||||
</div>
|
||||
<div>
|
||||
<table>
|
||||
<thead>
|
||||
@@ -39,19 +120,31 @@ function BitacoraEquipo() {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{equipo.map((equipo, index) => (
|
||||
<tr key={index}>
|
||||
<td>{equipo.hora_entrada}</td>
|
||||
<td>{equipo.min_utilizados}</td>
|
||||
<td>{equipo.hora_salida}</td>
|
||||
<td>{equipo.cuenta_asociada}</td>
|
||||
{equipo.length > 0 ? (
|
||||
equipo.map((registro, index) => (
|
||||
<tr key={index}>
|
||||
<td>{new Date(registro.hora_entrada).toLocaleString()}</td>
|
||||
<td>{registro.min_utilizados}</td>
|
||||
<td>
|
||||
{registro.hora_salida
|
||||
? new Date(registro.hora_salida).toLocaleString()
|
||||
: "—"}
|
||||
</td>
|
||||
<td>{registro.cuenta_asociada}</td>
|
||||
</tr>
|
||||
))
|
||||
) : (
|
||||
<tr>
|
||||
<td colSpan={4} style={{ textAlign: "center" }}>
|
||||
Este equipo no tuvo asignaciones en esa fecha
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
)}
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default BitacoraEquipo;
|
||||
//IO
|
||||
@@ -1,8 +1,13 @@
|
||||
"use client";
|
||||
import SearchDate from "../SearchDate/SearchDate";
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
|
||||
interface tables {
|
||||
import SearchDate from "../SearchDate/SearchDate";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
interface Tables {
|
||||
no_mesa: number;
|
||||
no_cuenta: number;
|
||||
hora_entrada: string;
|
||||
@@ -10,12 +15,33 @@ interface tables {
|
||||
hora_salida: string;
|
||||
}
|
||||
|
||||
function BitacoraMesas() {
|
||||
const [tables, setTables] = useState<tables[]>([]);
|
||||
export default function BitacoraMesas() {
|
||||
const [tables, setTables] = useState<Tables[]>([]);
|
||||
const searchParams = useSearchParams();
|
||||
const date = searchParams.get("date");
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
useEffect(() => {
|
||||
if (!date) return;
|
||||
|
||||
axios.post(`${envConfig.apiUrl}/bitacora-mesa/mesas-por-dia`, {
|
||||
fecha: date,
|
||||
}, { headers })
|
||||
.then(res => {
|
||||
setTables(res.data);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
}, [date]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchDate />
|
||||
|
||||
<div>
|
||||
<table>
|
||||
<thead>
|
||||
@@ -28,20 +54,27 @@ function BitacoraMesas() {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{tables.map((table, index) => (
|
||||
<tr key={index}>
|
||||
<td>{table.no_mesa}</td>
|
||||
<td>{table.no_cuenta}</td>
|
||||
<td>{table.hora_entrada}</td>
|
||||
<td>{table.tiempo_asignado}</td>
|
||||
<td>{table.hora_salida}</td>
|
||||
{tables.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan={5} style={{ textAlign: "center" }}>
|
||||
No hubo mesas utilizadas en esta fecha
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
) : (
|
||||
tables.map((table, index) => (
|
||||
<tr key={index}>
|
||||
<td>{table.no_mesa}</td>
|
||||
<td>{table.no_cuenta}</td>
|
||||
<td>{new Date(table.hora_entrada).toLocaleString()}</td>
|
||||
<td>{table.tiempo_asignado}</td>
|
||||
<td>{new Date(table.hora_salida).toLocaleString()}</td>
|
||||
</tr>
|
||||
))
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default BitacoraMesas;
|
||||
//IO
|
||||
@@ -1,6 +1,5 @@
|
||||
import Information from "../Global/Information/information";
|
||||
import SearchUser from "../Global/SearchUser/searchUser";
|
||||
import TableSancion from "./TableSancion";
|
||||
import ApplySanction from "./ApplySanction";
|
||||
|
||||
interface Student {
|
||||
id_cuenta: string;
|
||||
@@ -13,11 +12,10 @@ export default function Sanciones({ student }: { student?: Student }) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchUser value={idCuenta} />
|
||||
{student && (
|
||||
<>
|
||||
<Information NoCuenta={student.id_cuenta} Nombre={student.nombre} />
|
||||
<TableSancion idCuenta={parseInt(student.id_cuenta)} />
|
||||
<ApplySanction idCuenta={parseInt(student.id_cuenta)} />
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import axios from "axios";
|
||||
import toast from "react-hot-toast";
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
|
||||
interface Alumno {
|
||||
id_cuenta: number;
|
||||
nombre: string;
|
||||
credito: number;
|
||||
}
|
||||
|
||||
interface Sancion {
|
||||
id_sancion: number;
|
||||
sancion: string;
|
||||
duracion: number;
|
||||
}
|
||||
|
||||
interface AlumnoSancion {
|
||||
id_alumno_sancion: number;
|
||||
fecha_inicio: string;
|
||||
sancion: Sancion;
|
||||
}
|
||||
|
||||
if (!envConfig.apiUrl) {
|
||||
console.error("API URL is not defined in envConfig");
|
||||
}
|
||||
|
||||
export default function TableSancion({ idCuenta }: { idCuenta: number }) {
|
||||
const [sanciones, setSanciones] = useState<Sancion[]>([]);
|
||||
const [alumno, setAlumno] = useState<Alumno | null>(null);
|
||||
const [alumnoSanciones, setAlumnoSanciones] = useState<AlumnoSancion[]>([]);
|
||||
const [selectedSancion, setSelectedSancion] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
if (!idCuenta) return;
|
||||
|
||||
axios
|
||||
.get(`${envConfig.apiUrl}/alumno-sancion/${idCuenta}`)
|
||||
.then((res) => {
|
||||
setAlumno(res.data.student);
|
||||
setAlumnoSanciones(
|
||||
res.data.alusancion?.length ? res.data.alusancion : [],
|
||||
);
|
||||
})
|
||||
.catch((err) => {
|
||||
const mensaje =
|
||||
err.response?.data?.message ||
|
||||
"Error al obtener las sanciones del alumno";
|
||||
|
||||
toast.error(mensaje);
|
||||
});
|
||||
|
||||
// Obtener catálogo de sanciones
|
||||
axios
|
||||
.get(`${envConfig.apiUrl}/sancion`)
|
||||
.then((res) => setSanciones(res.data))
|
||||
.catch((err) =>
|
||||
toast.error("Error al obtener el catálogo de sanciones:", err),
|
||||
);
|
||||
}, [idCuenta]);
|
||||
|
||||
const calcularFechaFin = (fechaInicio: string, duracionSemanas: number) => {
|
||||
const fecha = new Date(fechaInicio);
|
||||
fecha.setDate(fecha.getDate() + duracionSemanas * 7);
|
||||
return fecha.toLocaleDateString();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ margin: "1rem 0" }}>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Cuenta</th>
|
||||
<th>Motivo de la sanción</th>
|
||||
<th>Duración (Semanas)</th>
|
||||
<th>Fecha Sanción</th>
|
||||
<th>Podrá utilizar el servicio hasta</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{alumnoSanciones.length > 0 ? (
|
||||
alumnoSanciones.map((item) => (
|
||||
<tr key={item.id_alumno_sancion}>
|
||||
<td>{alumno?.id_cuenta}</td>
|
||||
<td>{item.sancion.sancion}</td>
|
||||
<td>{item.sancion.duracion}</td>
|
||||
<td>{new Date(item.fecha_inicio).toLocaleDateString()}</td>
|
||||
<td>
|
||||
{calcularFechaFin(item.fecha_inicio, item.sancion.duracion)}
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
) : (
|
||||
<tr>
|
||||
<td colSpan={5}>No hay sanciones registradas</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<form className="containerForm">
|
||||
<div className="groupInput">
|
||||
<select
|
||||
value={selectedSancion}
|
||||
onChange={(e) => setSelectedSancion(e.target.value)}
|
||||
>
|
||||
<option value="">-- Selecciona una sanción --</option>
|
||||
{sanciones.map((sancion) => (
|
||||
<option key={sancion.id_sancion} value={sancion.id_sancion}>
|
||||
{sancion.sancion} ({sancion.duracion} semana/s)
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<button
|
||||
className="button buttonSearch"
|
||||
style={{ margin: "1rem 0" }}
|
||||
>
|
||||
Aplicar sanción
|
||||
</button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import { Alumno, AlumnoSancion } from "@/app/types/sanction";
|
||||
|
||||
interface Props {
|
||||
alumnoSanciones?: AlumnoSancion[] | null,
|
||||
alumno?: Alumno
|
||||
}
|
||||
|
||||
export default function TableSanction({ alumnoSanciones, alumno }: Props) {
|
||||
|
||||
const calcularFechaFin = (fechaInicio: string, duracionSemanas: number) => {
|
||||
const fecha = new Date(fechaInicio);
|
||||
fecha.setDate(fecha.getDate() + duracionSemanas * 7);
|
||||
return fecha.toLocaleDateString();
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ margin: "1rem 0", maxWidth:"730px"}}>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Cuenta</th>
|
||||
<th>Motivo de la sanción</th>
|
||||
<th>Duración (Semanas)</th>
|
||||
<th>Fecha Sanción</th>
|
||||
<th>Podrá utilizar el servicio hasta</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{!(alumnoSanciones?.length === 0) ? (
|
||||
alumnoSanciones?.map((item) => (
|
||||
<tr key={item.id_alumno_sancion}>
|
||||
<td>{alumno?.id_cuenta}</td>
|
||||
<td>{item.sancion.sancion}</td>
|
||||
<td>{item.sancion.duracion}</td>
|
||||
<td>{new Date(item.fecha_inicio).toLocaleDateString()}</td>
|
||||
<td>
|
||||
{calcularFechaFin(item.fecha_inicio, item.sancion.duracion)}
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
) : (
|
||||
<tr>
|
||||
<td colSpan={5}>No hay sanciones registradas</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,20 +1,25 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { envConfig } from "../lib/config";
|
||||
|
||||
import { getEquipoByCount } from "../lib/getEquipoByCount";
|
||||
import SearchUser from "./Global/SearchUser/searchUser";
|
||||
import SearchEquipo from "./SearchEquipo";
|
||||
import axios from "axios";
|
||||
import Information from "./Global/Information/information";
|
||||
import toast from "react-hot-toast";
|
||||
import Swal from "sweetalert2";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
async function getEquipoId(idEquipo: number) {
|
||||
try {
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
const res = await axios.get(
|
||||
`${envConfig.apiUrl}/bitacora/equipo/${idEquipo}`,
|
||||
{ headers }
|
||||
);
|
||||
|
||||
return res.data;
|
||||
} catch (error: any) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
@@ -22,7 +27,6 @@ async function getEquipoId(idEquipo: number) {
|
||||
error: error.response?.data?.message || "Error al consultar equipo",
|
||||
};
|
||||
}
|
||||
|
||||
return { error: "Error desconocido" };
|
||||
}
|
||||
}
|
||||
@@ -33,19 +37,31 @@ interface Props {
|
||||
}
|
||||
|
||||
export default function CheckBoxEquipo({ numAcount, machine }: Props) {
|
||||
const [modo, setModo] = useState<"Equipo" | "Cuenta" | null>("Cuenta");
|
||||
const [bitacora, setBitacora] = useState<any>(null);
|
||||
const [tiempoRestante, setTiempoRestante] = useState<string>("");
|
||||
const [minutos, setMinutos] = useState<number>();
|
||||
const [modo, setModo] = useState<"Equipo" | "Cuenta">("Equipo");
|
||||
|
||||
const [bitacoraCuenta, setBitacoraCuenta] = useState<any>(null);
|
||||
const [bitacoraEquipo, setBitacoraEquipo] = useState<any>(null);
|
||||
|
||||
const [tiempoRestante, setTiempoRestante] = useState("");
|
||||
const [minutos, setMinutos] = useState<number>(0);
|
||||
|
||||
const [errorCuenta, setErrorCuenta] = useState<string | null>(null);
|
||||
const [errorEquipo, setErrorEquipo] = useState<string | null>(null);
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const bitacora =
|
||||
modo === "Cuenta" ? bitacoraCuenta : bitacoraEquipo;
|
||||
|
||||
const fetchByCuenta = async (idCuenta: number) => {
|
||||
const result = await getEquipoByCount(idCuenta);
|
||||
|
||||
if (result?.error) {
|
||||
toast.error(result.error);
|
||||
setBitacora(null);
|
||||
setErrorCuenta(result.error);
|
||||
setBitacoraCuenta(null);
|
||||
} else {
|
||||
setBitacora(result);
|
||||
setErrorCuenta(null);
|
||||
setBitacoraCuenta(result);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -53,28 +69,27 @@ export default function CheckBoxEquipo({ numAcount, machine }: Props) {
|
||||
const result = await getEquipoId(idEquipo);
|
||||
|
||||
if (result?.error) {
|
||||
toast.error(result.error);
|
||||
setBitacora(null);
|
||||
setErrorEquipo(result.error);
|
||||
setBitacoraEquipo(null);
|
||||
} else {
|
||||
setBitacora(result);
|
||||
setErrorEquipo(null);
|
||||
setBitacoraEquipo(result);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!numAcount) return;
|
||||
const idCuenta = parseInt(numAcount);
|
||||
if (isNaN(idCuenta)) return;
|
||||
if (modo !== "Cuenta" || !numAcount) return;
|
||||
|
||||
fetchByCuenta(idCuenta);
|
||||
}, [numAcount]);
|
||||
const idCuenta = parseInt(numAcount);
|
||||
if (!isNaN(idCuenta)) fetchByCuenta(idCuenta);
|
||||
}, [numAcount, modo]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!machine) return;
|
||||
const idEquipo = parseInt(machine);
|
||||
if (isNaN(idEquipo)) return;
|
||||
if (modo !== "Equipo" || !machine) return;
|
||||
|
||||
fetchByEquipo(idEquipo);
|
||||
}, [machine]);
|
||||
const idEquipo = parseInt(machine);
|
||||
if (!isNaN(idEquipo)) fetchByEquipo(idEquipo);
|
||||
}, [machine, modo]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!bitacora) return;
|
||||
@@ -82,19 +97,32 @@ export default function CheckBoxEquipo({ numAcount, machine }: Props) {
|
||||
const entrada = new Date(bitacora.tiempo_entrada).getTime();
|
||||
const asignadoMs = bitacora.tiempo_asignado * 60 * 1000;
|
||||
|
||||
const interval = setInterval(() => {
|
||||
const updateTimer = () => {
|
||||
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`);
|
||||
setMinutos(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
const minutosRestantes = Math.floor(restante / 60000);
|
||||
const segundos = Math.floor((restante % 60000) / 1000);
|
||||
|
||||
setMinutos(minutosRestantes + 1);
|
||||
setTiempoRestante(
|
||||
`${minutosRestantes} minuto(s) con ${segundos} segundo(s)`
|
||||
);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
updateTimer();
|
||||
|
||||
const interval = setInterval(() => {
|
||||
const sigue = updateTimer();
|
||||
if (!sigue) clearInterval(interval);
|
||||
}, 1000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
@@ -102,25 +130,42 @@ export default function CheckBoxEquipo({ numAcount, machine }: Props) {
|
||||
|
||||
const handleButton = async (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.preventDefault();
|
||||
if (!bitacora) return;
|
||||
|
||||
await axios.patch(
|
||||
`${envConfig.apiUrl}/bitacora/cancelar/${bitacora.id_bitacora}`,
|
||||
{ tiempo_asignado: minutos },
|
||||
);
|
||||
|
||||
toast.success("Tiempo cancelado");
|
||||
Swal.fire({
|
||||
title: "Tiempo cancelado!",
|
||||
icon: "success",
|
||||
draggable: true,
|
||||
});
|
||||
setLoading(true);
|
||||
|
||||
if (modo === "Cuenta" && numAcount) {
|
||||
fetchByCuenta(parseInt(numAcount));
|
||||
}
|
||||
try {
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
if (modo === "Equipo" && machine) {
|
||||
fetchByEquipo(parseInt(machine));
|
||||
await axios.patch(
|
||||
`${envConfig.apiUrl}/bitacora/cancelar/${bitacora.id_bitacora}`,
|
||||
{ tiempo_asignado: minutos },
|
||||
{ headers }
|
||||
);
|
||||
|
||||
Swal.fire({
|
||||
title: "Tiempo cancelado correctamente!",
|
||||
icon: "success",
|
||||
});
|
||||
|
||||
if (modo === "Cuenta" && numAcount) {
|
||||
fetchByCuenta(parseInt(numAcount));
|
||||
setBitacoraEquipo(null);
|
||||
}
|
||||
|
||||
if (modo === "Equipo" && machine) {
|
||||
fetchByEquipo(parseInt(machine));
|
||||
setBitacoraCuenta(null);
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
Swal.fire({
|
||||
title: "Error al cancelar tiempo",
|
||||
icon: "error",
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -130,7 +175,6 @@ export default function CheckBoxEquipo({ numAcount, machine }: Props) {
|
||||
<label className="radio-card">
|
||||
<input
|
||||
type="radio"
|
||||
name="modo"
|
||||
checked={modo === "Equipo"}
|
||||
onChange={() => setModo("Equipo")}
|
||||
/>
|
||||
@@ -141,7 +185,6 @@ export default function CheckBoxEquipo({ numAcount, machine }: Props) {
|
||||
<label className="radio-card">
|
||||
<input
|
||||
type="radio"
|
||||
name="modo"
|
||||
checked={modo === "Cuenta"}
|
||||
onChange={() => setModo("Cuenta")}
|
||||
/>
|
||||
@@ -150,10 +193,21 @@ export default function CheckBoxEquipo({ numAcount, machine }: Props) {
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{modo === "Cuenta" && <SearchUser value={numAcount ?? null} />}
|
||||
{modo === "Equipo" && <SearchEquipo value={machine ?? null} />}
|
||||
{modo === "Cuenta" && (
|
||||
<>
|
||||
<SearchUser value={numAcount ?? null} />
|
||||
<h2>{errorCuenta}</h2>
|
||||
</>
|
||||
)}
|
||||
|
||||
{bitacora && (
|
||||
{modo === "Equipo" && (
|
||||
<>
|
||||
<SearchEquipo value={machine ?? null} />
|
||||
<h2>{errorEquipo}</h2>
|
||||
</>
|
||||
)}
|
||||
|
||||
{bitacora && tiempoRestante !== "agotado" && (
|
||||
<>
|
||||
<Information
|
||||
NoCuenta={bitacora.alumno_inscrito.alumno.id_cuenta}
|
||||
@@ -161,10 +215,12 @@ export default function CheckBoxEquipo({ numAcount, machine }: Props) {
|
||||
Tiempo={tiempoRestante}
|
||||
Equipo={bitacora.equipo.ubicacion}
|
||||
/>
|
||||
|
||||
<button
|
||||
className="button buttonSearch"
|
||||
style={{ marginTop: "1rem" }}
|
||||
onClick={handleButton}
|
||||
disabled={loading || minutos === 0}
|
||||
>
|
||||
Cancelar tiempo
|
||||
</button>
|
||||
@@ -172,5 +228,4 @@ export default function CheckBoxEquipo({ numAcount, machine }: Props) {
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
//IO
|
||||
}
|
||||
+148
-61
@@ -1,63 +1,80 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { getTableByCount } from "../lib/getTableByCount";
|
||||
import { envConfig } from "../lib/config";
|
||||
import { getMesaByCount } from "../lib/getMesaByCount";
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
|
||||
import SearchUser from "./Global/SearchUser/searchUser";
|
||||
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";
|
||||
import { getMesaByCount } from "../lib/getMesaByCount";
|
||||
import Swal from "sweetalert2";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
interface props {
|
||||
numAcount: string | null;
|
||||
table: number | null;
|
||||
table: string | null;
|
||||
}
|
||||
|
||||
export default function CheckBoxMesa({ numAcount, table }: props) {
|
||||
const [modo, setModo] = useState<"Mesa" | "Cuenta" | null>("Cuenta");
|
||||
const [bitacora, setBitacora] = useState<any>(null);
|
||||
const [modo, setModo] = useState<"Mesa" | "Cuenta" | null>("Mesa");
|
||||
const [bitacoraMesa, setBitacoraMesa] = useState<any>(null);
|
||||
const [bitacoraCuenta, setBitacoraCuenta] = useState<any>(null);
|
||||
const [tiempoRestante, setTiempoRestante] = useState<string>("");
|
||||
const [minutos, setMinutos] = useState<number>();
|
||||
const [errorMesa, setErrorMesa] = useState<string | null>()
|
||||
const [errorCount, setErrorCount] = useState<string | null>()
|
||||
const [loading, setLoading] = useState<boolean>(false)
|
||||
|
||||
const bitacora = modo === "Cuenta" ? bitacoraCuenta : bitacoraMesa;
|
||||
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
|
||||
const fetchByCuenta = async (idCuenta: number) => {
|
||||
const result = await getMesaByCount(idCuenta);
|
||||
|
||||
if (result?.error) {
|
||||
toast.error(result.error);
|
||||
setBitacora(null);
|
||||
setErrorCount(result.error);
|
||||
setBitacoraCuenta(null);
|
||||
} else {
|
||||
setBitacora(result);
|
||||
setBitacoraCuenta(result);
|
||||
setErrorCount(null)
|
||||
}
|
||||
};
|
||||
|
||||
const fetchByEquipo = async (idEquipo: number) => {
|
||||
const fetchByMesa = async (idEquipo: number) => {
|
||||
const result = await getTableByCount(idEquipo);
|
||||
|
||||
if (result?.error) {
|
||||
toast.error(result.error);
|
||||
setBitacora(null);
|
||||
setErrorMesa(result.error);
|
||||
setBitacoraMesa(null);
|
||||
} else {
|
||||
setBitacora(result);
|
||||
setBitacoraMesa(result);
|
||||
setErrorMesa(null)
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!numAcount) return;
|
||||
if (modo !== "Cuenta" || !numAcount) return;
|
||||
const idCuenta = parseInt(numAcount);
|
||||
if (isNaN(idCuenta)) return;
|
||||
|
||||
fetchByCuenta(idCuenta);
|
||||
}, [numAcount]);
|
||||
}, [numAcount, modo]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!table) return;
|
||||
const idEquipo = table;
|
||||
setBitacoraMesa(null);
|
||||
params.delete("numAcount");
|
||||
router.push(`${pathname}?${params.toString()}`);
|
||||
if (modo !== "Mesa" || !table) return;
|
||||
const idEquipo = parseInt(table);
|
||||
if (isNaN(idEquipo)) return;
|
||||
|
||||
fetchByEquipo(idEquipo);
|
||||
fetchByMesa(idEquipo);
|
||||
}, [table]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -66,19 +83,32 @@ export default function CheckBoxMesa({ numAcount, table }: props) {
|
||||
const entrada = new Date(bitacora.tiempo_entrada).getTime();
|
||||
const asignadoMs = bitacora.tiempo_asignado * 60 * 1000;
|
||||
|
||||
const interval = setInterval(() => {
|
||||
const updateTimer = () => {
|
||||
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`);
|
||||
setMinutos(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
const minutosRestantes = Math.floor(restante / 60000);
|
||||
const segundos = Math.floor((restante % 60000) / 1000);
|
||||
|
||||
setMinutos(minutosRestantes + 1);
|
||||
setTiempoRestante(
|
||||
`${minutosRestantes} minuto(s) con ${segundos} segundo(s)`
|
||||
);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
updateTimer();
|
||||
|
||||
const interval = setInterval(() => {
|
||||
const sigue = updateTimer();
|
||||
if (!sigue) clearInterval(interval);
|
||||
}, 1000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
@@ -86,28 +116,52 @@ export default function CheckBoxMesa({ numAcount, table }: props) {
|
||||
|
||||
const handleButton = async (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
|
||||
await axios.patch(
|
||||
`${envConfig.apiUrl}/bitacora-mesa/cancelar/${bitacora.id_bitacora_mesa}`,
|
||||
{ tiempo_asignado: minutos },
|
||||
);
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
toast.success("Tiempo cancelado");
|
||||
Swal.fire({
|
||||
title: "Tiempo cancelado!",
|
||||
icon: "success",
|
||||
draggable: true,
|
||||
});
|
||||
try {
|
||||
if (!bitacora) return;
|
||||
|
||||
if (modo === "Cuenta" && numAcount) {
|
||||
fetchByCuenta(parseInt(numAcount));
|
||||
}
|
||||
await axios.patch(
|
||||
`${envConfig.apiUrl}/bitacora-mesa/cancelar/${bitacora.id_bitacora_mesa}`,
|
||||
{ tiempo_asignado: minutos ?? 0 },
|
||||
{ headers }
|
||||
);
|
||||
|
||||
if (modo === "Mesa" && table) {
|
||||
fetchByEquipo(table);
|
||||
Swal.fire({
|
||||
title: "Tiempo cancelado correctamente!",
|
||||
icon: "success",
|
||||
});
|
||||
|
||||
if (modo === "Cuenta" && numAcount) {
|
||||
fetchByCuenta(parseInt(numAcount));
|
||||
params.delete("numAcount");
|
||||
router.push(`${pathname}?${params.toString()}`);
|
||||
}
|
||||
|
||||
if (modo === "Mesa" && table) {
|
||||
fetchByMesa(parseInt(table));
|
||||
params.delete("table");
|
||||
router.push(`${pathname}?${params.toString()}`);
|
||||
}
|
||||
|
||||
router.refresh();
|
||||
|
||||
setBitacoraMesa(null);
|
||||
setBitacoraCuenta(null);
|
||||
setErrorMesa('Alumno sin mesa');
|
||||
|
||||
} catch (error) {
|
||||
Swal.fire({
|
||||
title: "Error al cancelar tiempo",
|
||||
icon: "error",
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="radio-grid">
|
||||
@@ -134,26 +188,59 @@ export default function CheckBoxMesa({ numAcount, table }: props) {
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{modo === "Cuenta" && <SearchUser value={numAcount ?? null} />}
|
||||
{modo === "Mesa" && <SearchMesa />}
|
||||
|
||||
{bitacora && (
|
||||
{modo === "Cuenta" &&
|
||||
<>
|
||||
<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>
|
||||
<SearchUser value={numAcount ?? null} />
|
||||
<h2 style={{ marginTop: "10px" }}>{errorCount}</h2>
|
||||
|
||||
{bitacoraCuenta && tiempoRestante !== "agotado" && (
|
||||
<>
|
||||
<Information
|
||||
NoCuenta={bitacoraCuenta.alumno_inscrito.alumno.id_cuenta}
|
||||
Nombre={bitacoraCuenta.alumno_inscrito.alumno.nombre}
|
||||
Tiempo={tiempoRestante}
|
||||
Mesa={bitacoraCuenta.mesa.id_mesa}
|
||||
/>
|
||||
|
||||
<button
|
||||
className="button buttonSearch"
|
||||
style={{ marginTop: "1rem" }}
|
||||
onClick={handleButton}
|
||||
disabled={loading || !minutos}
|
||||
>
|
||||
Cancelar tiempo
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
}
|
||||
|
||||
{modo === "Mesa" &&
|
||||
<>
|
||||
<SearchMesa value={table ?? null} />
|
||||
<h2 style={{ marginTop: "10px" }}>{errorMesa}</h2>
|
||||
|
||||
{bitacoraMesa && tiempoRestante !== "agotado" && (
|
||||
<>
|
||||
<Information
|
||||
NoCuenta={bitacoraMesa.alumno_inscrito.alumno.id_cuenta}
|
||||
Nombre={bitacoraMesa.alumno_inscrito.alumno.nombre}
|
||||
Tiempo={tiempoRestante}
|
||||
Mesa={bitacoraMesa.mesa.id_mesa}
|
||||
/>
|
||||
|
||||
<button
|
||||
className="button buttonSearch"
|
||||
style={{ marginTop: "1rem" }}
|
||||
onClick={handleButton}
|
||||
disabled={loading || !minutos}
|
||||
>
|
||||
Cancelar tiempo
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,43 +1,74 @@
|
||||
"use client";
|
||||
|
||||
import styles from "./style.module.css";
|
||||
import Cookies from "js-cookie";
|
||||
import { useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { saveAs } from "file-saver";
|
||||
import ExcelJS from "exceljs";
|
||||
|
||||
export default function DownloadReporteXLSX() {
|
||||
import styles from "./style.module.css";
|
||||
|
||||
interface Recibo {
|
||||
id_recibo: number;
|
||||
folio_recibo: string;
|
||||
fecha_recibo: string;
|
||||
fecha_registro: string;
|
||||
monto: string;
|
||||
user: {
|
||||
usuario: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface Columns{
|
||||
header:string;
|
||||
key:string;
|
||||
width:number
|
||||
}
|
||||
|
||||
interface Props {
|
||||
data: Recibo[];
|
||||
columns:Columns[];
|
||||
}
|
||||
|
||||
export default function DownloadReporteXLSX({ data,columns }: Props) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const formatearFechaMX = (fechaISO: string) => {
|
||||
return new Date(fechaISO).toLocaleString("es-MX", {
|
||||
timeZone: "America/Mexico_City",
|
||||
});
|
||||
};
|
||||
|
||||
const handleDownload = async () => {
|
||||
if (!data || data.length === 0) return;
|
||||
|
||||
setLoading(true);
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${process.env.NEXT_PUBLIC_API_URL}/equipos/reporteXLSX`,//Modificar
|
||||
{ headers }
|
||||
);
|
||||
const workbook = new ExcelJS.Workbook();
|
||||
const worksheet = workbook.addWorksheet("Recibos");
|
||||
|
||||
if (!response.ok) {
|
||||
toast.error("Error al descargar el archivo");
|
||||
return;
|
||||
}
|
||||
worksheet.columns = columns;
|
||||
|
||||
const blob = await response.blob();
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
data.forEach((recibo) => {
|
||||
worksheet.addRow({
|
||||
folio: recibo.folio_recibo,
|
||||
monto: Number(recibo.monto),
|
||||
fechaRecibo: recibo.fecha_recibo,
|
||||
fechaRegistro: formatearFechaMX(recibo.fecha_registro),
|
||||
usuario: recibo.user.usuario,
|
||||
});
|
||||
});
|
||||
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = "Reporte Recibos.xlsx";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
worksheet.getColumn("monto").numFmt = '"$"#,##0.00';
|
||||
|
||||
window.URL.revokeObjectURL(url);
|
||||
const buffer = await workbook.xlsx.writeBuffer();
|
||||
const blob = new Blob([buffer], {
|
||||
type:
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
});
|
||||
|
||||
saveAs(blob, "Reporte_Recibos.xlsx");
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
toast.error("Hubo un problema al descargar el archivo.");
|
||||
console.error("Error generando Excel", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -52,7 +83,13 @@ export default function DownloadReporteXLSX() {
|
||||
{loading ? (
|
||||
<div className={styles.loader}></div>
|
||||
) : (
|
||||
<img src="/excel.svg" alt="Excel" className={styles.iconExcel} width={30} height={30}/>
|
||||
<img
|
||||
src="/excel.svg"
|
||||
alt="Excel"
|
||||
className={styles.iconExcel}
|
||||
width={30}
|
||||
height={30}
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
padding: 5px 5px;
|
||||
cursor: pointer;
|
||||
border-radius: 10px 10px 0 0;
|
||||
font-size: 14px;
|
||||
font-size: 1.4rem;
|
||||
font-weight: 600;
|
||||
transition: background 0.2s ease;
|
||||
min-width: 50px;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
"use client";
|
||||
import axios from "axios";
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
import { useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import Swal from "sweetalert2";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
interface Data {
|
||||
nombre_equipo: string;
|
||||
@@ -40,25 +41,43 @@ export default function Equipos() {
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const [isCreating, setIsCreating] = useState(false);
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
const [equipoRes, plataformaRes, areaRes] = await Promise.all([
|
||||
axios.get(`${envConfig.apiUrl}/equipo/${id}`),
|
||||
axios.get(`${envConfig.apiUrl}/alumno-inscrito/plataforma`),
|
||||
axios.get(`${envConfig.apiUrl}/area-ubicacion`),
|
||||
]);
|
||||
try {
|
||||
|
||||
const equipo = equipoRes.data as Data;
|
||||
const [equipoRes, plataformaRes, areaRes] = await Promise.all([
|
||||
axios.get(`${envConfig.apiUrl}/equipo/${id}`, { headers },
|
||||
),
|
||||
axios.get(`${envConfig.apiUrl}/alumno-inscrito/plataforma`, { headers },
|
||||
),
|
||||
axios.get(`${envConfig.apiUrl}/area-ubicacion`, { headers },
|
||||
),
|
||||
]);
|
||||
|
||||
const equipo = equipoRes.data as Data;
|
||||
|
||||
setData(equipo);
|
||||
setNombre(equipo.nombre_equipo);
|
||||
setUbicacion(equipo.ubicacion);
|
||||
setIdPlataforma(equipo.id_plataforma);
|
||||
setIdArea(equipo.id_area_ubicacion);
|
||||
|
||||
setPlataforma(plataformaRes.data);
|
||||
setArea(areaRes.data);
|
||||
|
||||
} catch (error) {
|
||||
Swal.fire({
|
||||
title: "Equipo no encontrado",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
}
|
||||
|
||||
setData(equipo);
|
||||
setNombre(equipo.nombre_equipo);
|
||||
setUbicacion(equipo.ubicacion);
|
||||
setIdPlataforma(equipo.id_plataforma);
|
||||
setIdArea(equipo.id_area_ubicacion);
|
||||
|
||||
setPlataforma(plataformaRes.data);
|
||||
setArea(areaRes.data);
|
||||
};
|
||||
|
||||
const handleSave = async () => {
|
||||
@@ -72,7 +91,9 @@ export default function Equipos() {
|
||||
id_plataforma: idPlataforma,
|
||||
id_area_ubicacion: idArea,
|
||||
ip: data.ip,
|
||||
});
|
||||
},
|
||||
{ headers }
|
||||
);
|
||||
|
||||
// Actualiza el estado local
|
||||
setData({
|
||||
@@ -84,18 +105,28 @@ export default function Equipos() {
|
||||
});
|
||||
|
||||
setIsEditing(false);
|
||||
toast.success("Equipo actualizado correctamente");
|
||||
|
||||
Swal.fire({
|
||||
title: "Equipo actualizado correctamente!",
|
||||
icon: "success",
|
||||
draggable: true
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
toast.error("Error al guardar el equipo");
|
||||
|
||||
Swal.fire({
|
||||
title: "Error al guardar el equipo!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleNuevo = async () => {
|
||||
try {
|
||||
const [plataformaRes, areaRes] = await Promise.all([
|
||||
axios.get(`${envConfig.apiUrl}/alumno-inscrito/plataforma`),
|
||||
axios.get(`${envConfig.apiUrl}/area-ubicacion`),
|
||||
axios.get(`${envConfig.apiUrl}/alumno-inscrito/plataforma`, { headers }),
|
||||
axios.get(`${envConfig.apiUrl}/area-ubicacion`, { headers }),
|
||||
]);
|
||||
|
||||
setPlataforma(plataformaRes.data);
|
||||
@@ -118,7 +149,11 @@ export default function Equipos() {
|
||||
setIsCreating(true);
|
||||
setIsEditing(true);
|
||||
} catch (error) {
|
||||
toast.error("Error al preparar formulario");
|
||||
Swal.fire({
|
||||
title: "Error al preparar formulario!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -130,9 +165,14 @@ export default function Equipos() {
|
||||
id_plataforma: idPlataforma,
|
||||
id_area_ubicacion: idArea,
|
||||
ip: "0.0.0.0",
|
||||
});
|
||||
}, { headers });
|
||||
|
||||
toast.success("Equipo creado correctamente");
|
||||
|
||||
Swal.fire({
|
||||
title: "Equipo creado correctamente!",
|
||||
icon: "success",
|
||||
draggable: true
|
||||
});
|
||||
|
||||
setIsCreating(false);
|
||||
setIsEditing(false);
|
||||
@@ -140,7 +180,11 @@ export default function Equipos() {
|
||||
} catch (error: any) {
|
||||
const message =
|
||||
error?.response?.data?.message || "Error al crear el equipo";
|
||||
toast.error(message);
|
||||
Swal.fire({
|
||||
title: message,
|
||||
icon: "error",
|
||||
draggable: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -230,13 +274,6 @@ export default function Equipos() {
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
className="button buttonCharge"
|
||||
onClick={handleNuevo}
|
||||
>
|
||||
Nuevo
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="button buttonSearch"
|
||||
@@ -249,6 +286,14 @@ export default function Equipos() {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
className="button buttonCharge"
|
||||
onClick={handleNuevo}
|
||||
>
|
||||
Nuevo
|
||||
</button>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
//IO
|
||||
@@ -3,44 +3,99 @@
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
import "./tableEquipos.css";
|
||||
|
||||
type AreaUbicacion = {
|
||||
id_area_ubicacion: number;
|
||||
area: string;
|
||||
};
|
||||
|
||||
type Equipo = {
|
||||
id_equipo: number;
|
||||
nombre_equipo: string;
|
||||
ubicacion: string;
|
||||
plataforma: {
|
||||
nombre: string
|
||||
};
|
||||
areaUbicacion: {area:string};
|
||||
ocupado: boolean;
|
||||
activo: {
|
||||
data: number[]
|
||||
}
|
||||
};
|
||||
|
||||
export default function TableEquipos() {
|
||||
const [equipos, setEquipos] = useState<any[]>([]);
|
||||
const [machines, setMachines] = useState<Equipo[]>([]);
|
||||
const [areas, setAreas] = useState<AreaUbicacion[]>([]);
|
||||
const [selectedArea, setSelectedArea] = useState("Todo");
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
useEffect(() => {
|
||||
fetch(`${envConfig.apiUrl}/equipo`)
|
||||
.then((res) => res.json())
|
||||
.then((data) => {
|
||||
setEquipos(data);
|
||||
|
||||
const fetchEquipos = async () => {
|
||||
try {
|
||||
const response = await axios.get(`${envConfig.apiUrl}/equipo`,
|
||||
{ headers },
|
||||
);
|
||||
setMachines(response.data);
|
||||
} catch (error: any) {
|
||||
console.error("ERROR API:", error.response?.data || error.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("ERROR API:", err);
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
fetchEquipos();
|
||||
fetchAreas();
|
||||
|
||||
}, []);
|
||||
|
||||
const fetchAreas = async () => {
|
||||
try {
|
||||
const res = await axios.get(
|
||||
`${process.env.NEXT_PUBLIC_API_URL}/area-ubicacion`,
|
||||
{ headers },
|
||||
|
||||
);
|
||||
|
||||
setAreas(res.data);
|
||||
} catch (error) {
|
||||
console.error("Error cargando áreas:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const toggleEquipo = async (id_equipo: number) => {
|
||||
try {
|
||||
await fetch(`${envConfig.apiUrl}/mesa/${id_equipo}/activo`, {
|
||||
method: "PATCH",
|
||||
});
|
||||
await axios.patch(
|
||||
`${envConfig.apiUrl}/equipo/${id_equipo}/activo`,
|
||||
{},
|
||||
{ headers },
|
||||
);
|
||||
|
||||
setEquipos((prev) =>
|
||||
setMachines((prev) =>
|
||||
prev.map((e) =>
|
||||
e.id_equipo === id_equipo
|
||||
? {
|
||||
...e,
|
||||
activo: {
|
||||
data: [e.activo?.data?.[0] === 1 ? 0 : 1],
|
||||
},
|
||||
}
|
||||
: e,
|
||||
),
|
||||
...e,
|
||||
activo: {
|
||||
data: [e.activo?.data?.[0] === 1 ? 0 : 1],
|
||||
},
|
||||
}
|
||||
: e
|
||||
)
|
||||
);
|
||||
} catch (error: any) {
|
||||
console.error(
|
||||
"Error al cambiar estado del equipo",
|
||||
error.response?.data || error.message
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Error al cambiar estado del equipo", error);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -48,6 +103,14 @@ export default function TableEquipos() {
|
||||
return <p>Cargando equipos...</p>;
|
||||
}
|
||||
|
||||
const filteredMachines =
|
||||
selectedArea === "Todo"
|
||||
? machines
|
||||
: machines.filter(
|
||||
(machine) => machine.areaUbicacion.area === selectedArea,
|
||||
);
|
||||
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
@@ -65,9 +128,29 @@ export default function TableEquipos() {
|
||||
<th>Área</th>
|
||||
<th>Activo</th>
|
||||
</tr>
|
||||
<tr style={{ position: "relative", zIndex: "0" }}>
|
||||
<th />
|
||||
<th />
|
||||
<th />
|
||||
<th>
|
||||
<select
|
||||
style={{ minWidth: "50px" }}
|
||||
value={selectedArea}
|
||||
onChange={(e) => setSelectedArea(e.target.value)}
|
||||
>
|
||||
<option value="Todo">Todo</option>
|
||||
{areas.map((area) => (
|
||||
<option key={area.id_area_ubicacion} value={area.area}>
|
||||
{area.area}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</th>
|
||||
<th />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{equipos.map((eq) => {
|
||||
{filteredMachines.map((eq) => {
|
||||
const isActivo = eq.activo?.data?.[0] === 1;
|
||||
|
||||
return (
|
||||
@@ -77,7 +160,7 @@ export default function TableEquipos() {
|
||||
<td className={eq.plataforma?.nombre}>
|
||||
{eq.plataforma?.nombre}
|
||||
</td>
|
||||
<td>{eq.areaUbicacion?.nombre || eq.id_area_ubicacion}</td>
|
||||
<td>{eq.areaUbicacion.area}</td>
|
||||
|
||||
<td
|
||||
style={{ display: "flex", alignItems: "center", gap: "5px" }}
|
||||
@@ -98,3 +181,4 @@ export default function TableEquipos() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
//IO
|
||||
@@ -1,8 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import axios from "axios";
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
import "../../(private)/AsignacionEquipo/asignacion.css";
|
||||
|
||||
@@ -39,14 +40,17 @@ const EnviarMensaje = ({ titulo }: EnviarMensajeProps) => {
|
||||
|
||||
const [customMsg, setCustomMsg] = useState("");
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
setLoadingMensajes(true);
|
||||
|
||||
const [equiposRes, mensajesRes] = await Promise.all([
|
||||
axios.get(`${envConfig.apiUrl}/equipo/busy`),
|
||||
axios.get(`${envConfig.apiUrl}/mensaje`)
|
||||
axios.get(`${envConfig.apiUrl}/equipo/busy`, { headers }),
|
||||
axios.get(`${envConfig.apiUrl}/mensaje`, { headers })
|
||||
]);
|
||||
|
||||
setEquipos(equiposRes.data);
|
||||
@@ -70,8 +74,6 @@ const EnviarMensaje = ({ titulo }: EnviarMensajeProps) => {
|
||||
mensaje: customMsg || mensaje,
|
||||
};
|
||||
|
||||
console.log(payload);
|
||||
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import axios from "axios";
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
interface Area {
|
||||
id_area_ubicacion: number;
|
||||
@@ -20,11 +21,13 @@ const EnviarMensajeSala = ({ titulo }: EnviarMensajeSalaProps) => {
|
||||
const [mensaje, setMensaje] = useState("");
|
||||
const [customMsg, setCustomMsg] = useState("");
|
||||
|
||||
// 🔹 Traer salas desde API
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
useEffect(() => {
|
||||
const fetchSalas = async () => {
|
||||
try {
|
||||
const response = await axios.get(`${envConfig.apiUrl}/area-ubicacion`);
|
||||
const response = await axios.get(`${envConfig.apiUrl}/area-ubicacion`, { headers });
|
||||
setSalas(response.data);
|
||||
} catch (error) {
|
||||
console.error("Error cargando salas:", error);
|
||||
@@ -42,14 +45,11 @@ const EnviarMensajeSala = ({ titulo }: EnviarMensajeSalaProps) => {
|
||||
mensaje: customMsg || mensaje,
|
||||
};
|
||||
|
||||
console.log(payload);
|
||||
|
||||
|
||||
};
|
||||
|
||||
return (
|
||||
<form className="containerForm" onSubmit={handleSubmit}>
|
||||
|
||||
|
||||
<label className="label">{titulo}</label>
|
||||
<div className="groupInput">
|
||||
<select
|
||||
@@ -66,7 +66,7 @@ const EnviarMensajeSala = ({ titulo }: EnviarMensajeSalaProps) => {
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<label className="label">Seleccione el mensaje</label>
|
||||
<div className="groupInput">
|
||||
<select value={mensaje} onChange={(e) => setMensaje(e.target.value)}>
|
||||
|
||||
@@ -15,7 +15,7 @@ export default function Information(props: InformationProps) {
|
||||
{entries.map(([key, value]) => (
|
||||
<li key={key} className="informationItem">
|
||||
<span className="informationKey">{key}</span>
|
||||
<span className="informationValue">{value}</span>
|
||||
<span className={`informationValue ${key}`}>{value}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
@@ -2,57 +2,77 @@
|
||||
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
import SearchDate from "../../SearchDate/SearchDate";
|
||||
|
||||
interface urlProp {
|
||||
value: string | null;
|
||||
}
|
||||
|
||||
function SearchUserWithDate(props: urlProp) {
|
||||
const [numAcount, setnumAcount] = useState("");
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
const todayISO = new Date().toLocaleDateString("en-CA");
|
||||
|
||||
const [numAcount, setNumAcount] = useState("");
|
||||
const [date, setDate] = useState(todayISO);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.value) {
|
||||
setnumAcount(props.value);
|
||||
}
|
||||
}, [props.value]);
|
||||
const num = searchParams.get("numAcount");
|
||||
const dateParam = searchParams.get("date");
|
||||
|
||||
if (num) setNumAcount(num);
|
||||
if (dateParam) setDate(dateParam);
|
||||
}, [searchParams]);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
|
||||
if (numAcount) {
|
||||
params.set("numAcount", `${numAcount}`);
|
||||
router.push(`${pathname}?${params.toString()}`);
|
||||
params.set("numAcount", numAcount);
|
||||
}
|
||||
|
||||
if (date) {
|
||||
params.set("date", date);
|
||||
}
|
||||
|
||||
router.push(`${pathname}?${params.toString()}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<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;
|
||||
if (/^\d*$/.test(value) && value.length <= 9) {
|
||||
setnumAcount(value);
|
||||
}
|
||||
}}
|
||||
placeholder="Coloca un número de cuenta..."
|
||||
inputMode="numeric"
|
||||
pattern="[0-9]*"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
<SearchDate />
|
||||
</>
|
||||
<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;
|
||||
if (/^\d*$/.test(value) && value.length <= 9) {
|
||||
setNumAcount(value);
|
||||
}
|
||||
}}
|
||||
placeholder="Coloca un número de cuenta..."
|
||||
/>
|
||||
</div>
|
||||
|
||||
<label className="label">Fecha</label>
|
||||
<div className="groupInput">
|
||||
|
||||
<input
|
||||
type="date"
|
||||
value={date}
|
||||
onChange={(e) => setDate(e.target.value)}
|
||||
/>
|
||||
|
||||
<button className="button buttonSearch" type="submit">
|
||||
Buscar
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
export default SearchUserWithDate;
|
||||
//IO
|
||||
|
||||
@@ -8,7 +8,7 @@ interface urlProp {
|
||||
}
|
||||
|
||||
function SearchUser(props: urlProp) {
|
||||
const [numAcount, setnumAcount] = useState("");
|
||||
const [numAcount, setnumAcount] = useState<string>("");
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
@@ -17,6 +17,10 @@ function SearchUser(props: urlProp) {
|
||||
if (props.value) {
|
||||
setnumAcount(props.value);
|
||||
}
|
||||
|
||||
if(props.value===null){
|
||||
setnumAcount("")
|
||||
}
|
||||
}, [props.value]);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
interface SearchUserProps {
|
||||
value?: string | null;
|
||||
@@ -19,7 +20,9 @@ export default function SearchUserTable({ value }: SearchUserProps) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
// Si el prop cambia, actualizar el input
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
useEffect(() => {
|
||||
if (value) setNumAcount(value);
|
||||
}, [value]);
|
||||
@@ -37,8 +40,8 @@ export default function SearchUserTable({ value }: SearchUserProps) {
|
||||
setAlumno(null);
|
||||
|
||||
try {
|
||||
// Llamada a la API con Axios
|
||||
const { data } = await axios.get<Alumno>(`/api/alumnos/${numAcount}`);
|
||||
const { data } = await axios.get<Alumno>(`/api/alumnos/${numAcount}`, { headers },
|
||||
);
|
||||
setAlumno(data);
|
||||
} catch (err: any) {
|
||||
setAlumno(null);
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import Swal from "sweetalert2";
|
||||
|
||||
export default function ShowError({ message }: { message: string }) {
|
||||
useEffect(() => {
|
||||
if (message) {
|
||||
toast.error(message);
|
||||
Swal.fire({
|
||||
title: message,
|
||||
icon: "error",
|
||||
draggable: true,
|
||||
});
|
||||
}
|
||||
}, [message]);
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { useState, ReactNode } from "react";
|
||||
interface ToggleOption {
|
||||
key: string;
|
||||
label: string;
|
||||
content: ReactNode;
|
||||
content: ReactNode | (() => ReactNode);
|
||||
}
|
||||
|
||||
interface ToggleProps {
|
||||
@@ -46,7 +46,15 @@ export default function Toggle({ options, defaultView }: ToggleProps) {
|
||||
</div>
|
||||
|
||||
<div className="padding toggleContent">
|
||||
{options.find((opt) => opt.key === view)?.content}
|
||||
{(() => {
|
||||
const active = options.find((opt) => opt.key === view)?.content;
|
||||
|
||||
if (typeof active === "function") {
|
||||
return active();
|
||||
}
|
||||
|
||||
return active;
|
||||
})()}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
import apiClient from "@/app/lib/apiClient";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export default function selectArea() {
|
||||
const [area, setArea] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchArea = async () => {
|
||||
const response = await apiClient.get("/area-ubicacion");
|
||||
setArea(response.data);
|
||||
};
|
||||
|
||||
fetchArea();
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<label className="label">Seleccione el área</label>
|
||||
<select>
|
||||
{area.map((area) => (
|
||||
<option>{area}</option>
|
||||
))}
|
||||
<option value="0">windows</option>
|
||||
<option value="1">ADOBE CREATIVE SUITE</option>
|
||||
<option value="2">mmmmm</option>
|
||||
<option value="3">mmmmm</option>
|
||||
<option value="4">mmmmm</option>
|
||||
<option value="5">mmmmm</option>
|
||||
</select>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
.tableContainer {
|
||||
margin-top: 1rem;
|
||||
margin-top: 2rem;
|
||||
width: 100%;
|
||||
max-width: 450px;
|
||||
overflow-x: hidden;
|
||||
@@ -43,4 +43,17 @@
|
||||
background-repeat: no-repeat;
|
||||
margin-right: 6px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
@media(max-height:800px) {
|
||||
.tableContainer {
|
||||
margin-top: 1.5rem;
|
||||
max-width: 320px;
|
||||
}
|
||||
}
|
||||
|
||||
@media(max-width:800px) {
|
||||
.tableContainer {
|
||||
margin-top: 0px;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import Cookies from "js-cookie";
|
||||
import { useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { PostImpressions } from "@/app/lib/postImpressions";
|
||||
import toast from "react-hot-toast";
|
||||
import Swal from "sweetalert2";
|
||||
|
||||
interface CostOption {
|
||||
@@ -19,10 +18,11 @@ interface ImpressionsProps {
|
||||
|
||||
function Impressions({ costs, numAcount, id_servicio }: ImpressionsProps) {
|
||||
const [pages, setPages] = useState("");
|
||||
const [cost, setCost] = useState("");
|
||||
const [cost, setCost] = useState(String(costs[0].value));
|
||||
|
||||
const total = Number(cost) * Number(pages);
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const handleLogout = () => {
|
||||
Cookies.remove("token");
|
||||
Cookies.remove("session");
|
||||
@@ -30,25 +30,40 @@ function Impressions({ costs, numAcount, id_servicio }: ImpressionsProps) {
|
||||
};
|
||||
|
||||
const handlePayment = async () => {
|
||||
if (!numAcount) {
|
||||
toast.error("busca de nuevo al estudiante");
|
||||
if (numAcount == null) {
|
||||
|
||||
Swal.fire({
|
||||
title: "busca de nuevo al estudiante!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pages) {
|
||||
toast.error("Ingresa el numero de hojas a imprimir");
|
||||
|
||||
Swal.fire({
|
||||
title: "Ingresa el numero de hojas a imprimir!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cost) {
|
||||
toast.error("Selecciona un costo");
|
||||
|
||||
Swal.fire({
|
||||
title: "Selecciona un costo!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await PostImpressions({
|
||||
id_cuenta: numAcount,
|
||||
numero_hojas: parseInt(pages),
|
||||
monto: parseInt(cost) * parseInt(pages),
|
||||
monto: total,
|
||||
id_servicio,
|
||||
});
|
||||
|
||||
@@ -56,16 +71,20 @@ function Impressions({ costs, numAcount, id_servicio }: ImpressionsProps) {
|
||||
if (result.message === "Token inválido") {
|
||||
handleLogout();
|
||||
} else {
|
||||
toast.error(result.message);
|
||||
Swal.fire({
|
||||
title: result.message,
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
setPages("");
|
||||
setCost("");
|
||||
toast.success("Impresion cobrada correctamente");
|
||||
setCost(String(costs[0].value));
|
||||
|
||||
Swal.fire({
|
||||
title: "Cobro exitoso!",
|
||||
title: "Impresion cobrada correctamente!",
|
||||
icon: "success",
|
||||
draggable: true
|
||||
});
|
||||
@@ -110,14 +129,13 @@ function Impressions({ costs, numAcount, id_servicio }: ImpressionsProps) {
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="groupInput"
|
||||
style={{ height: "35px", flexWrap: "nowrap" }}
|
||||
className="groupInput total"
|
||||
>
|
||||
<label className="label">Total:</label>
|
||||
<label
|
||||
style={{ width: "100%", minWidth: "200px", maxWidth: "500px" }}
|
||||
>
|
||||
{pages && cost && `$${parseInt(cost) * parseInt(pages)}.00`}
|
||||
{pages && cost && `$${total}.00`}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -2,17 +2,8 @@
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
import axios from "axios";
|
||||
import { useEffect, useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
|
||||
interface Equipos {
|
||||
id_equipo: number;
|
||||
id_plataforma: number;
|
||||
id_area_ubicacion: number;
|
||||
nombre_equipo: string;
|
||||
ubicacion: string;
|
||||
activo: boolean;
|
||||
ip: string;
|
||||
}
|
||||
import Swal from "sweetalert2";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
interface Programa {
|
||||
id_programa: number;
|
||||
@@ -26,16 +17,17 @@ export default function ProgramSelector({
|
||||
ubicacion?: string | null;
|
||||
id?: number | null;
|
||||
}) {
|
||||
const [equipoSelection, setEquipoSelection] = useState<string>("");
|
||||
const [roomSelection, setRoomSelection] = useState<number>();
|
||||
const [programas, setProgramas] = useState<Programa[]>([]);
|
||||
const [checkboxes, setCheckboxes] = useState<Record<number, boolean>>({});
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
const [programasRes] = await Promise.all([
|
||||
axios.get(`${envConfig.apiUrl}/programa`),
|
||||
]);
|
||||
axios.get(`${envConfig.apiUrl}/programa`, { headers },
|
||||
)]);
|
||||
|
||||
setProgramas(programasRes.data);
|
||||
|
||||
@@ -70,25 +62,49 @@ export default function ProgramSelector({
|
||||
{
|
||||
programas: programasSeleccionados,
|
||||
},
|
||||
{ headers },
|
||||
);
|
||||
|
||||
toast.success("Programas actualizados en la máquina");
|
||||
|
||||
Swal.fire({
|
||||
title: "Programas actualizados en la máquina!",
|
||||
icon: "success",
|
||||
draggable: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (id) {
|
||||
await axios.patch(`${envConfig.apiUrl}/programa-equipo/sala`, {
|
||||
sala: id,
|
||||
programas: programasSeleccionados,
|
||||
});
|
||||
await axios.patch(`${envConfig.apiUrl}/programa-equipo/sala`,
|
||||
{
|
||||
sala: id,
|
||||
programas: programasSeleccionados,
|
||||
},
|
||||
{ headers },
|
||||
);
|
||||
|
||||
toast.success("Programas actualizados en la sala");
|
||||
|
||||
Swal.fire({
|
||||
title: "Programas actualizados en la sala",
|
||||
icon: "success",
|
||||
draggable: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
toast.error("No se pudo determinar el destino");
|
||||
Swal.fire({
|
||||
title: "No se pudo determinar el destino!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
} catch (error) {
|
||||
toast.error("Error al guardar cambios");
|
||||
|
||||
|
||||
Swal.fire({
|
||||
title: "Error al guardar cambios!",
|
||||
icon: "error",
|
||||
draggable: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -108,12 +124,15 @@ export default function ProgramSelector({
|
||||
if (ubicacion && ubicacion !== "0") {
|
||||
res = await axios.get(
|
||||
`${envConfig.apiUrl}/programa-equipo/${ubicacion}`,
|
||||
{ headers },
|
||||
);
|
||||
}
|
||||
|
||||
if (id) {
|
||||
res = await axios.get(
|
||||
`${envConfig.apiUrl}/area-ubicacion/programs/${id}`,
|
||||
{ headers },
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
@@ -123,12 +142,28 @@ export default function ProgramSelector({
|
||||
} catch (error: any) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
if (error.response?.status === 404) {
|
||||
toast.error("Sin programas asignados");
|
||||
|
||||
Swal.fire({
|
||||
title: "Sin programas asignados!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
} else {
|
||||
toast.error("Error al cargar programas");
|
||||
|
||||
Swal.fire({
|
||||
title: "Error al cargar programas!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
|
||||
}
|
||||
} else {
|
||||
toast.error("Error inesperado");
|
||||
|
||||
Swal.fire({
|
||||
title: "Error inesperado!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +175,7 @@ export default function ProgramSelector({
|
||||
|
||||
return (
|
||||
<form className="form-container" onSubmit={handleSubmit}>
|
||||
<div className="checkbox-grid">
|
||||
<div className="checkbox-grid" style={{ gridAutoFlow: "column" }}>
|
||||
{programas.map((prog) => (
|
||||
<label key={prog.id_programa}>
|
||||
<input
|
||||
@@ -159,4 +194,4 @@ export default function ProgramSelector({
|
||||
</form>
|
||||
);
|
||||
}
|
||||
//IO
|
||||
//IO
|
||||
@@ -1,8 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
import "../../(private)/AsignacionEquipo/asignacion.css";
|
||||
|
||||
@@ -33,10 +35,15 @@ export default function SelectorEquipo({ onSearch }: Props) {
|
||||
const [loadingEquipos, setLoadingEquipos] = useState(false);
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
setLoadingEquipos(true);
|
||||
const response = await axios.get(`${envConfig.apiUrl}/equipo`);
|
||||
const response = await axios.get(`${envConfig.apiUrl}/equipo`, { headers },
|
||||
);
|
||||
setEquipos(response.data);
|
||||
setLoadingEquipos(false);
|
||||
};
|
||||
@@ -85,7 +92,7 @@ export default function SelectorEquipo({ onSearch }: Props) {
|
||||
</div>
|
||||
|
||||
{open && (
|
||||
<div className="options" style={{ bottom: "auto"}}>
|
||||
<div className="options" style={{ bottom: "auto" }}>
|
||||
{equipos.length === 0 && (
|
||||
<div className="option disabled">
|
||||
No hay equipos disponibles
|
||||
|
||||
@@ -3,6 +3,7 @@ import { envConfig } from "@/app/lib/config";
|
||||
import { useEffect, useState } from "react";
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
interface Area {
|
||||
id_area_ubicacion: number;
|
||||
@@ -45,8 +46,13 @@ export default function SelectorSala({ onSearch }: Props) {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
const fetchData = async () => {
|
||||
const response = await axios.get(`${envConfig.apiUrl}/area-ubicacion`);
|
||||
const response = await axios.get(`${envConfig.apiUrl}/area-ubicacion`, { headers },
|
||||
);
|
||||
setSala(response.data);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,75 +1,64 @@
|
||||
interface Alumno {
|
||||
id_cuenta: number;
|
||||
nombre: string;
|
||||
credito: number;
|
||||
}
|
||||
"use client";
|
||||
|
||||
interface Sancion {
|
||||
id_sancion: number;
|
||||
sancion: string;
|
||||
duracion: number;
|
||||
}
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
import { useEffect, useState } from "react";
|
||||
import { GetSancionByStudent } from "@/app/lib/getSancionByStudent";
|
||||
import { Alumno, AlumnoSancion } from "@/app/types/sanction";
|
||||
import TableSanction from "../BitacoraSanciones/TableSanction";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
interface AlumnoSancion {
|
||||
id_alumno_sancion: number;
|
||||
fecha_inicio: string;
|
||||
sancion: Sancion;
|
||||
}
|
||||
function QuitarSancion({ id_cuenta }: { id_cuenta: number }) {
|
||||
const [alumno, setAlumno] = useState<Alumno>();
|
||||
const [alumnoSanciones, setAlumnoSanciones] = useState<AlumnoSancion[]>([]);
|
||||
const [loading, setLoading] = useState<boolean>(false)
|
||||
|
||||
interface DataProps {
|
||||
student: Alumno;
|
||||
alusancion: AlumnoSancion[];
|
||||
}
|
||||
const fetchAlumnoSanciones = async () => {
|
||||
try {
|
||||
|
||||
interface Props {
|
||||
data: DataProps | null;
|
||||
}
|
||||
const res = await GetSancionByStudent(id_cuenta);
|
||||
|
||||
function QuitarSancion({ data }: Props) {
|
||||
const calcularFechaFin = (fechaInicio: string, duracionSemanas: number) => {
|
||||
const fecha = new Date(fechaInicio);
|
||||
fecha.setDate(fecha.getDate() + duracionSemanas * 7);
|
||||
return fecha.toLocaleDateString();
|
||||
setAlumno(res.student ?? null);
|
||||
setAlumnoSanciones(res.alusancion ?? []);
|
||||
} catch {
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!id_cuenta) return;
|
||||
|
||||
fetchAlumnoSanciones();
|
||||
|
||||
}, [id_cuenta]);
|
||||
|
||||
const handleButton = async (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.preventDefault();
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
setLoading(true)
|
||||
await axios.delete(`${envConfig.apiUrl}/alumno-sancion/${id_cuenta}`, { headers })
|
||||
setAlumnoSanciones([])
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="containerSection">
|
||||
<div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Nombre</th>
|
||||
<th>Motivo Sanción</th>
|
||||
<th>Duración (semanas)</th>
|
||||
<th>Fecha Sanción</th>
|
||||
<th>Podra utilizar el servicio hasta</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data && data.alusancion.length !== 0 ? (
|
||||
data.alusancion.map((item) => (
|
||||
<tr key={item.id_alumno_sancion}>
|
||||
<td>{item.id_alumno_sancion}</td>
|
||||
<td>{data.student.nombre}</td>
|
||||
<td>{item.sancion.sancion}</td>
|
||||
<td>{item.sancion.duracion}</td>
|
||||
<td>{new Date(item.fecha_inicio).toLocaleDateString()}</td>
|
||||
<td>
|
||||
{calcularFechaFin(item.fecha_inicio, item.sancion.duracion)}
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
) : (
|
||||
<tr>
|
||||
<td colSpan={6}>No hay sanciones registradas</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<TableSanction alumnoSanciones={alumnoSanciones} alumno={alumno} />
|
||||
{(alumnoSanciones?.length > 0) &&
|
||||
<button
|
||||
className="button buttonSearch"
|
||||
style={{ margin: "1rem 0" }}
|
||||
onClick={handleButton}
|
||||
disabled={loading}
|
||||
>
|
||||
Quitar sancion
|
||||
</button>
|
||||
}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default QuitarSancion;
|
||||
//IO
|
||||
@@ -1,16 +1,15 @@
|
||||
"use client";
|
||||
|
||||
import toast from "react-hot-toast";
|
||||
import { useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
|
||||
import Selection from "../Selection/Selection";
|
||||
import { envConfig } from "@/app/lib/config";
|
||||
import Cookies from "js-cookie";
|
||||
import axios from "axios";
|
||||
import Swal from "sweetalert2";
|
||||
|
||||
import "./Receipt.css";
|
||||
import Swal from "sweetalert2";
|
||||
|
||||
interface ReceiptsProps {
|
||||
numAcount: number | null;
|
||||
@@ -33,11 +32,13 @@ export default function Inscripcion({
|
||||
>(null);
|
||||
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
const [folio, setFolio] = useState("");
|
||||
const [amount, setAmount] = useState("");
|
||||
const [lock, setLock] = useState<boolean>(true);
|
||||
const todayISO = new Date().toISOString().split("T")[0];
|
||||
const todayISO = new Date().toLocaleDateString("en-CA");
|
||||
const [date, setDate] = useState(todayISO);
|
||||
|
||||
//restrict this month//
|
||||
@@ -46,33 +47,63 @@ export default function Inscripcion({
|
||||
const month = day.getMonth();
|
||||
const today = day.getDate();
|
||||
|
||||
const minFecha = new Date(year, month, 1).toISOString().split("T")[0];
|
||||
let minMount = month
|
||||
if(!lock){
|
||||
minMount = month-1
|
||||
}
|
||||
|
||||
const minFecha = new Date(year, minMount, 1).toISOString().split("T")[0];
|
||||
const maxFecha = new Date(year, month, today).toISOString().split("T")[0];
|
||||
//restrict this month//
|
||||
|
||||
const handleSaveReceipt = async () => {
|
||||
if (!numAcount) {
|
||||
toast.error("busca de nuevo al estudiante");
|
||||
if (numAcount == null) {
|
||||
|
||||
Swal.fire({
|
||||
title: "busca de nuevo al estudiante!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!folio) {
|
||||
toast.error("Ingresa el folio del ticket");
|
||||
|
||||
Swal.fire({
|
||||
title: "Ingresa el folio del ticket!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!amount) {
|
||||
toast.error("Coloca el monto a depositar");
|
||||
|
||||
Swal.fire({
|
||||
title: "Coloca el monto a depositar!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!date) {
|
||||
toast.error("Coloca la fecha");
|
||||
|
||||
Swal.fire({
|
||||
title: "Coloca la fecha!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!plataformaSeleccionada) {
|
||||
toast.error("Selecciona una plataforma");
|
||||
|
||||
Swal.fire({
|
||||
title: "Selecciona una plataforma!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -95,58 +126,88 @@ export default function Inscripcion({
|
||||
{ headers },
|
||||
);
|
||||
|
||||
toast.success("Alumno con pago");
|
||||
Swal.fire("Alumno con pago");
|
||||
Swal.fire({
|
||||
title: "Alumno inscrito con pago",
|
||||
icon: "success",
|
||||
draggable: true
|
||||
});
|
||||
setFolio("");
|
||||
setAmount("");
|
||||
setDate(todayISO);
|
||||
|
||||
router.refresh();
|
||||
} catch (err: any) {
|
||||
toast.error(String(err));
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
params.delete("numAcount");
|
||||
router.push(`${pathname}?${params.toString()}`);
|
||||
|
||||
} catch (error: any) {
|
||||
const msg =
|
||||
error.response?.data?.message ||
|
||||
error.message ||
|
||||
"Error desconocido al crear recibo";
|
||||
Swal.fire({
|
||||
title: msg,
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleInscripcionSinPago = async () => {
|
||||
if (!numAcount) {
|
||||
toast.error("busca de nuevo al estudiante");
|
||||
if (numAcount == null) {
|
||||
|
||||
Swal.fire({
|
||||
title: "busca de nuevo al estudiante!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!plataformaSeleccionada) {
|
||||
toast.error("Selecciona una plataforma");
|
||||
|
||||
Swal.fire({
|
||||
title: "Selecciona una plataforma!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const id_plataforma = PLATAFORMA_MAP[plataformaSeleccionada];
|
||||
|
||||
try {
|
||||
const res = await fetch(`${envConfig.apiUrl}/alumno-inscrito`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
await axios.post(
|
||||
`${envConfig.apiUrl}/alumno-inscrito`,
|
||||
{
|
||||
id_cuenta: numAcount,
|
||||
id_plataforma,
|
||||
realizo_pago: false,
|
||||
}),
|
||||
});
|
||||
},
|
||||
{ headers },
|
||||
);
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
if (!res.ok) {
|
||||
Swal.fire("Error");
|
||||
throw new Error(data.message || "Error al inscribir");
|
||||
}
|
||||
|
||||
toast.success("Alumno inscrito sin pago");
|
||||
Swal.fire({
|
||||
title: "Alumno inscrito sin pago!",
|
||||
icon: "success",
|
||||
draggable: true
|
||||
draggable: true,
|
||||
});
|
||||
|
||||
router.refresh();
|
||||
|
||||
} catch (err: any) {
|
||||
toast.error(err.message);
|
||||
|
||||
const message =
|
||||
err.response?.data?.message || "Error al inscribir";
|
||||
|
||||
Swal.fire({
|
||||
title: message,
|
||||
icon: "error",
|
||||
draggable: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -161,7 +222,6 @@ export default function Inscripcion({
|
||||
value={conPago}
|
||||
onChange={(e) => setConPago(e.target.value as "con" | "sin")}
|
||||
style={{
|
||||
marginBottom: "1rem",
|
||||
maxWidth: "120px",
|
||||
minWidth: "120px",
|
||||
}}
|
||||
@@ -206,7 +266,25 @@ export default function Inscripcion({
|
||||
const numericValue = parseFloat(value);
|
||||
|
||||
if (lock && numericValue > 1000) {
|
||||
toast.error("El monto no puede superar $1000.00");
|
||||
|
||||
Swal.fire({
|
||||
title:
|
||||
"El monto no puede superar $1000.00 Desbloquea el candado !",
|
||||
icon: "error",
|
||||
draggable: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (numericValue > 10000) {
|
||||
|
||||
Swal.fire({
|
||||
title:
|
||||
"El monto no puede superar $10000.00 pesos",
|
||||
icon: "error",
|
||||
draggable: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -229,16 +307,16 @@ export default function Inscripcion({
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="containerButton" style={{ position: 'relative' }}>
|
||||
|
||||
<button className="button buttonSearch">Inscribir</button>
|
||||
<div className="containerButton" style={{ position: "relative" }}>
|
||||
<button className="button buttonSearch" disabled={!plataformaSeleccionada}
|
||||
>Inscribir</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`button buttonCancel ${lock ? "buttonLock" : "buttonOpenLock"
|
||||
}`}
|
||||
onClick={() => {
|
||||
setLock((prev) => !prev)
|
||||
setAmount('');
|
||||
setLock((prev) => !prev);
|
||||
setAmount("");
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@@ -246,7 +324,6 @@ export default function Inscripcion({
|
||||
</form>
|
||||
)}
|
||||
{conPago === "sin" && (
|
||||
|
||||
<div className="containerButton">
|
||||
<button
|
||||
className="button buttonSearch"
|
||||
|
||||
@@ -23,21 +23,21 @@
|
||||
background-color: #cfcfcf;
|
||||
}
|
||||
|
||||
.buttonLock{
|
||||
.buttonLock {
|
||||
padding: 0.8rem;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
right: 100px;
|
||||
background-color: #d32f2f;
|
||||
}
|
||||
|
||||
.buttonOpenLock{
|
||||
.buttonOpenLock {
|
||||
padding: 0.8rem;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
right: 100px;
|
||||
background-color: #8cd32f;
|
||||
}
|
||||
|
||||
.buttonOpenLock:hover{
|
||||
.buttonOpenLock:hover {
|
||||
background-color: #78b32c;
|
||||
}
|
||||
|
||||
@@ -61,4 +61,10 @@
|
||||
filter: invert(1);
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
@media(max-height:800px) {
|
||||
.buttonLock {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,23 @@
|
||||
"use client";
|
||||
|
||||
import toast from "react-hot-toast";
|
||||
import { useState } from "react";
|
||||
import { PostReceipt } from "@/app/lib/postReceipt";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
import "./Receipt.css";
|
||||
import Swal from "sweetalert2";
|
||||
import "./Receipt.css";
|
||||
|
||||
interface ReceiptsProps {
|
||||
numAcount: number | null;
|
||||
}
|
||||
|
||||
function Receipt({ numAcount }: ReceiptsProps) {
|
||||
export default function Receipt({ numAcount }: ReceiptsProps) {
|
||||
const router = useRouter();
|
||||
|
||||
const [folio, setFolio] = useState("");
|
||||
const [amount, setAmount] = useState("");
|
||||
const [lock, setLock] = useState<boolean>(true);
|
||||
const todayISO = new Date().toISOString().split("T")[0];
|
||||
const todayISO = new Date().toLocaleDateString("en-CA");
|
||||
const [date, setDate] = useState(todayISO);
|
||||
|
||||
//restrict this month//
|
||||
@@ -27,28 +26,53 @@ function Receipt({ numAcount }: ReceiptsProps) {
|
||||
const month = day.getMonth();
|
||||
const today = day.getDate();
|
||||
|
||||
const minFecha = new Date(year, month, 1).toISOString().split("T")[0];
|
||||
let minMount = month
|
||||
if(!lock){
|
||||
minMount = month-1
|
||||
}
|
||||
|
||||
const minFecha = new Date(year, minMount, 1).toISOString().split("T")[0];
|
||||
const maxFecha = new Date(year, month, today).toISOString().split("T")[0];
|
||||
//restrict this month//
|
||||
|
||||
const handleSaveReceipt = async () => {
|
||||
if (!numAcount) {
|
||||
toast.error("busca de nuevo al estudiante");
|
||||
if (numAcount == null) {
|
||||
|
||||
Swal.fire({
|
||||
title: "busca de nuevo al estudiante!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!folio) {
|
||||
toast.error("Ingresa el folio del ticket");
|
||||
|
||||
Swal.fire({
|
||||
title: "Ingresa el folio del ticket!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!amount) {
|
||||
toast.error("Coloca el monto a depositar");
|
||||
|
||||
Swal.fire({
|
||||
title: "Coloca el monto a depositar!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!date) {
|
||||
toast.error("Coloca la fecha");
|
||||
|
||||
Swal.fire({
|
||||
title: "Coloca la fecha!",
|
||||
icon: "error",
|
||||
draggable: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -64,16 +88,20 @@ function Receipt({ numAcount }: ReceiptsProps) {
|
||||
setAmount("");
|
||||
setDate(todayISO);
|
||||
|
||||
toast.success("Recibo guardado");
|
||||
|
||||
Swal.fire({
|
||||
title: "Recibo Guardado!",
|
||||
title: "Recibo Guardado Correctamente!",
|
||||
icon: "success",
|
||||
draggable: true
|
||||
});
|
||||
|
||||
router.refresh();
|
||||
} catch (err: any) {
|
||||
toast.error(String(err));
|
||||
Swal.fire({
|
||||
title: err,
|
||||
icon: "error",
|
||||
draggable: false
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -114,7 +142,24 @@ function Receipt({ numAcount }: ReceiptsProps) {
|
||||
const numericValue = parseFloat(value);
|
||||
|
||||
if (lock && numericValue > 1000) {
|
||||
toast.error("El monto no puede superar $1000.00");
|
||||
|
||||
Swal.fire({
|
||||
title:
|
||||
"El monto no puede superar $1000.00 Desbloquea el candado !",
|
||||
icon: "error",
|
||||
draggable: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (numericValue > 10000) {
|
||||
|
||||
Swal.fire({
|
||||
title:
|
||||
"El monto no puede superar $10000.00 pesos",
|
||||
icon: "error",
|
||||
draggable: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -154,6 +199,4 @@ function Receipt({ numAcount }: ReceiptsProps) {
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
export default Receipt;
|
||||
//IO
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import axios from "axios";
|
||||
import DownloadReporteXLSX from "../Dowload/Reporte";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
interface Recibo {
|
||||
id_recibo: number;
|
||||
@@ -20,19 +21,31 @@ interface Props {
|
||||
hasta: string | null;
|
||||
}
|
||||
|
||||
function PorRecibos({ desde, hasta }: Props) {
|
||||
export default function PorRecibos({ desde, hasta }: Props) {
|
||||
const [recibos, setRecibos] = useState<Recibo[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const columns = [
|
||||
{ header: "Folio", key: "folio", width: 15 },
|
||||
{ header: "Monto", key: "monto", width: 15 },
|
||||
{ header: "Fecha Recibo", key: "fechaRecibo", width: 18 },
|
||||
{ header: "Fecha Registro", key: "fechaRegistro", width: 22 },
|
||||
{ header: "Usuario", key: "usuario", width: 20 },
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
if (!desde || !hasta) return;
|
||||
|
||||
const fetchRecibos = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
const res = await axios.post(
|
||||
`${process.env.NEXT_PUBLIC_API_URL}/recibo/rango`,
|
||||
{ desde, hasta }
|
||||
{ desde, hasta },
|
||||
{ headers },
|
||||
);
|
||||
|
||||
setRecibos(res.data);
|
||||
@@ -61,7 +74,8 @@ function PorRecibos({ desde, hasta }: Props) {
|
||||
|
||||
return (
|
||||
<div style={{ position: "relative" }}>
|
||||
{recibos.length > 0 && <DownloadReporteXLSX />}
|
||||
{recibos.length > 0 && <DownloadReporteXLSX data={recibos} columns={columns} />}
|
||||
|
||||
<div
|
||||
style={{
|
||||
overflow: "auto",
|
||||
@@ -105,5 +119,4 @@ function PorRecibos({ desde, hasta }: Props) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default PorRecibos;
|
||||
//IO
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import axios from "axios";
|
||||
import DownloadReporteXLSX from "../Dowload/Reporte";
|
||||
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
interface ServicioReporte {
|
||||
id_servicio: number;
|
||||
@@ -16,7 +15,7 @@ interface Props {
|
||||
hasta: string | null;
|
||||
}
|
||||
|
||||
function PorServicio({ desde, hasta }: Props) {
|
||||
export default function PorServicio({ desde, hasta }: Props) {
|
||||
const [servicios, setServicios] = useState<ServicioReporte[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
@@ -26,9 +25,13 @@ function PorServicio({ desde, hasta }: Props) {
|
||||
const fetchServicios = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
const res = await axios.post(
|
||||
`${process.env.NEXT_PUBLIC_API_URL}/detalle-servicio/rango`,
|
||||
{ desde, hasta }
|
||||
{ desde, hasta },
|
||||
{ headers },
|
||||
);
|
||||
|
||||
setServicios(res.data);
|
||||
@@ -44,7 +47,6 @@ function PorServicio({ desde, hasta }: Props) {
|
||||
|
||||
return (
|
||||
<div style={{ position: "relative" }}>
|
||||
{servicios.length > 0 && <DownloadReporteXLSX />}
|
||||
|
||||
<div
|
||||
style={{
|
||||
@@ -82,5 +84,4 @@ function PorServicio({ desde, hasta }: Props) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default PorServicio;
|
||||
//IO
|
||||
@@ -1,29 +1,50 @@
|
||||
"use client";
|
||||
import { useState } from "react";
|
||||
|
||||
function SearchDate() {
|
||||
const [date, setDate] = useState("");
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
export default function SearchDate() {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
const todayISO = new Date().toLocaleDateString("en-CA");
|
||||
const [date, setDate] = useState(todayISO);
|
||||
|
||||
useEffect(() => {
|
||||
const dateParam = searchParams.get("date");
|
||||
if (dateParam) {
|
||||
setDate(dateParam);
|
||||
}
|
||||
}, [searchParams]);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
|
||||
if (date) {
|
||||
params.set("date", date);
|
||||
}
|
||||
|
||||
router.push(`${pathname}?${params.toString()}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<form className="containerForm">
|
||||
<label className="label">Fecha</label>
|
||||
<div className="groupInput">
|
||||
<input
|
||||
type="date"
|
||||
value={date}
|
||||
onChange={(e) => setDate(e.target.value)}
|
||||
placeholder="Selecciona una fecha..."
|
||||
/>
|
||||
<button className="button buttonSearch" type="submit">
|
||||
Buscar
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</>
|
||||
<form className="containerForm" onSubmit={handleSubmit}>
|
||||
<label className="label">Fecha</label>
|
||||
<div className="groupInput">
|
||||
<input
|
||||
type="date"
|
||||
value={date}
|
||||
onChange={(e) => setDate(e.target.value)}
|
||||
/>
|
||||
<button className="button buttonSearch" type="submit">
|
||||
Buscar
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
export default SearchDate;
|
||||
|
||||
//IO
|
||||
//By Tyrannuss
|
||||
|
||||
@@ -7,9 +7,10 @@ interface Props {
|
||||
onSearch: (desde: string, hasta: string) => void;
|
||||
}
|
||||
|
||||
function SearchDateBetween({ onSearch }: Props) {
|
||||
export default function SearchDateBetween({ onSearch }: Props) {
|
||||
const [startDate, setStartDate] = useState("");
|
||||
const [endDate, setEndDate] = useState("");
|
||||
const todayISO = new Date().toLocaleDateString("en-CA");
|
||||
const [endDate, setEndDate] = useState(todayISO);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
@@ -54,5 +55,4 @@ function SearchDateBetween({ onSearch }: Props) {
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
export default SearchDateBetween;
|
||||
//IO
|
||||
@@ -1,63 +1,28 @@
|
||||
"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 urlProp {
|
||||
value: string | null;
|
||||
}
|
||||
|
||||
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() {
|
||||
export default function SearchMesa(props: urlProp) {
|
||||
const [inputValue, setInputValue] = useState("");
|
||||
const [idCuenta, setIdCuenta] = useState<number | null>(null);
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
useEffect(() => {
|
||||
if (props.value) {
|
||||
setInputValue(props.value);
|
||||
}
|
||||
|
||||
if(props.value===null){
|
||||
setInputValue("")
|
||||
}
|
||||
}, [props.value]);
|
||||
|
||||
const buscar = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
@@ -74,7 +39,7 @@ export default function SearchMesa() {
|
||||
|
||||
<div className="groupInput">
|
||||
<input
|
||||
type="number"
|
||||
type="text"
|
||||
placeholder="Coloca el numero de mesa"
|
||||
value={inputValue}
|
||||
onChange={(e) => setInputValue(e.target.value)}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
"use client";
|
||||
import axios from "axios";
|
||||
import { useEffect, useState } from "react";
|
||||
import { envConfig } from "../lib/config";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
if (!envConfig.apiUrl) {
|
||||
console.error("API URL is not defined in envConfig");
|
||||
@@ -15,9 +16,14 @@ export default function SelectAreas(props: proms) {
|
||||
const [areas, setAreas] = useState([]);
|
||||
const [selectedArea, setSelectedArea] = useState("");
|
||||
|
||||
const token = Cookies.get("token");
|
||||
const headers = { Authorization: `Bearer ${token}` };
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
axios
|
||||
.get(`${envConfig.apiUrl}/area-ubicacion`)
|
||||
.get(`${envConfig.apiUrl}/area-ubicacion`, { headers }
|
||||
)
|
||||
.then((data) => {
|
||||
setAreas(data.data);
|
||||
})
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.selectionItem {
|
||||
@@ -14,6 +15,10 @@
|
||||
}
|
||||
|
||||
.buttonSelection {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 100%;
|
||||
@@ -23,6 +28,13 @@
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.imageSelection {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
position: relative;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.buttonSelection:hover {
|
||||
transform: scale(1.1);
|
||||
background-color: #d0e1ff;
|
||||
@@ -40,3 +52,31 @@
|
||||
color: #333;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media(max-height:550px) {
|
||||
.buttonLabel {
|
||||
margin-top: 2px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media(max-height:550px) {
|
||||
.selection {
|
||||
margin-bottom: 0rem;
|
||||
gap: 2rem;
|
||||
|
||||
}
|
||||
|
||||
.buttonSelection {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.imageSelection {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
position: relative;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import Image from "next/image";
|
||||
import "./Selection.css";
|
||||
|
||||
function Selection({
|
||||
export default function Selection({
|
||||
plataformasInscritas = [],
|
||||
onSelect,
|
||||
}: {
|
||||
@@ -24,11 +25,11 @@ function Selection({
|
||||
},
|
||||
{
|
||||
name: "MACINTOSH",
|
||||
img: "apple.png",
|
||||
img: "/apple.png",
|
||||
},
|
||||
{
|
||||
name: "PROFESORES",
|
||||
img: "teacher.png",
|
||||
img: "/teacher.png",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -45,16 +46,16 @@ function Selection({
|
||||
onClick={() => handleSelect(option.name)}
|
||||
>
|
||||
<button
|
||||
className={`buttonSelection ${
|
||||
selected === option.name ? "active" : ""
|
||||
}`}
|
||||
className={`buttonSelection ${selected === option.name ? "active" : ""
|
||||
}`}
|
||||
>
|
||||
<img
|
||||
src={option.img}
|
||||
alt={option.name.toLowerCase()}
|
||||
height={30}
|
||||
width={30}
|
||||
/>
|
||||
<div className="imageSelection">
|
||||
<Image
|
||||
src={option.img}
|
||||
alt={option.name.toLowerCase()}
|
||||
fill
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
<span className="buttonLabel">{option.name}</span>
|
||||
</div>
|
||||
@@ -68,5 +69,4 @@ function Selection({
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default Selection;
|
||||
//IO
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
import { useState } from "react";
|
||||
import "./Selection.css";
|
||||
import Image from "next/image";
|
||||
|
||||
function SelectionCo({
|
||||
export default function SelectionCo({
|
||||
plataformasInscritas = [],
|
||||
onSelect,
|
||||
}: {
|
||||
@@ -19,11 +20,11 @@ function SelectionCo({
|
||||
},
|
||||
{
|
||||
name: "MACINTOSH",
|
||||
img: "apple.png",
|
||||
img: "/apple.png",
|
||||
},
|
||||
{
|
||||
name: "PROFESORES",
|
||||
img: "teacher.png",
|
||||
img: "/teacher.png",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -46,16 +47,16 @@ function SelectionCo({
|
||||
onClick={() => handleSelect(option.name)}
|
||||
>
|
||||
<button
|
||||
className={`buttonSelection ${
|
||||
selected === option.name ? "active" : ""
|
||||
}`}
|
||||
className={`buttonSelection ${selected === option.name ? "active" : ""
|
||||
}`}
|
||||
>
|
||||
<img
|
||||
src={option.img}
|
||||
alt={option.name.toLowerCase()}
|
||||
height={30}
|
||||
width={30}
|
||||
/>
|
||||
<div className="imageSelection">
|
||||
<Image
|
||||
src={option.img}
|
||||
alt={option.name.toLowerCase()}
|
||||
fill
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
<span className="buttonLabel">{option.name}</span>
|
||||
</div>
|
||||
@@ -69,5 +70,4 @@ function SelectionCo({
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default SelectionCo;
|
||||
//IO
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
import apiClient from "@/app/lib/apiClient";
|
||||
import { useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import Swal from "sweetalert2";
|
||||
|
||||
export default function ChangePassword() {
|
||||
const [password, setPass] = useState("");
|
||||
@@ -12,16 +12,26 @@ export default function ChangePassword() {
|
||||
e.preventDefault();
|
||||
const data = { password, newPassword };
|
||||
|
||||
try{
|
||||
try {
|
||||
const response = await apiClient.post("/user/changePassword", data);
|
||||
toast.success( `${response.data.message}`)
|
||||
Swal.fire({
|
||||
title: response.data.message,
|
||||
icon: "success",
|
||||
draggable: true,
|
||||
});
|
||||
setPass('');
|
||||
setNewPass('');
|
||||
setconfirmNewPass('');
|
||||
}catch{
|
||||
toast.error( `No es la contraseña actual`)
|
||||
} catch {
|
||||
|
||||
Swal.fire({
|
||||
title: "No es tu contraseña actual!",
|
||||
icon: "error",
|
||||
draggable: true,
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -85,4 +95,3 @@ export default function ChangePassword() {
|
||||
</section>
|
||||
);
|
||||
}
|
||||
//IO
|
||||
@@ -1,12 +1,13 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { loginUser } from "@/app/lib/login";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
import toast from "react-hot-toast";
|
||||
import Swal from "sweetalert2";
|
||||
import "./Login.css";
|
||||
|
||||
function Login() {
|
||||
export default function Login() {
|
||||
const [user, setUser] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
|
||||
@@ -16,30 +17,46 @@ function Login() {
|
||||
e.preventDefault();
|
||||
|
||||
if (!user) {
|
||||
toast.error("Coloca un usuario");
|
||||
|
||||
Swal.fire({
|
||||
title: "Coloca un usuario!",
|
||||
icon: "error",
|
||||
draggable: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!password) {
|
||||
toast.error("Coloca una contraseña");
|
||||
|
||||
Swal.fire({
|
||||
title: "Coloca una contraseña!",
|
||||
icon: "error",
|
||||
draggable: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await loginUser(user, password);
|
||||
|
||||
if ("error" in data) {
|
||||
toast.error(data.error);
|
||||
Swal.fire({
|
||||
title: data.error,
|
||||
icon: "error",
|
||||
draggable: true,
|
||||
});
|
||||
} else {
|
||||
const token = data.access_token;
|
||||
const payload = JSON.parse(atob(token.split(".")[1]));
|
||||
const usuario = payload.usuario;
|
||||
const role = payload.role;
|
||||
|
||||
document.cookie = `token=${token}; path=/; SameSite=Strict`;
|
||||
document.cookie = `user=${usuario}; path=/; SameSite=Strict`;
|
||||
document.cookie = `role=${role}; path=/; SameSite=Strict`;
|
||||
|
||||
toast.success("Inicio de sesión exitoso");
|
||||
Swal.fire({
|
||||
title: "Inicio de sesión exitoso!",
|
||||
icon: "success",
|
||||
draggable: true,
|
||||
});
|
||||
router.push("/Impresiones");
|
||||
router.refresh();
|
||||
}
|
||||
@@ -85,6 +102,4 @@ function Login() {
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default Login;
|
||||
//IO
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
background-color: #d12020;
|
||||
}
|
||||
|
||||
.session{
|
||||
.session {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
@@ -19,11 +19,19 @@
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.userName{
|
||||
.userName {
|
||||
background-color: white;
|
||||
border-radius: 6px;
|
||||
padding: 6px 12px;
|
||||
z-index: 1;
|
||||
outline: 1px solid #cfcfcf;
|
||||
}
|
||||
|
||||
@media(max-height: 800px) {
|
||||
.session {
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
@@ -57,16 +65,17 @@
|
||||
transform: translate(0, -50%);
|
||||
}
|
||||
|
||||
.userName{
|
||||
.userName {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 50px;
|
||||
}
|
||||
}
|
||||
@media(max-width:450px){
|
||||
.userName{
|
||||
|
||||
@media(max-width:450px) {
|
||||
.userName {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
right: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
.backgroundContainer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 725px;
|
||||
height: 615px;
|
||||
z-index: -1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.bgImage {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
transition: opacity 2s ease-in-out;
|
||||
opacity: 1;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.bgImage.fade {
|
||||
z-index: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.bgImage.fade.active {
|
||||
opacity: 1;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.bgImage::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(to right, #f9f9f9, rgba(128, 128, 128, 0));
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
|
||||
.backgroundContainer {
|
||||
background-image: url("/rock.jpg");
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
width: 600px;
|
||||
height: 650px;
|
||||
right: 50%;
|
||||
transform: translateX(50%);
|
||||
}
|
||||
|
||||
.bgImage {
|
||||
display: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.backgroundContainer::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(to right, #f9f9f9, rgba(128, 128, 128, 0));
|
||||
}
|
||||
|
||||
.backgroundContainer::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(to left, #f9f9f9, rgba(128, 128, 128, 0));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import "./Background.css";
|
||||
|
||||
const images = [
|
||||
"/rock2.jpg",
|
||||
"/CEDETEC.jpg",
|
||||
"/FES-ACATLAN.jpg",
|
||||
"/DSC.jpeg",
|
||||
];
|
||||
|
||||
export default function BackgroundRotator() {
|
||||
const [current, setCurrent] = useState(0);
|
||||
const [next, setNext] = useState(1);
|
||||
const [isTransitioning, setIsTransitioning] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setIsTransitioning(true);
|
||||
|
||||
setTimeout(() => {
|
||||
setCurrent(next);
|
||||
setNext((next + 1) % images.length);
|
||||
setIsTransitioning(false);
|
||||
}, 2000);
|
||||
}, 20000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [next]);
|
||||
|
||||
return (
|
||||
<div className="backgroundContainer">
|
||||
<div
|
||||
className="bgImage"
|
||||
style={{ backgroundImage: `url(${images[current]})` }}
|
||||
/>
|
||||
|
||||
<div
|
||||
className={`bgImage fade ${isTransitioning ? "active" : ""}`}
|
||||
style={{ backgroundImage: `url(${images[next]})` }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -24,7 +24,7 @@
|
||||
transition:
|
||||
background-color 0.3s ease,
|
||||
border 0.3s ease;
|
||||
font-size: 1.5rem;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.barNavigation li:hover {
|
||||
@@ -107,12 +107,12 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #545454;
|
||||
font-size: 1.5rem;
|
||||
font-size: 1.4rem;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.subMenu:hover > span,
|
||||
.subMenu > a:hover > span {
|
||||
.subMenu:hover>span,
|
||||
.subMenu>a:hover>span {
|
||||
color: black;
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
color: white;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 1.5rem;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
thead,
|
||||
@@ -137,6 +137,12 @@ tbody {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
@media(max-height:550px) {
|
||||
.barNavigation {
|
||||
max-height: 35px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1001px) {
|
||||
.subMenu:hover ul {
|
||||
opacity: 1;
|
||||
@@ -158,7 +164,7 @@ tbody {
|
||||
}
|
||||
|
||||
.barNavigation {
|
||||
font-size: 15px;
|
||||
font-size: 1.4rem;
|
||||
justify-content: end;
|
||||
}
|
||||
|
||||
@@ -166,6 +172,7 @@ tbody {
|
||||
position: absolute;
|
||||
top: 76px;
|
||||
left: 0;
|
||||
top: 100%;
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
flex-direction: column;
|
||||
@@ -235,13 +242,13 @@ tbody {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.subMenu.open ul a{
|
||||
.subMenu.open ul a {
|
||||
display: flex;
|
||||
pointer-events:auto;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
thead,
|
||||
tbody {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,7 +123,7 @@ export default function BarNavigation() {
|
||||
>
|
||||
<li>Activos y en Mantenimiento</li>
|
||||
</Link>
|
||||
<Link
|
||||
{/* <Link
|
||||
href="/Mensajes"
|
||||
className="links"
|
||||
onClick={(e) => {
|
||||
@@ -132,7 +132,7 @@ export default function BarNavigation() {
|
||||
}}
|
||||
>
|
||||
<li>Mensajes</li>
|
||||
</Link>
|
||||
</Link> */}
|
||||
<Link
|
||||
href="/Programas"
|
||||
className="links"
|
||||
|
||||
@@ -100,7 +100,7 @@ export default function BarNavigationServicio() {
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li className="subMenu" onClick={toggleMenu}>
|
||||
{/* <li className="subMenu" onClick={toggleMenu}>
|
||||
<Link
|
||||
href="/Mensajes"
|
||||
className="links"
|
||||
@@ -111,7 +111,21 @@ export default function BarNavigationServicio() {
|
||||
>
|
||||
<span>Mensajes</span>
|
||||
</Link>
|
||||
</li> */}
|
||||
|
||||
<li className="subMenu" onClick={toggleMenu}>
|
||||
<Link
|
||||
href="/ActivosMantenimiento"
|
||||
className="links"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
closeAllMenus();
|
||||
}}
|
||||
>
|
||||
<span>Activos y en Mantenimiento</span>
|
||||
</Link>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
);
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
.link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 10px 5px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
@@ -86,15 +92,50 @@
|
||||
max-height: 60%;
|
||||
}
|
||||
|
||||
@media (max-height: 550px) {
|
||||
.containerBarNav {
|
||||
max-height: 70%;
|
||||
}
|
||||
|
||||
.yellowPart {
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
.logoContainer {
|
||||
min-width: 150px;
|
||||
aspect-ratio: 250/70;
|
||||
}
|
||||
|
||||
.link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 5px 2px;
|
||||
}
|
||||
|
||||
.header::after {
|
||||
left: -60px;
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
.header::before {
|
||||
left: -40px;
|
||||
width: 10%;
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
.yellowPart {
|
||||
left: 0;
|
||||
background: #bd8c01;
|
||||
transform: skew(0deg);
|
||||
}
|
||||
|
||||
.header::after {
|
||||
left: -100px;
|
||||
}
|
||||
|
||||
.header::before {
|
||||
left: -80px;
|
||||
}
|
||||
@@ -105,11 +146,13 @@
|
||||
min-width: 100%;
|
||||
transform: skew(25deg);
|
||||
}
|
||||
|
||||
.header::before {
|
||||
min-width: 100%;
|
||||
transform: skew(25deg);
|
||||
}
|
||||
|
||||
.containerBarNav {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,33 @@
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import BarNavigation from "../BarNavigation/BarNavigation";
|
||||
import header from "./Header.module.css";
|
||||
import { cookies } from "next/headers";
|
||||
import BarNavigationServicio from "../BarNavigation/BarNavigationServicio";
|
||||
import { jwtVerify } from "jose";
|
||||
import HeaderNavigation from "./HeaderNavigation";
|
||||
|
||||
const secret = new TextEncoder().encode(process.env.JWT_SECRET);
|
||||
|
||||
export default async function Header() {
|
||||
const cookieStore = await cookies();
|
||||
const role = cookieStore.get("role")?.value || "";
|
||||
const cookieStore = cookies();
|
||||
const token = (await cookieStore).get("token")?.value;
|
||||
|
||||
let role: number = 5;
|
||||
|
||||
if (token) {
|
||||
try {
|
||||
const { payload } = await jwtVerify(token, secret);
|
||||
role = payload.role as number;
|
||||
} catch (error) {
|
||||
role = 5;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<header className={header.header}>
|
||||
<Link
|
||||
href="https://www.unam.mx/"
|
||||
target="_blank"
|
||||
className={header.center}
|
||||
style={{ display: "flex", alignItems: "center", margin: "10px 5px" }}
|
||||
className={`${header.center} ${header.link}`}
|
||||
>
|
||||
<div className={header.logoContainer}>
|
||||
<Image
|
||||
@@ -29,11 +41,7 @@ export default async function Header() {
|
||||
</Link>
|
||||
<div className={header.yellowPart}></div>
|
||||
<div className={header.containerBarNav}>
|
||||
{role === "ADMINIS.TRADOR" && <BarNavigation />}
|
||||
{role === "SUPER ADMINISTRADOR (quita sanciones)" && <BarNavigation />}
|
||||
{role === "ADMINISTRADOR" && <BarNavigation/>}
|
||||
{role === "ATENCION A USUARIO" && <BarNavigation/>}
|
||||
{role === "SERVICIO SOCIAL" && <BarNavigationServicio/>}
|
||||
<HeaderNavigation role={role} />
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
"use client";
|
||||
|
||||
import { usePathname } from "next/navigation";
|
||||
import BarNavigation from "../BarNavigation/BarNavigation";
|
||||
import BarNavigationServicio from "../BarNavigation/BarNavigationServicio";
|
||||
|
||||
export default function HeaderNavigation({ role }: { role: number }) {
|
||||
const pathname = usePathname();
|
||||
|
||||
if (pathname === "/") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{role === 1 && <BarNavigation />}
|
||||
{role === 4 && <BarNavigation />}
|
||||
{role === 2 && <BarNavigationServicio />}
|
||||
{role === 3 && <BarNavigationServicio />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { Toaster } from "react-hot-toast";
|
||||
import React from "react";
|
||||
|
||||
export function ToastProvider({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
{children}
|
||||
<Toaster
|
||||
toastOptions={{
|
||||
style: {
|
||||
padding: "16px",
|
||||
fontSize: "16px",
|
||||
maxWidth: "400px",
|
||||
},
|
||||
|
||||
error: {
|
||||
duration: 6000,
|
||||
style: {
|
||||
fontSize: "1.5rem",
|
||||
backgroundColor: "#fee2e2dd",
|
||||
color: "#000000ff",
|
||||
fontWeight: "600",
|
||||
padding: "1.5rem",
|
||||
},
|
||||
},
|
||||
|
||||
success: {
|
||||
duration: 6000,
|
||||
style: {
|
||||
fontSize: "1.5rem",
|
||||
backgroundColor: "#d1fae5dd",
|
||||
color: "#000000ff",
|
||||
fontWeight: "600",
|
||||
padding: "1.5rem",
|
||||
},
|
||||
},
|
||||
}}
|
||||
position="top-left"
|
||||
reverseOrder={false}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import Image from "next/image";
|
||||
import "./creadores.css";
|
||||
|
||||
interface props{
|
||||
title:string;
|
||||
img:string;
|
||||
width:number;
|
||||
height:number;
|
||||
}
|
||||
|
||||
export default function CreatorCard({title,img,width,height}:props) {
|
||||
return (
|
||||
<div className="card">
|
||||
<div className="imageWrapper">
|
||||
<Image
|
||||
src={img}
|
||||
alt="IO"
|
||||
width={width}
|
||||
height={height}
|
||||
className="creators"
|
||||
/>
|
||||
</div>
|
||||
<h1 className="titles">{title}</h1>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
.imageWrapper {
|
||||
position: relative;
|
||||
animation: slideIn 1s ease-out forwards;
|
||||
transform: translateX(-120px) rotate(12deg);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
animation: slideIn 1s ease-out forwards;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.card:hover .creators {
|
||||
transform: rotateY(360deg) rotate(12deg) scale(1.05);
|
||||
box-shadow: 0 30px 60px rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
|
||||
.creators {
|
||||
object-fit: cover;
|
||||
border-radius: 16px;
|
||||
background-color: rgba(255, 255, 255, 0.6);
|
||||
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.25);
|
||||
transition: transform 1s ease, box-shadow 0.4s ease;
|
||||
}
|
||||
|
||||
.imageWrapper:hover .creators {
|
||||
transform: rotateY(180deg) rotate(24deg) scale(1.05);
|
||||
box-shadow: 0 30px 60px rgba(0, 0, 0, 0.35);
|
||||
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
to {
|
||||
transform: translateX(0) rotate(12deg);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.titles {
|
||||
margin-left: 40px;
|
||||
font-size: 3rem;
|
||||
font-weight: 600;
|
||||
opacity: 0;
|
||||
animation: fadeIn 1s ease forwards;
|
||||
animation-delay: 0.5s;
|
||||
color: #1E3A8A;
|
||||
}
|
||||
|
||||
.card:hover .title {
|
||||
transform: translateY(-5px);
|
||||
color: #163172;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import BackgroundRotator from "../Components/layout/BackgroundRotator/BackgroundRotator";
|
||||
import CreatorCard from "./CreatorCard";
|
||||
import "./creadores.css";
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<div className="mainContainer">
|
||||
<div className="container" style={{ display: "flex", flexDirection: "row", justifyContent: "center", gap: "3rem", flexWrap: "wrap" }}>
|
||||
<BackgroundRotator />
|
||||
|
||||
<CreatorCard title="IO" img="/IO.png" width={150} height={200} />
|
||||
<CreatorCard title="CarloSpak" img="/SPAK.png" width={160} height={100} />
|
||||
<CreatorCard title="Tyrannuss" img="/Tyrannuss.png" width={140} height={140} />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user