Merge branch 'Lino' of https://github.com/IO420/Nexus into Carlos

This commit is contained in:
2025-10-10 10:50:07 -06:00
73 changed files with 1286 additions and 876 deletions
+8 -28
View File
@@ -1,52 +1,32 @@
import Areas from "@/app/Components/ActivosMantenimiento/Areas";
import Mesas from "@/app/Components/ActivosMantenimiento/Mesas";
import Equipos from "@/app/Components/Equipos/equipos";
import AlertBox from "@/app/Components/Global/AlertBox/AlertBox";
import ClearParams from "@/app/Components/Global/ClearParams/ClearParams";
import SearchUser from "@/app/Components/Global/SearchUser/searchUser";
import MesasDisponibles from "@/app/Components/ActivosMantenimiento/MesasDisponibles";
import TableEquipos from "@/app/Components/Equipos/tableequipos";
import Toggle from "@/app/Components/Global/Toggle/Toggle";
export default async function Page(props: {
searchParams?: Promise<{
key?: string;
numAcount?: string;
machine?: string;
success?: string;
error?: string;
}>;
}) {
const params = await props.searchParams;
const key = params?.key && params.key;
const numAcount = params?.numAcount ? params.numAcount : null;
const showSuccess = params?.success ? params.success : null;
const showError = params?.error ? params.error : null;
return (
<section className="containerSection">
{showError && (
<>
<AlertBox key={Date.now()} message={showError} type="error" />
<ClearParams paramsToClear={["error"]} />
</>
)}
{showSuccess && (
<>
<AlertBox key={Date.now()} message={showSuccess} type="success" />
<ClearParams paramsToClear={["success"]} />
</>
)}
<h2 className="title">EQUIPOS ACTIVOS Y EN MANTENIMIENTO</h2>
<Toggle
defaultView="Equipos"
defaultView={key}
options={[
{
key: "Equipos",
label: "Equipos",
content: (
<>
<SearchUser value={numAcount} />
<Equipos />
<TableEquipos />
</>
),
},
@@ -61,10 +41,10 @@ export default async function Page(props: {
},
{
key: "Mesas",
label: "Liberar mesa",
label: "Mesas",
content: (
<>
<Mesas />
<MesasDisponibles />
</>
),
},
+10 -10
View File
@@ -1,11 +1,11 @@
.addTime {
position: relative;
max-width: 600px;
margin-top: 1rem;
border: 1px solid #e5e7eb;
border-radius: 4px;
background-color: #f9fafb;
padding: 1rem;
display: flex;
flex-direction: column;
}
position: relative;
max-width: 600px;
margin-top: 1rem;
border-radius: 4px;
background-color: #fff;
padding: 1rem;
display: flex;
flex-direction: column;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
+5 -24
View File
@@ -1,31 +1,27 @@
import SearchUser from "@/app/Components/Global/SearchUser/searchUser";
import Information from "@/app/Components/Global/Information/information";
import Receipt from "@/app/Components/Receipt/Receipt";
import AlertBox from "@/app/Components/Global/AlertBox/AlertBox";
import toast from "react-hot-toast";
import { GetStudent } from "@/app/lib/getStudent";
import "./addTime.css";
import ClearParams from "@/app/Components/Global/ClearParams/ClearParams";
export default async function Page(props: {
searchParams?: Promise<{
numAcount: string;
success?: string;
error?: string;
}>;
}) {
const params = await props.searchParams;
const numAcount = params?.numAcount ? params.numAcount : null;
const showSuccess = params?.success ? params.success : null;
let showError = params?.error ? params.error : null;
let student: any = null;
if (numAcount) {
const result = await GetStudent(parseInt(numAcount));
if (result.error) {
showError = "Alumno no encontrado";
toast.error("Alumno no encontrado");
return;
} else {
student = result;
}
@@ -33,34 +29,19 @@ export default async function Page(props: {
return (
<section className="containerSection">
{showError && (
<>
<AlertBox key={Date.now()} message={showError} type="error" />
<ClearParams paramsToClear={["error"]} />
</>
)}
{showSuccess && (
<>
<AlertBox message="Recibo guardado correctamente" type="success" />
<ClearParams paramsToClear={["success"]} />
</>
)}
<h2 className="title"> AGREGAR TIEMPO </h2>
<SearchUser value={numAcount} />
{student ? (
{student && (
<>
<Information NoCuenta={student.id_cuenta} Nombre={student.nombre} />
<div className="addTime">
<div className="groupInput" style={{ marginBottom: "1rem" }}></div>
<Receipt numAcount={student.id_cuenta} />
</div>
</>
) : (
<></>
)}
</section>
);
-20
View File
@@ -1,34 +1,14 @@
import AlertBox from "@/app/Components/Global/AlertBox/AlertBox";
import RegisterAlta from "@/app/Components/Alta/registerAlta";
import "./style.css";
import ClearParams from "@/app/Components/Global/ClearParams/ClearParams";
export default async function Page(props: {
searchParams?: Promise<{
success?: string;
error?: string;
}>;
}) {
const params = await props.searchParams;
const showSuccess = params?.success ? params.success : null;
const showError = params?.error ? params.error : null;
return (
<section className="containerSection">
{showError && (
<>
<AlertBox key={Date.now()} message={showError} type="error" />
<ClearParams paramsToClear={["error"]} />
</>
)}
{showSuccess && (
<>
<AlertBox key={Date.now()} message={showSuccess} type="success" />
<ClearParams paramsToClear={["success"]} />
</>
)}
<h1 className="title">ALTA</h1>
+2 -1
View File
@@ -3,7 +3,8 @@
grid-template-columns: 1fr 1fr;
}
.containerAlta {
background-color: #f9f9f9;
background-color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
width: 100%;
max-width: 900px;
padding: 1rem;
+38 -36
View File
@@ -1,60 +1,46 @@
import AlertBox from "@/app/Components/Global/AlertBox/AlertBox";
import ClearParams from "@/app/Components/Global/ClearParams/ClearParams";
import SearchUser from "@/app/Components/Global/SearchUser/searchUser";
import Toggle from "@/app/Components/Global/Toggle/Toggle";
import { GetStudent } from "@/app/lib/getStudent";
import "@/app/globals.css";
import SearchBoxEquipo from "@/app/Components/SearchEquipo";
import CheckBox from "@/app/Components/CheckBox";
import CheckBoxEquipo from "@/app/Components/CheckBoxEquipo";
import Information from "@/app/Components/Global/Information/information";
import ShowError from "@/app/Components/Global/ShowError";
import "@/app/globals.css";
export default async function Page(props: {
searchParams?: Promise<{
key?:string
numAcount?: string;
machine?: string;
success?: string;
error?: string;
}>;
}) {
const params = await props.searchParams;
const key = params?.key && params.key;
const numAcount = params?.numAcount ? params.numAcount : null;
const machine = params?.machine ? params.machine : null;
const showSuccess = params?.success ? params.success : null;
const showError = params?.error ? params.error : null;
let student: any = null;
let errorMessage = "";
if (numAcount) {
const result = await GetStudent(parseInt(numAcount));
if (result.error) {
errorMessage = `${result.error}`;
} else {
student = result;
student = result as Student;
}
}
return (
<section className="containerSection">
{showError && (
<>
<AlertBox key={Date.now()} message={showError} type="error" />
<ClearParams paramsToClear={["error"]} />
</>
)}
{showSuccess && (
<>
<AlertBox key={Date.now()} message={showSuccess} type="success" />
<ClearParams paramsToClear={["success"]} />
</>
)}
{errorMessage && <ShowError key={Date.now()} message={errorMessage} />}
<h2 className="title"> ASIGNACION DE EQUIPOS </h2>
<Toggle
defaultView="Asignar"
defaultView={key}
options={[
{
key: "Asignar",
@@ -63,18 +49,34 @@ export default async function Page(props: {
<>
<SearchUser value={numAcount} />
<Information
numerocuenta={"12345"}
nombre={"Carlos"}
inscrito={"WINDOWS"}
tiempo={"9minutos"}
confirmo={"si/no"}
/>
<label>Seleccionar tiempo</label>
<select name="" id=""></select>
<label>Seleccione un equipo</label>
<select name="" id=""></select>
<button className="button buttonSearch">Asignar Equipo</button>
{student && (
<>
<Information
numerocuenta={student.id_cuenta}
nombre={student.nombre}
/>
<Information
inscrito={"WINDOWS"}
tiempo={"9minutos"}
confirmo={"si/no"}
/>
{/* <div className="containerForm">
<label style={{ marginTop: "1rem" }}>
Seleccionar tiempo
</label>
<select></select>
<label style={{ marginTop: "1rem" }}>
Seleccione un equipo
</label>
<div className="groupInput">
<select></select>
<button className="button buttonSearch">
Asignar Equipo
</button>
</div>
</div> */}
</>
)}
</>
),
},
+51 -12
View File
@@ -2,35 +2,74 @@ import AsignacionMesas from "@/app/Components/AsignacionMesas";
import CheckBox from "@/app/Components/CheckBox";
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 { GetStudent } from "@/app/lib/getStudent";
export default async function Page(props: {
searchParams?: Promise<{
key: string;
numAcount: string;
}>;
}) {
const params = await props.searchParams;
const key = params?.key && params.key;
const numAcount = params?.numAcount ? params.numAcount : null;
let student: any = null;
let errorMessage = "";
if (numAcount) {
const result = await GetStudent(parseInt(numAcount));
if (result.error) {
errorMessage = `${result.error}`;
} else {
student = result as Student;
}
}
export default function Page() {
return (
<section className="containerSection">
{errorMessage && <ShowError key={Date.now()} message={errorMessage} />}
<h2 className="title"> ASIGNACION DE MESAS </h2>
<Toggle
defaultView="Asignar"
defaultView={key}
options={[
{
key: "Asignar",
label: "Asignar mesa",
content: (
<>
<SearchUser value={"3"} />
<AsignacionMesas />
<Information cuenta={"12345"} nombre={"Alberto"} />
<label>Tiempo</label>
<select name="" id="">
<option value="1">Seleciona el tiempo </option>{" "}
</select>
<button className="button buttonSearch">Asignar</button>
<SearchUser value={numAcount} />
{student && (
<>
<Information
cuenta={student.id_cuenta}
nombre={student.nombre}
/>
{/* <div
className="containerForm"
style={{ margin: "1rem 0" }}
>
<label>Tiempo</label>
<div className="groupInput">
<select name="" id="">
<option value="1">Seleciona el tiempo </option>{" "}
</select>
<button className="button buttonSearch">Asignar</button>
</div>
</div> */}
<AsignacionMesas />
</>
)}
</>
),
},
{
key: "Liberar",
label: "Liberar mesa",
key: "Tiempo",
label: "Cancelar Tiempo",
content: (
<>
<CheckBox />
+2 -19
View File
@@ -2,24 +2,19 @@ import BitacoraAlumno from "@/app/Components/BitacoraSanciones/BitacoraAlumno";
import BitacoraEquipo from "@/app/Components/BitacoraSanciones/BitacoraEquipo";
import BitacoraMesas from "@/app/Components/BitacoraSanciones/BitacoraMesas";
import Sanciones from "@/app/Components/BitacoraSanciones/Sanciones";
import SearchUser from "@/app/Components/Global/SearchUser/searchUser";
import Toggle from "@/app/Components/Global/Toggle/Toggle";
import AlertBox from "@/app/Components/Global/AlertBox/AlertBox";
import { GetStudent } from "@/app/lib/getStudent";
import ClearParams from "@/app/Components/Global/ClearParams/ClearParams";
export default async function Page(props: {
searchParams?: Promise<{
key?: string;
numAcount?: string;
success?: string;
error?: string;
}>;
}) {
const params = await props.searchParams;
const key = params?.key && params.key ;
const numAcount = params?.numAcount ? params.numAcount : null;
const showSuccess = params?.success ? params.success : null;
const showError = params?.error ? params.error : null;
let student: any = null;
@@ -34,19 +29,6 @@ export default async function Page(props: {
return (
<section className="containerSection">
{showError && (
<>
<AlertBox key={Date.now()} message={showError} type="error" />
<ClearParams paramsToClear={["error"]} />
</>
)}
{showSuccess && (
<>
<AlertBox key={Date.now()} message={showSuccess} type="success" />
<ClearParams paramsToClear={["success"]} />
</>
)}
<h2 className="title"> BITACORA Y SANCIONES </h2>
@@ -67,6 +49,7 @@ export default async function Page(props: {
label: "Bitacora alumno",
content: (
<>
<SearchUser value={numAcount}/>
<BitacoraAlumno />
</>
),
-19
View File
@@ -1,32 +1,13 @@
import ChangePassword from "@/app/Components/auth/ChangePassword/changePassword";
import AlertBox from "@/app/Components/Global/AlertBox/AlertBox";
import ClearParams from "@/app/Components/Global/ClearParams/ClearParams";
export default async function Page(props: {
searchParams?: Promise<{
success?: string;
error?: string;
}>;
}) {
const params = await props.searchParams;
const showSuccess = params?.success ? params.success : null;
const showError = params?.error ? params.error : null;
return (
<section className="containerSection">
{showError && (
<>
<AlertBox key={Date.now()} message={showError} type="error" />
<ClearParams paramsToClear={["error"]} />
</>
)}
{showSuccess && (
<>
<AlertBox key={Date.now()} message={showSuccess} type="success" />
<ClearParams paramsToClear={["success"]} />
</>
)}
<h2 className="title"> Cambiar contraseña </h2>
+6 -19
View File
@@ -2,53 +2,40 @@ import SearchUser from "../../Components/Global/SearchUser/searchUser";
import Receipt from "../../Components/Receipt/Receipt";
import Toggle from "../../Components/Global/Toggle/Toggle";
import Information from "../../Components/Global/Information/information";
import AlertBox from "@/app/Components/Global/AlertBox/AlertBox";
import Impressions from "@/app/Components/Impressions/impressions";
import ShowError from "@/app/Components/Global/ShowError";
import { GetStudent } from "@/app/lib/getStudent";
import "@/app/globals.css";
import ClearParams from "@/app/Components/Global/ClearParams/ClearParams";
export default async function Page(props: {
searchParams?: Promise<{
key: string;
numAcount: string;
success?: string;
error?: string;
}>;
}) {
const params = await props.searchParams;
const key = params?.key && params.key;
const numAcount = params?.numAcount ? params.numAcount : null;
const showSuccess = params?.success ? params.success : null;
const showError = params?.error ? params.error : null;
let student: any = null;
let errorMessage = "";
if (numAcount) {
const result = await GetStudent(parseInt(numAcount));
if (result.error) {
errorMessage = `${result.error}`;
} else {
student = result;
student = result as Student;
}
}
return (
<section className="containerSection">
{showError && (
<>
<AlertBox key={Date.now()} message={showError} type="error" />
<ClearParams paramsToClear={["error"]} />
</>
)}
{showSuccess && (
<>
<AlertBox key={Date.now()} message={showSuccess} type="success" />
<ClearParams paramsToClear={["success"]} />
</>
)}
{errorMessage && <ShowError key={Date.now()} message={errorMessage} />}
<h2 className="title">IMPRESIONES Y PLOTEO</h2>
<SearchUser value={numAcount} />
-19
View File
@@ -1,40 +1,21 @@
import Toggle from "@/app/Components/Global/Toggle/Toggle";
import Equipos from "@/app/Components/Equipos/equipos";
import AlertBox from "@/app/Components/Global/AlertBox/AlertBox";
import ProgramSelector from "@/app/Components/InformacionEquipos/ProgramSelector";
import "./informacionequipo.css";
import ClearParams from "@/app/Components/Global/ClearParams/ClearParams";
export default async function Page(props: {
searchParams?: Promise<{
key?: string;
machine?: string;
success?: string;
error?: string;
}>;
}) {
const params = await props.searchParams;
const key = params?.key && params.key;
const machine = params?.machine ? params.machine : null;
const showSuccess = params?.success ? params.success : null;
const showError = params?.error ? params.error : null;
return (
<section className="containerSection">
{showError && (
<>
<AlertBox key={Date.now()} message={showError} type="error" />
<ClearParams paramsToClear={["error"]} />
</>
)}
{showSuccess && (
<>
<AlertBox key={Date.now()} message={showSuccess} type="success" />
<ClearParams paramsToClear={["success"]} />
</>
)}
<h2 className="title"> INFORMACION DE EQUIPOS </h2>
+37 -9
View File
@@ -1,9 +1,37 @@
.inscripcion{
background-color: #f9f9f9;
width: 100%;
max-width: 700px;
border-radius: 4px;
padding: 1rem;
margin-top: 1rem;
outline: 1px solid #cfcfcf;
}
.inscripcion {
position: relative;
top: 0;
background-color: #ffffff;
width: 100%;
max-width: 700px;
border-radius: 4px;
padding: 1rem;
margin-top: 1rem;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.containeInformation {
display: flex;
gap: 10px;
width: 100%;
}
.firstPartInformation {
display: flex;
flex-direction: column;
width: 100%;
max-width: 450px;
}
@media (max-width: 800px) {
.containeInformation {
justify-content: center;
align-items: center;
}
}
@media (max-width: 800px) {
.containeInformation {
flex-direction: column;
}
}
+52 -27
View File
@@ -2,65 +2,90 @@ import SearchUser from "@/app/Components/Global/SearchUser/searchUser";
import Information from "@/app/Components/Global/Information/information";
import Receipt from "@/app/Components/Receipt/Receipt";
import Selection from "@/app/Components/Selection/Selection";
import AlertBox from "@/app/Components/Global/AlertBox/AlertBox";
import ClearParams from "@/app/Components/Global/ClearParams/ClearParams";
import ShowError from "@/app/Components/Global/ShowError";
import { GetStudent } from "@/app/lib/getStudent";
import "./inscripcion.css";
import Table from "@/app/Components/Global/table";
export default async function Page(props: {
searchParams?: Promise<{
numAcount: string;
success?: string;
error?: string;
}>;
}) {
const params = await props.searchParams;
const numAcount = params?.numAcount ? params.numAcount : null;
const showSuccess = params?.success ? params.success : null;
let showError = params?.error ? params.error : null;
let student: any = null;
let errorMessage = "";
if (numAcount) {
const result = await GetStudent(parseInt(numAcount));
if (result.error) {
showError = "Alumno no encontrado";
errorMessage = `${result.error}`;
} else {
student = result;
}
}
const headers = ["Inscrito", "Tiempo", "Confirmó"];
const data = [
{
Inscrito: "WINDOWS",
Tiempo: "9 minutos",
Confirmó: "si",
},
{
Inscrito: "WINDOWS",
Tiempo: "9 minutos",
Confirmó: "si/no",
},
{
Inscrito: "WINDOWS",
Tiempo: "9 minutos",
Confirmó: "si/no",
},
];
return (
<section className="containerSection">
{showError && (
<>
<AlertBox key={Date.now()} message={showError} type="error" />
<ClearParams paramsToClear={["error"]} />
</>
)}
{errorMessage && <ShowError key={Date.now()} message={errorMessage} />}
{showSuccess && (
<>
<AlertBox key={Date.now()} message={showSuccess} type="success" />
<ClearParams paramsToClear={["success"]} />
</>
)}
<h2 className="title"> INSCRIPCIÓN </h2>
<h2 className="title"> INSCRIPCION </h2>
<div className="containeInformation">
<div className="firstPartInformation">
<SearchUser value={numAcount} />
<SearchUser value={numAcount} />
{student && (
<Information
NoCuenta={student.id_cuenta}
Nombre={student.nombre}
Carrera={student.carrera.carrera}
Credito={student.credito}
/>
)}
</div>
{student && <Table headers={headers} data={data} />}
</div>
{student && (
<>
<Information
NoCuenta={student.id_cuenta}
Nombre={student.nombre}
Carrera={student.carrera.carrera}
Credito={student.credito}
/>
<section className="inscripcion">
<Selection />
<select
style={{
marginBottom: "1rem",
maxWidth: "100px",
minWidth: "100px",
}}
>
<option value="0">con pago</option>
<option value="1">sin pago</option>
</select>
<Receipt numAcount={student.id_cuenta} />
</section>
</>
+26 -21
View File
@@ -1,33 +1,15 @@
import AlertBox from "@/app/Components/Global/AlertBox/AlertBox";
import ClearParams from "@/app/Components/Global/ClearParams/ClearParams";
export default async function Page(props: {
searchParams?: Promise<{
period: string;
success?: string;
error?: string;
}>;
}) {
const params = await props.searchParams;
const period = params?.period ? params.period : null;
const showSuccess = params?.success ? params.success : null;
const showError = params?.error ? params.error : null;
return (
<section className="containerSection">
{showError && (
<>
<AlertBox key={Date.now()} message={showError} type="error" />
<ClearParams paramsToClear={["error"]} />
</>
)}
{showSuccess && (
<>
<AlertBox key={Date.now()} message={showSuccess} type="success" />
<ClearParams paramsToClear={["success"]} />
</>
)}
<h2 className="title"> INSCRITOS </h2>
<form className="containerForm">
@@ -53,15 +35,38 @@ export default async function Page(props: {
<thead>
<tr>
<th>Carrera</th>
<th>Windows</th>
<th>Macintosh</th>
<th>Linux</th>
<th>Genero</th>
<th>Profesores</th>
<th>Total</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<div className="tableContainer" style={{ marginTop: "100px" }}>
<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>
</tbody>
</table>
</div>
</section>
);
}
+2 -19
View File
@@ -1,35 +1,16 @@
import EnviarMensaje from "@/app/Components/EviarMensaje/EnviarMensaje";
import AlertBox from "@/app/Components/Global/AlertBox/AlertBox";
import ClearParams from "@/app/Components/Global/ClearParams/ClearParams";
import Toggle from "@/app/Components/Global/Toggle/Toggle";
export default async function Page(props: {
searchParams?: Promise<{
key:string;
success?: string;
error?: string;
}>;
}) {
const params = await props.searchParams;
const key = params?.key && params.key ;
const showSuccess = params?.success ? params.success : null;
const showError = params?.error ? params.error : null;
return (
<section className="containerSection">
{showError && (
<>
<AlertBox key={Date.now()} message={showError} type="error" />
<ClearParams paramsToClear={["error"]} />
</>
)}
{showSuccess && (
<>
<AlertBox key={Date.now()} message={showSuccess} type="success" />
<ClearParams paramsToClear={["success"]} />
</>
)}
<h2 className="title">Enviar mensaje</h2>
@@ -41,6 +22,7 @@ export default async function Page(props: {
label: "Equipo",
content: (
<EnviarMensaje
key={1}
titulo="Seleccione un equipo"
opciones={["1", "2", "3", "4", "5", "6"]}
/>
@@ -51,6 +33,7 @@ export default async function Page(props: {
label: "Sala",
content: (
<EnviarMensaje
key={2}
titulo="Seleccione una sala"
opciones={["PECERA", "PCNET1", "PCNET2", "PCNET3"]}
/>
+25 -54
View File
@@ -1,70 +1,41 @@
.tableContainer {
overflow-y: auto;
overflow-x: auto;
border-radius: 4px;
border: 1px solid #cfcfcf;
max-height: 430px;
scrollbar-color: rgb(1, 92, 184) rgba(0, 0, 0, 0);
background-color: #f9f9f9;
width: 100%;
}
.machineTable {
width: 100%;
border-collapse: collapse;
table-layout: auto;
}
.machineTable th,
.machineTable td {
padding: 10px;
text-align: center;
border-bottom: 1px solid #cfcfcf;
word-wrap: break-word;
overflow-wrap: break-word;
}
.machineTable th {
position: sticky;
top: 0px;
background-color: rgb(1, 92, 184);
color: white;
}
.machineTable tr {
min-width: 400px;
overflow-y: auto;
overflow-x: auto;
border-radius: 4px;
max-height: 430px;
scrollbar-color: rgb(1, 92, 184) rgba(0, 0, 0, 0);
width: 100%;
}
.disponible {
display: flex;
width: 100%;
height: 100%;
background-color: green;
color: green;
font-weight: bold;
display: flex;
width: 100%;
height: 100%;
background-color: green;
color: green;
font-weight: bold;
}
.ocupado {
color: red;
font-weight: bold;
color: red;
font-weight: bold;
}
.actions {
text-align: center;
text-align: center;
}
.resetButton {
padding: 8px 16px;
background-color: #ff4d4d;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-weight: bold;
transition: 0.3s;
padding: 8px 16px;
background-color: #ff4d4d;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-weight: bold;
transition: 0.3s;
}
.resetButton:hover {
background-color: #cc0000;
}
background-color: #cc0000;
}
+32 -11
View File
@@ -3,35 +3,56 @@ import styles from "./Page.module.css";
export default async function Page(props: {
searchParams?: Promise<{
numAcount: string;
success?: string;
error?: string;
}>;
}) {
const params = await props.searchParams;
const numAcount = params?.numAcount ? params.numAcount : null;
const showSuccess = params?.success ? params.success : null;
const showError = params?.error ? params.error : null;
return (
<section className='containerSection'>
<h2 className='title'> MONITOR DE MÁQUINAS DISPONIBLES </h2>
<section className="containerSection">
<h2 className="title"> MONITOR DE MÁQUINAS DISPONIBLES </h2>
<div className={styles.actions}>
<button className={styles.resetButton}>
Actualizar informacion
</button>
<button className={styles.resetButton}>Actualizar informacion</button>
</div>
<div className={styles.tableContainer}>
<table className={styles.machineTable}>
<thead>
<tr>
<tr style={{fontSize:"15px"}}>
<th>Ubicación</th>
<th>Nombre Equipo</th>
<th>Plataforma</th>
<th>Área</th>
<th>Disponible</th>
</tr>
<tr>
<th>
<select style={{ minWidth: "50px" }}>
<option style={{ minWidth: "50px" }}>pcnet1</option>
</select>
</th>
<th>
<select style={{ minWidth: "50px" }}>
<option style={{ minWidth: "50px" }}>mostrar todos</option>
</select>
</th>
<th>
<select style={{ minWidth: "50px" }}>
<option style={{ minWidth: "50px" }}>windows</option>
</select>
</th>
<th>
<select style={{ minWidth: "50px" }}>
<option style={{ minWidth: "50px" }}>mostrar Todo</option>
</select>
</th>
<th>
<select style={{ minWidth: "50px" }}>
<option style={{ minWidth: "50px" }}>si</option>
</select>
</th>
</tr>
</thead>
<tbody>
{/* {machines.map((machine, index) => (
@@ -51,4 +72,4 @@ export default async function Page(props: {
</section>
);
}
//IO
//IO
+2 -2
View File
@@ -18,7 +18,7 @@ export default function Page() {
};
return (
<>
<section className="containerSection">
{modo === "ver" && (
<section className="containersection">
<h3 className="title">PROGRAMAS</h3>
@@ -86,6 +86,6 @@ export default function Page() {
</div>
</section>
)}
</>
</section>
);
}
+6 -9
View File
@@ -4,22 +4,19 @@ import QuitarSancion from "@/app/Components/QuitarSancion/QuitarSancion";
export default async function Page(props: {
searchParams?: Promise<{
numAcount: string;
success?: string;
error?: string;
}>;
}) {
const params = await props.searchParams;
const numAcount = params?.numAcount ? params.numAcount : null;
const showSuccess = params?.success ? params.success : null;
const showError = params?.error ? params.error : null;
return (
<>
<h2 className="title"> Quitar Sanciones </h2>
<div style={{ display: "flex", gap: "1rem", flexDirection: "column" }}>
<SearchUser value={numAcount} />
<QuitarSancion />
</div>
<h2 className="title"> Quitar Sanciones </h2>
<div className="containerSection"
>
<SearchUser value={numAcount} />
<QuitarSancion />
</div>
</>
);
}
+15 -67
View File
@@ -1,94 +1,42 @@
"use client";
import styles from "./Page.module.css";
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 { useState } from "react";
export default function Page() {
const [reportes] = useState([
{
Servicio: "Plotter",
Total: "$1440.00",
},
]);
const [recibos] = useState([
{
folio_recibo: "100255",
monto: "40.00",
fecha_recibo: "10/10/2025",
fecha_registro: "10/10/2025 05:32:20 pm",
usuario: "modulo1",
},
]);
export default async function Page(props: {
searchParams?: Promise<{
key: string;
numAcount: string;
}>;
}) {
const params = await props.searchParams;
const key = params?.key && params.key;
return (
<section className="containerSection">
<h2 className="title"> REPORTES </h2>
<Toggle
defaultView="1"
defaultView={key}
options={[
{
key: "1",
key: "Por recibo",
label: "Por recibo",
content: (
<>
<SearchDateBetween />
<div className={styles.tableContainer}>
<table className={styles.machineTable}>
<thead>
<tr>
<th>Folio Recibo</th>
<th>Monto</th>
<th>Fecha Recibo</th>
<th>Fecha Registro</th>
<th>Usuario</th>
</tr>
</thead>
<tbody>
{recibos.map((recibo, index) => (
<tr key={index}>
<td>{recibo.folio_recibo}</td>
<td>{recibo.monto}</td>
<td>{recibo.fecha_recibo}</td>
<td>{recibo.fecha_registro}</td>
<td>{recibo.usuario}</td>
</tr>
))}
</tbody>
</table>
</div>
<PorServicios />
</>
),
},
{
key: "2",
key: "Por Servicio",
label: "Por Servicio",
content: (
<>
<SearchDateBetween />
<div className={styles.tableContainer}>
<table className={styles.machineTable}>
<thead>
<tr>
<th>Servicio</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{reportes.map((reporte, index) => (
<tr key={index}>
<td>{reporte.Servicio}</td>
<td>{reporte.Total}</td>
</tr>
))}
</tbody>
</table>
</div>
<PorRecibos />
</>
),
},
+11 -7
View File
@@ -1,13 +1,15 @@
"use client";
import { useState } from "react";
import "@/app/globals.css"
export default function Areas() {
const [area, setArea] = useState(""); // Área seleccionada
const [activo, setActivo] = useState(false); // Checkbox Activo
const [mantenimiento, setMantenimiento] = useState(false); // Checkbox Mantenimiento
const [mensaje, setMensaje] = useState(""); // Mensaje dinámico
const handleActualizar = (e: React.FormEvent) => {
const handleActualizar = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!area) {
@@ -35,11 +37,10 @@ export default function Areas() {
return (
<form className="containerForm" onSubmit={handleActualizar}>
<label className="label">Áreas disponibles:</label>
<label className="label">Áreas</label>
<div className="groupInput">
{/* Select de áreas */}
<select value={area} onChange={(e) => setArea(e.target.value)}>
<option value="">-- Áreas disponibles --</option>
<option value="">-- Áreas --</option>
<option value="PECERA">PECERA</option>
<option value="JAULA">JAULA</option>
<option value="HUACAL">HUACAL</option>
@@ -48,13 +49,15 @@ export default function Areas() {
</select>
{/* Checkboxes */}
<div className="checkbox-grid">
<div className="checkbox" style={{ marginTop: "10px" }}>
<label style={{ marginRight: "10px" }}>
<label style={{ marginRight: "10px"}}>
<input
type="checkbox"
checked={activo}
onChange={(e) => setActivo(e.target.checked)}
/>
/>
Activo
</label>
<label>
@@ -62,10 +65,11 @@ export default function Areas() {
type="checkbox"
checked={mantenimiento}
onChange={(e) => setMantenimiento(e.target.checked)}
/>
/>
Mantenimiento
</label>
</div>
</div>
{/* Botón Actualizar */}
<button
@@ -6,7 +6,7 @@ function Equipos() {
const [tiempo, setTiempo] = useState("");
const [mensaje, setMensaje] = useState("");
const handleBuscar = (e: React.FormEvent) => {
const handleBuscar = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!cuenta) {
setMensaje("Ingresa un número de cuenta antes de buscar");
@@ -15,7 +15,7 @@ function Equipos() {
setMensaje(`Buscando información del No. de cuenta: ${cuenta}`);
};
const handleAsignar = (e: React.FormEvent) => {
const handleAsignar = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!tiempo) {
setMensaje("Selecciona un equipo antes de asignar");
@@ -1,12 +1,14 @@
"use client";
import { useState } from "react";
import "@/app/globals.css"
function Mesas() {
const [mesa, setMesa] = useState(""); // Mesa seleccionada
const [mantenimiento, setMantenimiento] = useState(false); // Checkbox Mantenimiento
const [mensaje, setMensaje] = useState(""); // Mensaje dinámico
const handleConfirmar = (e: React.FormEvent) => {
const handleConfirmar = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!mesa) {
@@ -26,7 +28,7 @@ function Mesas() {
return (
<form className="containerForm" onSubmit={handleConfirmar}>
<label className="label">Mesas disponibles:</label>
<div className="groupInput">
<div className="groupInput" style={{display:"flex", flexDirection:"column"}}>
{/* Select de mesas */}
<select value={mesa} onChange={(e) => setMesa(e.target.value)}>
<option value="">-- Mesas disponibles --</option>
@@ -0,0 +1,33 @@
import styles from "./Page.module.css";
export default async function MesasDisponibles() {
return (
<section className="containerSection">
<div className={styles.tableContainer}>
<table className={styles.machineTable}>
<thead>
<tr style={{fontSize:"15px"}}>
<th>Mesa</th>
<th>Activo</th>
</tr>
</thead>
<tbody>
{/* {machines.map((machine, index) => (
<tr key={index}>
<td>{machine.ubicacion}</td>
<td>{machine.nombre}</td>
<td>{machine.plataforma}</td>
<td>{machine.area}</td>
<td className={machine.disponible ? "disponible" : ""}>
{machine.disponible ? "si" : "no"}
</td>
</tr>
))} */}
</tbody>
</table>
</div>
</section>
);
}
//IO
@@ -0,0 +1,70 @@
.tableContainer {
overflow-y: auto;
overflow-x: auto;
border-radius: 4px;
border: 1px solid #cfcfcf;
max-height: 430px;
scrollbar-color: rgb(1, 92, 184) rgba(0, 0, 0, 0);
background-color: #f9f9f9;
width: 100%;
}
.machineTable {
width: 100%;
border-collapse: collapse;
table-layout: auto;
}
.machineTable th,
.machineTable td {
padding: 10px;
text-align: center;
border-bottom: 1px solid #cfcfcf;
word-wrap: break-word;
overflow-wrap: break-word;
}
.machineTable th {
position: sticky;
top: 0px;
background-color: rgb(1, 92, 184);
color: white;
}
.machineTable tr {
min-width: 400px;
}
.disponible {
display: flex;
width: 100%;
height: 100%;
background-color: green;
color: green;
font-weight: bold;
}
.ocupado {
color: red;
font-weight: bold;
}
.actions {
text-align: center;
}
.resetButton {
padding: 8px 16px;
background-color: #ff4d4d;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-weight: bold;
transition: 0.3s;
}
.resetButton:hover {
background-color: #cc0000;
}
+27 -1
View File
@@ -1,8 +1,29 @@
"use client";
import { useState } from "react";
import apiClient from "@/app/lib/apiClient";
import { useEffect, useState } from "react";
export default function RegisterAlta() {
const [listMajor, setListMajor] = useState([]);
const [major, setMajor] = useState("");
useEffect(() => {
const fetchCarreras = async () => {
try {
const response = await apiClient.get("/carrera");
const sortedCarreras = response.data.sort((a: any, b: any) =>
a.carrera.localeCompare(b.carrera)
);
setListMajor(sortedCarreras);
} catch (error) {
console.error("Error al obtener carreras:", error);
}
};
fetchCarreras();
}, []);
return (
<form className="containerAlta gap gridAlta">
<div className="containerForm">
@@ -59,6 +80,11 @@ export default function RegisterAlta() {
<label className="label">Carrera</label>
<select value={major} onChange={(e) => setMajor(e.target.value)}>
<option value="">Selecciona la carrera</option>
{listMajor.map((carrera: any, index) => (
<option key={index} value={carrera.id_carrera}>
{carrera.carrera}
</option>
))}
</select>
</div>
@@ -15,7 +15,7 @@ function BitacoraAlumno() {
return (
<>
<SearchDate />
<div className={styles.tableContainer}>
<div className={styles.tableContainer} style={{marginTop:"1rem"}}>
<table className={styles.machineTable}>
<thead>
<tr>
@@ -33,7 +33,7 @@ function BitacoraEquipo() {
</button>
</div>
</form>
<div className={styles.tableContainer}>
<div className={styles.tableContainer} style={{marginTop:"1rem"}}>
<table className={styles.machineTable}>
<thead>
<tr>
@@ -18,7 +18,7 @@ function BitacoraMesas() {
return (
<>
<SearchDate />
<div className={styles.tableContainer}>
<div className={styles.tableContainer} style={{marginTop:"1rem"}}>
<table className={styles.machineTable}>
<thead>
<tr>
@@ -20,7 +20,7 @@ export default async function Sanciones(props: { student?: Student }) {
Nombre={props.student.nombre}
/>
<TableSancion />
<TableSancion />
</>
)}
</>
@@ -27,30 +27,28 @@ export default function TableSancion() {
const [sanciones, setSanciones] = useState<any>();
const [button, setButton] = useState<boolean>(false);
useEffect(() => {
const getSanciones = async () => {
const response = await axios.get(
""
);
setSanciones(response);
};
getSanciones();
}, [button]);
// useEffect(() => {
// const getSanciones = async () => {
// const response = await axios.get("");
// setSanciones(response);
// };
// getSanciones();
// }, [button]);
const handlebutton = () => {
setButton(!button);
};
return (
<>
<h1>{sanciones}</h1>
<div className={styles.tableContainer}>
<div className={styles.tableContainer} style={{margin:"1rem 0"}}>
<table className={styles.machineTable}>
<thead>
<tr>
<th>Cuenta</th>
<th>Motivo de la sancion</th>
<th>Motivo de la sanción</th>
<th>Duracion (Semanas) </th>
<th>Fecha Sancion</th>
<th>Fecha Sanción</th>
<th>Podra utilizar el servicio hasta</th>
</tr>
</thead>
@@ -61,15 +59,14 @@ export default function TableSancion() {
<form className="containerForm">
<div className="groupInput">
<select>
<option value="">-- Selecciona una sancion --</option>
<option value="">-- Selecciona una sanción --</option>
<option value="sancion 1">No cerrar sesion (Una semana)</option>
</select>
</div>
</form>
<button className="button buttonSearch" onClick={handlebutton}>
Aplicar sancion
</button>
<h1>{button ? <p>desactivado</p> : <p>activado</p>}</h1>
<button className="button buttonSearch" style={{margin:"1rem 0"}} onClick={handlebutton}>
Aplicar sanción
</button>
</>
);
}
+70
View File
@@ -0,0 +1,70 @@
.tableContainer {
overflow-y: auto;
overflow-x: auto;
border-radius: 4px;
border: 1px solid #cfcfcf;
max-height: 430px;
scrollbar-color: rgb(1, 92, 184) rgba(0, 0, 0, 0);
background-color: #f9f9f9;
width: 100%;
}
.machineTable {
width: 100%;
border-collapse: collapse;
table-layout: auto;
}
.machineTable th,
.machineTable td {
padding: 10px;
text-align: center;
border-bottom: 1px solid #cfcfcf;
word-wrap: break-word;
overflow-wrap: break-word;
}
.machineTable th {
position: sticky;
top: 0px;
background-color: rgb(1, 92, 184);
color: white;
}
.machineTable tr {
min-width: 400px;
}
.disponible {
display: flex;
width: 100%;
height: 100%;
background-color: green;
color: green;
font-weight: bold;
}
.ocupado {
color: red;
font-weight: bold;
}
.actions {
text-align: center;
}
.resetButton {
padding: 8px 16px;
background-color: #ff4d4d;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-weight: bold;
transition: 0.3s;
}
.resetButton:hover {
background-color: #cc0000;
}
+11 -10
View File
@@ -14,16 +14,17 @@ export default function Equipos() {
const [Equipo, setEquipo] = useState("");
const [Data, setData] = useState<Data | any>();
const handleSubmit = async () => {
const response = await axios.get(
`${envConfig.apiUrl}/InformacionEquipo/${Equipo}`
);
const handleSubmit = async (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
// const response = await axios.get(
// `${envConfig.apiUrl}/equipo/${Equipo}`
// );
if (!response) {
return;
}
// if (!response) {
// return;
// }
setData(response);
setData("response");
};
return (
@@ -37,7 +38,7 @@ export default function Equipos() {
}}
/>
<button className="button buttonSearch" onClick={handleSubmit}>
<button type="button" className="button buttonSearch" onClick={handleSubmit}>
Buscar
</button>
</div>
@@ -73,7 +74,7 @@ export default function Equipos() {
<option value="4">mmmmm</option>
<option value="5">mmmmm</option>
</select>
<div className="containerButton">
<div className="containerButton" style={{marginTop:"1rem"}}>
<button className="button buttonSearch">Nuevo</button>
<button className="button buttonSearch">Editar</button>
</div>
+63
View File
@@ -0,0 +1,63 @@
import styles from "./Page.module.css";
export default async function TableEquipos() {
return (
<section className="containerSection">
<div className={styles.tableContainer}>
<table className={styles.machineTable}>
<thead>
<tr style={{fontSize:"15px"}}>
<th>Ubicación</th>
<th>Nombre</th>
<th>Plataforma</th>
<th>Área</th>
<th>Activo</th>
</tr>
<tr>
<th>
<select style={{ minWidth: "50px" }}>
<option style={{ minWidth: "50px" }}>pcnet1</option>
</select>
</th>
<th>
<select style={{ minWidth: "50px" }}>
<option style={{ minWidth: "50px" }}>mostrar todos</option>
</select>
</th>
<th>
<select style={{ minWidth: "50px" }}>
<option style={{ minWidth: "50px" }}>windows</option>
</select>
</th>
<th>
<select style={{ minWidth: "50px" }}>
<option style={{ minWidth: "50px" }}>mostrar Todo</option>
</select>
</th>
<th>
<select style={{ minWidth: "50px" }}>
<option style={{ minWidth: "50px" }}>si</option>
</select>
</th>
</tr>
</thead>
<tbody>
{/* {machines.map((machine, index) => (
<tr key={index}>
<td>{machine.ubicacion}</td>
<td>{machine.nombre}</td>
<td>{machine.plataforma}</td>
<td>{machine.area}</td>
<td className={machine.disponible ? "disponible" : ""}>
{machine.disponible ? "si" : "no"}
</td>
</tr>
))} */}
</tbody>
</table>
</div>
</section>
);
}
//IO
@@ -12,7 +12,7 @@ const EnviarMensaje = ({ titulo, opciones }: EnviarMensajeProps) => {
const [mensaje, setMensaje] = useState("");
const [customMsg, setCustomMsg] = useState("");
const handleSubmit = (e: React.FormEvent) => {
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
// Aquí puedes manejar el envío (guardar en estado global, enviar a backend, etc.)
};
@@ -51,6 +51,7 @@ const EnviarMensaje = ({ titulo, opciones }: EnviarMensajeProps) => {
</option>
))}
</select>
<input type="checkbox" style={{minWidth:"20px", width:"20px",maxWidth:"30px"}}/>
</div>
{/* Mensaje personalizado */}
@@ -62,10 +63,12 @@ const EnviarMensaje = ({ titulo, opciones }: EnviarMensajeProps) => {
onChange={(e) => setCustomMsg(e.target.value)}
placeholder="Escribe tu mensaje..."
/>
<input type="checkbox" style={{minWidth:"20px", width:"20px",maxWidth:"30px"}}/>
</div>
{/* Botón de enviar */}
<button className="button buttonSearch" type="submit">
<button className="button buttonSearch" type="submit" style={{marginTop:"1rem"}}>
Mandar mensaje
</button>
</form>
@@ -1,57 +0,0 @@
@keyframes slideInLeft {
0% {
opacity: 0;
transform: translateX(-100%);
}
100% {
opacity: 0.9;
transform: translateX(0);
}
}
@keyframes slideOutRight {
0% {
opacity: 0.9;
transform: translateX(0);
}
100% {
opacity: 0;
transform: translateX(100%);
}
}
.messageBox {
display: flex;
position: absolute;
padding: 0.5rem 1.25rem;
border-radius: 0 4px 4px 0;
font-weight: bold;
font-size: 2rem;
text-align: center;
z-index: 100;
top: 0;
left: 0;
max-width: 500px;
max-height: min-content;
opacity: 0;
}
.messageBox:not(.hidden) {
animation: slideInLeft 0.5s ease forwards;
}
.messageBox.hidden {
animation: slideOutRight 0.5s ease forwards;
}
.success {
background-color: #d1f7c4;
color: #000000;
border: 1px solid #a5d6a7;
}
.error {
background-color: #ffcdd2;
color: #000000;
border: 1px solid #ef9a9a;
}
@@ -1,42 +0,0 @@
"use client";
import { useEffect, useState } from "react";
import "./AlertBox.css";
import ClearParams from "../ClearParams/ClearParams";
interface AlertBoxProps {
message: string | null;
type: "error" | "success";
duration?: number;
}
export default function AlertBox({
message,
type,
duration = 6000,
}: AlertBoxProps) {
const [visible, setVisible] = useState(false);
const [text, setText] = useState("");
useEffect(() => {
if (message) {
setText(message);
setVisible(true);
const timeout = setTimeout(() => {
setVisible(false);
setTimeout(() => setText(""), 500);
}, duration);
return () => clearTimeout(timeout);
}
}, [message, duration]);
if (!text) return null;
return (
<div className={`messageBox ${type} ${!visible ? "hidden" : ""}`}>
{text}
</div>
);
}
@@ -1,28 +0,0 @@
"use client";
import { useEffect } from "react";
interface ClearParamsProps {
paramsToClear: string[];
}
export default function ClearParams({ paramsToClear }: ClearParamsProps) {
useEffect(() => {
if (typeof window === "undefined") return;
const url = new URL(window.location.href);
let changed = false;
paramsToClear.forEach((param) => {
if (url.searchParams.has(param)) {
url.searchParams.delete(param);
changed = true;
}
});
if (changed) {
window.history.replaceState({}, "", url.toString());
}
}, [paramsToClear]);
return null;
}
-40
View File
@@ -1,40 +0,0 @@
"use client";
import { ReactNode, useCallback } from "react";
import { useRouter, usePathname, useSearchParams } from "next/navigation";
interface FormHandlerProps {
children: ReactNode;
onSubmit: () => Promise<void>;
}
export default function FormHandler({ children, onSubmit }: FormHandlerProps) {
const router = useRouter();
const searchParams = useSearchParams();
const pathname = usePathname();
const updateParams = useCallback(
(updates: Record<string, string | null>) => {
const params = new URLSearchParams(searchParams.toString());
Object.entries(updates).forEach(([key, value]) => {
if (value === null) params.delete(key);
else params.set(key, value);
});
router.push(`${pathname}?${params.toString()}`);
},
[searchParams, router, pathname]
);
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
try {
await onSubmit();
} catch (err: any) {
updateParams({ error: String(err) });
}
};
return <form onSubmit={handleSubmit}>{children}</form>;
}
@@ -1,25 +1,25 @@
'use client';
interface InformationProps {
[key: string]: string | number | undefined;
}
export default function Information(props: InformationProps) {
// Obtenemos las entradas (key + value) y filtramos los que sean undefined
const entries = Object.entries(props).filter(([_, value]) => value !== undefined);
const entries = Object.entries(props).filter(
([_, value]) => value !== undefined
);
if (entries.length === 0) return null; // no mostrar nada si no hay datos
if (entries.length === 0) return null;
return (
<div className="information">
<ul>
<ul className="informationList">
{entries.map(([key, value]) => (
<li key={key}>
<b>{key}: </b>{value}
<li key={key} className="informationItem">
<span className="informationKey">{key}</span>
<span className="informationValue">{value}</span>
</li>
))}
</ul>
</div>
);
}
//IO
//IO
@@ -19,11 +19,10 @@ function SearchUser(props: urlProp) {
}
}, [props.value]);
const handleSubmit = (e: React.FormEvent) => {
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const params = new URLSearchParams(searchParams.toString());
if (numAcount) {
params.delete("error");
params.set("numAcount", `${numAcount}`);
router.push(`${pathname}?${params.toString()}`);
}
@@ -57,3 +56,4 @@ function SearchUser(props: urlProp) {
}
export default SearchUser;
//IO
+14
View File
@@ -0,0 +1,14 @@
"use client";
import { useEffect } from "react";
import toast from "react-hot-toast";
export default function ShowError({ message }: { message: string }) {
useEffect(() => {
if (message) {
toast.error(message);
}
}, [message]);
return null;
}
@@ -1,50 +1,49 @@
'use client'
"use client";
import { useState, ReactNode } from "react";
import "./StepNavigator.css"
import "./StepNavigator.css";
interface StepNavigatorProps {
totalSteps: number;
children: ReactNode[];
onFinish?: () => void;
totalSteps: number;
children: ReactNode[];
onFinish?: () => void;
}
export default function StepNavigator({ totalSteps, children, onFinish }: StepNavigatorProps) {
const [step, setStep] = useState(1);
export default function StepNavigator({
totalSteps,
children,
onFinish,
}: StepNavigatorProps) {
const [step, setStep] = useState(1);
const handleNext = (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
if (step < totalSteps) setStep(step + 1);
else if (onFinish) onFinish();
};
const handleNext = (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
if (step < totalSteps) setStep(step + 1);
else if (onFinish) onFinish();
};
const handlePrev = (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
if (step > 1) setStep(step - 1);
};
const handlePrev = (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
if (step > 1) setStep(step - 1);
};
return (
<section className="stepNavigator">
{children[step - 1]}
return (
<section className="stepNavigator">
{children[step - 1]}
<div className="absoluteButton">
{step > 1 && (
<button
onClick={handlePrev}
className="button buttonSearch">
Atrás
</button>
)}
<div className="absoluteButton">
{step > 1 && (
<button onClick={handlePrev} className="button buttonSearch">
Atrás
</button>
)}
{step < totalSteps &&
<button
onClick={handleNext}
className="button buttonSearch"
>
Siguiente
</button>
}
</div>
</section>
);
{step < totalSteps && (
<button onClick={handleNext} className="button buttonSearch">
Siguiente
</button>
)}
</div>
</section>
);
}
+31
View File
@@ -0,0 +1,31 @@
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>
</>
);
}
+8
View File
@@ -0,0 +1,8 @@
.tableContainer {
width: 100%;
max-width: 450px;
overflow-x: hidden;
scrollbar-color: #2563eb #ffffff00;
scroll-behavior: smooth;
transition: all 0.3s ease;
}
+40
View File
@@ -0,0 +1,40 @@
"use client";
import React from "react";
import styles from "./table.module.css";
interface TableProps {
headers: string[];
data: Array<Record<string, any>>;
}
export default function Table({ headers, data }: TableProps) {
return (
<div className={styles.tableContainer}>
<table>
<thead>
<tr>
{headers.map((header, index) => (
<th key={index}>{header}</th>
))}
</tr>
</thead>
<tbody>
{data.length > 0 ? (
data.map((row, rowIndex) => (
<tr key={rowIndex}>
{headers.map((header, colIndex) => (
<td key={colIndex}>{row[header]}</td>
))}
</tr>
))
) : (
<tr>
<td colSpan={headers.length}>No hay registros</td>
</tr>
)}
</tbody>
</table>
</div>
);
}
@@ -1,36 +0,0 @@
"use client";
import { useEffect, useState } from "react";
import AlertBox from "@/app/Components/Global/AlertBox/AlertBox";
import ClearParams from "@/app/Components/Global/ClearParams/ClearParams";
import { useSearchParams } from "next/navigation";
export default function GlobalAlert() {
const searchParams = useSearchParams();
const [showSuccess, setShowSuccess] = useState<string | null>(null);
const [showError, setShowError] = useState<string | null>(null);
useEffect(() => {
const success = searchParams.get("success");
const error = searchParams.get("error");
if (success) setShowSuccess(success);
if (error) setShowError(error);
}, []);
return (
<section className="containerAlerts">
{showError && (
<>
<AlertBox key={Date.now()} message={showError} type="error" />
</>
)}
{showSuccess && (
<>
<AlertBox key={Date.now()} message={showSuccess} type="success" />
</>
)}
</section>
);
}
+11 -15
View File
@@ -4,6 +4,7 @@ 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";
interface CostOption {
value: number;
@@ -27,24 +28,19 @@ function Impressions({ costs, numAcount }: ImpressionsProps) {
};
const handlePayment = async () => {
const currentUrl = new URL(window.location.href);
const params = new URLSearchParams();
const setError = (msg: string) => {
params.set("error", msg);
router.push(`${currentUrl}&${params.toString()}`);
};
if (!numAcount) {
return setError("busca de nuevo al estudiante");
toast.error("busca de nuevo al estudiante");
return;
}
if (!pages) {
return setError("Ingresa el numero de hojas a imprimir");
toast.error("Ingresa el numero de hojas a imprimir");
return;
}
if (!cost) {
return setError("Selecciona un costo");
toast.error("Selecciona un costo");
return;
}
const result = await PostImpressions({
@@ -56,16 +52,16 @@ function Impressions({ costs, numAcount }: ImpressionsProps) {
if (result.error) {
if (result.error === "Token inválido") handleLogout();
else {
return setError(`Error: ${result.error}`);
toast.error(result.error);
return;
}
return;
}
setPages("");
setCost("");
params.delete("error");
params.set("success", "Impresion cobrada correctamente");
router.push(`${currentUrl}&${params.toString()}`);
toast.success("Impresion cobrada correctamente");
router.refresh();
};
return (
@@ -1,5 +1,6 @@
"use client";
import { useState } from "react";
import SelectAreas from "../SelectAreas";
interface DatosEquipo {
titulo: string;
@@ -43,7 +44,7 @@ const caracteristicasPorEquipo: Record<string, string[]> = {
// Agrega más equipos según necesites
};
function ProgramSelector({ titulo, opcion }: DatosEquipo) {
export default function ProgramSelector({ titulo, opcion }: DatosEquipo) {
// Estado del equipo seleccionado
const [equipoSeleccionado, setEquipoSeleccionado] = useState("");
// Estado de los checkboxes (programas)
@@ -108,5 +109,3 @@ function ProgramSelector({ titulo, opcion }: DatosEquipo) {
</form>
);
}
export default ProgramSelector;
@@ -6,7 +6,6 @@
max-height: 430px;
scrollbar-color: rgb(1, 92, 184) rgba(0, 0, 0, 0);
background-color: #f9f9f9;
width: 65%;
}
.machineTable {
@@ -16,15 +16,15 @@ function QuitarSancion() {
const [quitarSanciones, SetQuitarSanciones] = useState<quitarSanciones[]>([]);
return (
<section className="containerSection">
<div className={styles.tableContainer}>
<div className={styles.tableContainer} style={{margin:"1rem 0"}}>
<table className={styles.machineTable}>
<thead>
<tr>
<th>id</th>
<th>Nombre</th>
<th>Motivo Sancion</th>
<th>Motivo Sanción</th>
<th>Duracion (semanas) </th>
<th>Fecha Sancion</th>
<th>Fecha Sanción</th>
<th>Podria utilizar el servicio hasta</th>
</tr>
</thead>
@@ -42,7 +42,7 @@ function QuitarSancion() {
</tbody>
</table>
</div>
<button className="button buttonSearch">Quitar Sancion</button>
<button className="button buttonSearch" style={{marginTop:"1rem"}}>Quitar Sanción</button>
</section>
);
}
+24
View File
@@ -0,0 +1,24 @@
.groupInformation {
display: flex;
max-width: 500px;
min-width: 40px;
width: 100%;
justify-content: end;
gap: 10px;
}
.informationButton {
text-align: center;
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
border: 1px solid #cfcfcf;
background-color: #fff;
max-width: 40px;
min-width: 40px;
}
.informationButton:hover {
border: 1px solid #cfcfcf;
background-color: #cfcfcf;
}
+13 -20
View File
@@ -1,5 +1,6 @@
"use client";
import toast from "react-hot-toast";
import { useState } from "react";
import { PostReceipt } from "@/app/lib/postReceipt";
import { useRouter } from "next/navigation";
@@ -28,28 +29,24 @@ function Receipt({ numAcount }: ReceiptsProps) {
//restrict this month//
const handleSaveReceipt = async () => {
const currentUrl = new URL(window.location.href);
const params = new URLSearchParams();
const setError = (msg: string) => {
params.set("error", msg);
router.push(`${currentUrl}&${params.toString()}`);
};
if (!numAcount) {
return setError("busca de nuevo al estudiante");
toast.error("busca de nuevo al estudiante");
return;
}
if (!folio) {
return setError("Ingresa el folio del ticket");
toast.error("Ingresa el folio del ticket");
return;
}
if (!amount) {
return setError("Coloca el monto a depositar");
toast.error("Coloca el monto a depositar");
return;
}
if (!date) {
return setError("Coloca la fecha");
toast.error("Coloca la fecha");
return;
}
try {
@@ -64,11 +61,10 @@ function Receipt({ numAcount }: ReceiptsProps) {
setAmount("");
setDate("");
params.delete("error");
params.set("success", "Recibo guardado");
router.push(`${currentUrl}&${params.toString()}`);
toast.success("Recibo guardado");
router.refresh();
} catch (err: any) {
setError(String(err));
toast.error(String(err));
}
};
@@ -111,10 +107,7 @@ function Receipt({ numAcount }: ReceiptsProps) {
if (value === "" || numericValue <= 1000) {
setAmount(value);
} else {
const currentUrl = new URL(window.location.href);
const params = new URLSearchParams();
params.set("error", "El monto no puede superar $1000.00");
router.push(`${currentUrl}&${params.toString()}`);
toast.error("El monto no puede superar $1000.00");
}
}
}}
+69
View File
@@ -0,0 +1,69 @@
.tableContainer {
overflow-y: auto;
overflow-x: auto;
border-radius: 4px;
border: 1px solid #cfcfcf;
max-height: 430px;
scrollbar-color: rgb(1, 92, 184) rgba(0, 0, 0, 0);
background-color: #f9f9f9;
width: 100%;
}
.machineTable {
width: 100%;
border-collapse: collapse;
table-layout: auto;
}
.machineTable th,
.machineTable td {
padding: 10px;
text-align: center;
border-bottom: 1px solid #cfcfcf;
word-wrap: break-word;
overflow-wrap: break-word;
}
.machineTable th {
position: sticky;
top: 0px;
background-color: rgb(1, 92, 184);
color: white;
}
.machineTable tr {
min-width: 400px;
}
.disponible {
display: flex;
width: 100%;
height: 100%;
background-color: green;
color: green;
font-weight: bold;
}
.ocupado {
color: red;
font-weight: bold;
}
.actions {
text-align: center;
}
.resetButton {
padding: 8px 16px;
background-color: #ff4d4d;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-weight: bold;
transition: 0.3s;
}
.resetButton:hover {
background-color: #cc0000;
}
+34
View File
@@ -0,0 +1,34 @@
"use client";
import { useState } from "react";
import styles from "./Page.module.css";
interface reportes {
Servicio: "Plotter";
Total: "$1440.00";
}
function PorRecibos() {
const [reportes, SetQuitarSanciones] = useState<reportes[]>([]);
return (
<div className={styles.tableContainer}>
<table className={styles.machineTable}>
<thead>
<tr>
<th>Servicio</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{reportes.map((reporte, index) => (
<tr key={index}>
<td>{reporte.Servicio}</td>
<td>{reporte.Total}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
export default PorRecibos;
+43
View File
@@ -0,0 +1,43 @@
"use client";
import { useState } from "react";
import styles from "./Page.module.css";
interface servicios {
folio_recibo: "100255";
monto: "40.00";
fecha_recibo: "10/10/2025";
fecha_registro: "10/10/2025 05:32:20 pm";
usuario: "modulo1";
}
function PorServicios() {
const [recibos, setRecibos] = useState<servicios[]>([]);
return (
<div className={styles.tableContainer}>
<table className={styles.machineTable}>
<thead>
<tr>
<th>Folio Recibo</th>
<th>Monto</th>
<th>Fecha Recibo</th>
<th>Fecha Registro</th>
<th>Usuario</th>
</tr>
</thead>
<tbody>
{recibos.map((recibo, index) => (
<tr key={index}>
<td>{recibo.folio_recibo}</td>
<td>{recibo.monto}</td>
<td>{recibo.fecha_recibo}</td>
<td>{recibo.fecha_registro}</td>
<td>{recibo.usuario}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
export default PorServicios;
@@ -6,7 +6,7 @@ function SearchDateBetween() {
const [startDate, setStartDate] = useState("");
const [endDate, setEndDate] = useState("");
const handleSubmit = (e: React.FormEvent) => {
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
console.log("Fecha inicio:", startDate);
console.log("Fecha fin:", endDate);
+5 -4
View File
@@ -1,11 +1,12 @@
"use client";
export default function SearchEquipo() {
return (
<form action="">
<form className="containerForm">
<label>Numero de equipo</label>
<input type="text" />
<button className="button buttonSearch">Buscar</button>
<div className="groupInput">
<input type="text" placeholder="Coloca el numero de equipo"/>
<button className="button buttonSearch">Buscar</button>
</div>
</form>
);
}
+5 -6
View File
@@ -1,12 +1,11 @@
export default function SearchTable() {
return (
<form className="containerForm">
{" "}
<label>Numero de Mesa</label>
<div className="groupInput">
<input type="text" placeholder="Coloca el numero de Mesa" />
<button className="buttonSearch button">Buscar</button>
</div>
<label>Numero de Mesa</label>
<div className="groupInput">
<input type="text" placeholder="Coloca el numero de Mesa" />
<button className="buttonSearch button">Buscar</button>
</div>
</form>
);
}
+17 -17
View File
@@ -1,35 +1,35 @@
"use clien";
import React, { useEffect, useState } from "react";
"use client";
import axios from "axios";
import { useEffect, useState } from "react";
export default function SelectAreas() {
const [areas, setAreas] = useState([]); // aquí guardaremos los datos del servidor
const [areas, setAreas] = useState([]);
const [selectedArea, setSelectedArea] = useState("");
// useEffect se ejecuta una vez al montar el componente
useEffect(() => {
fetch("https://venus.acatlan.unam.mx/asignacionTiempo_test/area-ubicacion")
.then((response) => response.json())
axios
.get("https://venus.acatlan.unam.mx/asignacionTiempo_test/area-ubicacion")
.then((data) => {
console.log("Áreas obtenidas:", data);
setAreas(data);
setAreas(data.data);
})
.catch((error) => {
console.error("Error al traer las áreas:", error);
});
}, []);
const handleChange = (e) => {
setSelectedArea(e.target.value);
console.log("Área seleccionada:", e.target.value);
};
return (
<div>
<label htmlFor="areaSelect">Selecciona un área:</label>
<select id="areaSelect" value={selectedArea} onChange={handleChange}>
<option value="">-- Selecciona una opción --</option>
{areas.map((area) => (
<select
id="areaSelect"
value={selectedArea}
onChange={(e) => setSelectedArea(e.target.value)}
>
<option value="">-- Selecciona una opción --</option>
{areas.map((area: any, index) => (
<option key={index} value={area.area}>
{area.area}
</option>
))}
</select>
</div>
-1
View File
@@ -3,7 +3,6 @@
gap: 1rem;
justify-content: center;
align-items: center;
margin: 10px;
flex-wrap: wrap;
}
@@ -1,4 +1,5 @@
"use client";
import apiClient from "@/app/lib/apiClient";
import { useState } from "react";
export default function ChangePassword() {
@@ -6,10 +7,11 @@ export default function ChangePassword() {
const [newPass, setNewPass] = useState("");
const [confirmNewPass, setconfirmNewPass] = useState("");
const handleChangePass = (e: React.FormEvent) => {
const handleChangePass = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault;
const data = { pass, newPass, confirmNewPass };
console.log(data);
await apiClient.post("/user/create", data);
};
return (
+14 -9
View File
@@ -3,33 +3,41 @@ import { useState } from "react";
import { loginUser } from "@/app/lib/login";
import { useRouter } from "next/navigation";
import toast from "react-hot-toast";
import "./Login.css";
import AlertBox from "../../Global/AlertBox/AlertBox";
function Login() {
const [user, setUser] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const [alert, setAlert] = useState("");
const router = useRouter();
const handleLogin = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!user) {
toast.error("Coloca un usuario");
return;
}
if (!password) {
toast.error("Coloca una contraseña");
return;
}
const data = await loginUser(user, password);
if ("error" in data) {
setError(data.error);
toast.error(data.error);
} else {
const token = data.access_token;
const payload = JSON.parse(atob(token.split(".")[1]));
const usuario = payload.usuario;
document.cookie = `token=${token}; path=/; SameSite=Strict`;
document.cookie = `usuario=${usuario}; path=/; SameSite=Strict`;
document.cookie = `user=${usuario}; path=/; SameSite=Strict`;
setAlert("Inicio de sesión exitoso");
toast.success("Inicio de sesión exitoso");
router.push("/Impresiones");
}
};
@@ -70,9 +78,6 @@ function Login() {
>
Iniciar sesión
</button>
{error && <AlertBox message={error} type="error" />}
{alert && <AlertBox message={alert} type="success" />}
</form>
</section>
);
@@ -24,7 +24,7 @@ function BarNavigation() {
<ul className={openMenu ? "active" : ""}>
<li className={`subMenu ${openSubMenu === 0 ? "open" : ""}`}>
<span onClick={() => toggleSubMenu(0)}>Inscripcion</span>
<span onClick={() => toggleSubMenu(0)}>Inscripción</span>
<ul className="containerLinks" onClick={toggleMenu}>
<Link href="/Alta" className="links">
<li>Alta</li>
@@ -33,7 +33,7 @@ function BarNavigation() {
<li>Agregar Tiempo</li>
</Link>
<Link href="/Inscripcion" className="links">
<li>Inscripcion</li>
<li>Inscripción</li>
</Link>
</ul>
</li>
@@ -90,7 +90,7 @@ function BarNavigation() {
</li>
<li className="subMenu" onClick={toggleMenu}>
<Link href="/QuitarSancion" className="links">
<span>Quitar sancion</span>
<span>Quitar sanción</span>
</Link>
</li>
<li className="subMenu" onClick={toggleMenu}>
+45
View File
@@ -0,0 +1,45 @@
"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}
/>
</>
);
}
+127 -53
View File
@@ -23,7 +23,7 @@ body {
display: grid;
grid-template-rows: auto 1fr auto;
min-height: 100dvh;
width: 100dvw;
width: 100vw;
overflow: hidden;
}
@@ -88,11 +88,12 @@ footer p {
.mainContainer {
position: relative;
display: grid;
grid-template-rows: 40px 1fr;
grid-template-rows: auto 1fr;
align-items: center;
justify-items: center;
height: 100%;
width: 100%;
background-color: #f9f9f9;
}
@keyframes fadeInUp {
@@ -172,35 +173,43 @@ select {
border: 1px solid #cfcfcf;
background-color: #fff;
border-radius: 4px;
font-size: 2rem;
font-size: 1.5rem;
color: black;
height: 4rem;
height: 3.5rem;
}
input:focus,
select:focus {
background-color: #f9f9f9;
outline:none;
box-shadow: 0px 0px 8px 2px rgba(0, 62, 121, 0.5);
outline: none;
box-shadow: 0px 0px 8px 2px rgba(0, 62, 121, 0.5);
transition: all 0.2s ease-in-out;
}
input[type="checkbox"]{
select:-webkit-scrollbar {
width: 6px;
}
option {
font-size: 1.5rem;
}
input[type="checkbox"] {
min-width: 3rem;
}
label {
font-size: 2rem;
font-size: 1.5rem;
font-weight: bold;
display: block;
}
button {
font-size: 2rem;
font-size: 1.5rem;
padding: 1rem 1.75rem;
border-radius: 4px;
cursor: pointer;
height: 4rem;
height: 3.5rem;
}
.groupInput {
@@ -209,6 +218,8 @@ button {
gap: 10px;
align-items: center;
justify-content: space-between;
width: 100%;
max-width: 450px;
}
.button {
@@ -277,26 +288,53 @@ a {
.information {
display: flex;
flex-direction: column;
border: 1px solid #e5e7eb;
background-color: #ffffff;
border-radius: 4px;
background-color: #f3f4f6;
width: 100%;
max-width: 450px;
margin-top: 10px;
margin-top: 1rem;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
overflow: hidden;
transition: box-shadow 0.3s ease, transform 0.3s ease;
}
.information ul {
padding: 1rem;
.informationList {
list-style: none;
padding: 0 1rem;
margin: 0;
}
.informationItem {
display: flex;
justify-content: flex-start;
align-items: center;
padding: 5px 0;
border-bottom: 1px solid #e5e5e5;
}
.informationItem:last-child {
border-bottom: none;
}
.informationKey {
font-weight: 600;
text-transform: capitalize;
width: 100px;
}
.informationValue {
color: #555;
font-size: 1.5rem;
}
.title {
top: 0;
left: 0;
width: 100%;
font-size: 3rem;
font-size: 2.5rem;
font-weight: bold;
text-align: start;
color:#bd8c01;
color: #bd8c01;
border-bottom: 1px solid #cfcfcf;
margin-bottom: 10px;
}
@@ -323,9 +361,9 @@ form {
width: 100%;
max-width: 750px;
margin-top: 1rem;
border: 1px solid #e5e7eb;
border-radius: 4px;
background-color: #f9fafb;
background-color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.toggleGroup {
@@ -352,11 +390,11 @@ form {
}
.toggleButton.active {
font-weight: 700;
background-color: #e5e7eb;
font-weight: 600;
background-color: #ffffff;
color: rgb(1, 92, 184);
border-radius: 4px 4px 0 0;
border-bottom: 1px solid rgb(1, 92, 184);
border-bottom: none;
}
p {
@@ -365,28 +403,78 @@ p {
table {
width: 100%;
border-collapse: collapse;
border-collapse: separate;
border-spacing: 0 1rem;
table-layout: auto;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 1.5rem;
color: #333;
}
table th,
table td {
padding: 10px;
text-align: center;
border-bottom: 1px solid #cfcfcf;
word-wrap: break-word;
overflow-wrap: break-word;
padding: 0.85rem 1.5rem;
}
table th {
position: sticky;
top: 0px;
background-color: rgb(1, 92, 184);
color: white;
top: 0;
color: #ffffff;
font-weight: 800;
text-transform: uppercase;
letter-spacing: 1px;
text-align: center;
z-index: 2;
border: none;
}
table td {
text-align: center;
word-wrap: break-word;
overflow-wrap: break-word;
border: none;
}
table tr {
min-width: 400px;
background-color: rgb(255, 255, 255);
transition: background-color 0.2s ease;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
thead tr {
background-color: #2563eb;
position: relative;
z-index: 1;
}
tbody tr {
transition: transform 0.3s ease, opacity 0.3s ease;
opacity: 1;
z-index: 0;
}
tbody tr.hidden {
transform: translateY(-10px);
opacity: 0;
height: 0;
}
table tr:nth-child(even) {
background-color: #f9f9f9;
}
table tr:hover {
background-color: #cfcfcf;
}
table th:first-child,
table td:first-child {
border-radius: 4px 0 0 4px;
}
table th:last-child,
table td:last-child {
border-radius: 0 4px 4px 0;
}
.tableContainer {
@@ -461,26 +549,6 @@ table tr {
justify-content: center;
align-items: center;
}
.img {
width: 100%;
}
.img::after {
background: linear-gradient(to right, #f9f9f993, rgba(128, 128, 128, 0));
}
.img::before {
display: flex;
content: "";
position: absolute;
inset: 0;
background: linear-gradient(to left, #f9f9f993, rgba(128, 128, 128, 0));
}
.title {
text-align: center;
}
}
@media (max-width: 1300px) {
@@ -488,6 +556,11 @@ table tr {
width: 100%;
max-width: none;
}
.containerSection {
overflow: auto;
scrollbar-width: none;
}
}
@media (max-width: 800px) {
@@ -541,6 +614,7 @@ table tr {
.containerSection {
align-items: center;
scrollbar-width: none;
}
.centerGrid {
@@ -563,7 +637,6 @@ table tr {
}
button {
font-size: 1.5rem;
padding: 1rem 1.5rem;
}
@@ -580,6 +653,7 @@ table tr {
@media (max-width: 450px) {
.title {
text-align: center;
max-width: 250px;
overflow-wrap: break-word;
}
+6 -3
View File
@@ -5,6 +5,7 @@ import Header from "./Components/layout/Header/Header";
import Footer from "./Components/layout/Footer/Footer";
import "./globals.css";
import { ToastProvider } from "./Components/layout/ToastProvider";
const poppins = Poppins({
variable: "--font-poppins",
@@ -27,9 +28,11 @@ export default function RootLayout({
return (
<html lang="es">
<body className={poppins.variable} suppressHydrationWarning>
<Header />
<main>{children}</main>
<Footer />
<ToastProvider>
<Header />
<main>{children}</main>
<Footer />
</ToastProvider>
</body>
</html>
);
+42 -7
View File
@@ -2,22 +2,57 @@ import axios from "axios";
import Cookies from "js-cookie";
import { envConfig } from "./config";
if (!envConfig.apiUrl) {
throw new Error("API URL is not defined in envConfig");
}
const apiClient = axios.create({
baseURL: envConfig.apiUrl,
timeout: 10000,
headers: {
"Content-Type": "application/json",
},
});
apiClient.interceptors.request.use((config) => {
const token = Cookies.get("token");
if (token) {
if (config.headers && "set" in config.headers) {
config.headers.set("Authorization", `Bearer ${token}`);
apiClient.interceptors.request.use(
(config) => {
const token = Cookies.get("token");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
return config;
});
);
apiClient.interceptors.response.use(
(response) => response,
(error) => {
if (error.response) {
const status = error.response.status;
if (status === 401) {
Cookies.remove("token");
Cookies.remove("user");
if (
typeof window !== "undefined" &&
!window.location.pathname.includes("/")
) {
window.location.href = "/";
}
}
if (status === 403) {
window.location.href = "/Impresiones";
}
}
return Promise.reject(error);
}
);
export default apiClient;
//IO
//Mike
+2
View File
@@ -6,6 +6,7 @@ export async function GetSanciones(numAcount: number) {
const response = await axios.get(
`${envConfig.apiUrl}/alumno-sancion/${numAcount}`
);
return response.data;
} catch (error: any) {
const msg =
@@ -15,3 +16,4 @@ export async function GetSanciones(numAcount: number) {
return { error: msg };
}
}
//IO
+1 -1
View File
@@ -9,7 +9,7 @@ export async function PostReceipt(data: any) {
error.response?.data?.message ||
error.message ||
"Error desconocido al crear recibo";
return { error: msg };
throw new Error(msg);
}
}
//IO
+10
View File
@@ -0,0 +1,10 @@
interface Carrera {
carrera: string;
}
interface Student {
id_cuenta: number;
nombre: string;
carrera: Carrera;
credito: number;
}
+27 -1
View File
@@ -13,6 +13,7 @@
"next": "^15.5.3",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-hot-toast": "^2.6.0",
"react-icons": "^5.5.0"
},
"devDependencies": {
@@ -748,7 +749,6 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
"dev": true,
"license": "MIT"
},
"node_modules/delayed-stream": {
@@ -911,6 +911,15 @@
"node": ">= 0.4"
}
},
"node_modules/goober": {
"version": "2.1.16",
"resolved": "https://registry.npmjs.org/goober/-/goober-2.1.16.tgz",
"integrity": "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==",
"license": "MIT",
"peerDependencies": {
"csstype": "^3.0.10"
}
},
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
@@ -1139,6 +1148,23 @@
"react": "^19.1.0"
}
},
"node_modules/react-hot-toast": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.6.0.tgz",
"integrity": "sha512-bH+2EBMZ4sdyou/DPrfgIouFpcRLCJ+HoCA32UoAYHn6T3Ur5yfcDCeSr5mwldl6pFOsiocmrXMuoCJ1vV8bWg==",
"license": "MIT",
"dependencies": {
"csstype": "^3.1.3",
"goober": "^2.1.16"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"react": ">=16",
"react-dom": ">=16"
}
},
"node_modules/react-icons": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz",
+2 -1
View File
@@ -5,7 +5,7 @@
"scripts": {
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
@@ -14,6 +14,7 @@
"next": "^15.5.3",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-hot-toast": "^2.6.0",
"react-icons": "^5.5.0"
},
"devDependencies": {