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