added new icons and new monitor

This commit is contained in:
2026-01-23 19:34:03 -06:00
parent 42168efe65
commit 09fdf8e98c
13 changed files with 238 additions and 21 deletions
+1 -1
View File
@@ -25,7 +25,7 @@ export default function MachineTable() {
const fetchMachines = async () => {
try {
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/equipo`,
`${process.env.NEXT_PUBLIC_API_URL}/equipo/disable`,
{ cache: "no-store" }
);
const data = await res.json();
@@ -0,0 +1,81 @@
"use client";
import { useEffect, useState } from "react";
import styles from "./Page.module.css";
type Equipo = {
id_equipo: number;
nombre_equipo: string;
ubicacion: string;
activo: {
data: number[];
};
plataforma: {
nombre: string;
};
areaUbicacion: {
area: string;
};
};
export default function MachineTableActive() {
const [machines, setMachines] = useState<Equipo[]>([]);
const [loading, setLoading] = useState(true);
const fetchMachines = async () => {
try {
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/equipo/active`,
{ cache: "no-store" },
);
const data = await res.json();
setMachines(data);
} catch (error) {
console.error("Error al cargar equipos", error);
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchMachines();
}, []);
if (loading) {
return <p>Cargando equipos...</p>;
}
return (
<div className={styles.tableContainer}>
<table className={styles.machineTable}>
<thead>
<tr style={{ fontSize: "15px" }}>
<th>Ubicación</th>
<th>Nombre Equipo</th>
<th>Plataforma</th>
<th>Área</th>
<th>Disponible</th>
</tr>
</thead>
<tbody>
{machines.map((machine) => {
const disponible = machine.activo.data[0] === 1;
return (
<tr key={machine.id_equipo}>
<td>{machine.ubicacion}</td>
<td>{machine.nombre_equipo}</td>
<td className={styles[machine.plataforma.nombre]}>
{machine.plataforma.nombre}
</td>
<td>{machine.areaUbicacion.area}</td>
<td>{disponible ? "Sí" : "No"}</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
+36
View File
@@ -39,3 +39,39 @@
.resetButton:hover {
background-color: #cc0000;
}
.WINDOWS::before {
content: "";
display: inline-block;
width: 20px;
height: 20px;
background-image: url("/windows.png");
background-size: contain;
background-repeat: no-repeat;
margin-right: 6px;
vertical-align: middle;
}
.MACINTOSH::before {
content: "";
display: inline-block;
width: 20px;
height: 20px;
background-image: url("/apple.png");
background-size: contain;
background-repeat: no-repeat;
margin-right: 6px;
vertical-align: middle;
}
.PROFESORES::before {
content: "";
display: inline-block;
width: 20px;
height: 20px;
background-image: url("/teacher.png");
background-size: contain;
background-repeat: no-repeat;
margin-right: 6px;
vertical-align: middle;
}
+30 -7
View File
@@ -1,23 +1,46 @@
import Toggle from "@/app/Components/Global/Toggle/Toggle";
import MachineTable from "./MachineTable";
import styles from "./Page.module.css";
import ToggleTable from "@/app/Components/Global/Toggle/ToggleTable";
import MachineTableActive from "./MachineTableActive";
export default async function Page(props: {
searchParams?: Promise<{ numAcount: string }>;
searchParams?: Promise<{ numAcount: string; key: string }>;
}) {
const params = await props.searchParams;
const numAcount = params?.numAcount ?? null;
const key = params?.key ?? "active";
return (
<section className="containerSection">
<h2 className="title">MONITOR DE MÁQUINAS DISPONIBLES</h2>
<h2 className="title">MONITOR DE MÁQUINAS</h2>
<div className={styles.actions}>
<button className={styles.resetButton}>
Actualizar información
</button>
<button className={styles.resetButton}>Actualizar información</button>
</div>
<MachineTable />
<ToggleTable
defaultView={key}
options={[
{
key: "active",
label: "Disponibles",
content: (
<>
<MachineTableActive />
</>
),
},
{
key: "disable",
label: "No Disponibles",
content: (
<>
<MachineTable />
</>
),
},
]}
/>
</section>
);
}
+5
View File
@@ -8,6 +8,11 @@
color: #ffffff;
}
.buttonInscription{
background-color: #007a5b;
color: white;
}
.buttonSave:not(:disabled):hover {
background-color: #001f5c;
}
+26 -6
View File
@@ -62,9 +62,19 @@ export default function RegisterAlta(props: urlProp) {
e.preventDefault();
try {
await apiClient.post("/alumno", form);
const payload = {
id_cuenta: Number(form.cuenta),
nombre: `${form.apellidoP} ${form.apellidoM} ${form.nombre}`.trim(),
fecha_nacimiento: form.fecha.replaceAll("-", ""),
correo: form.email || undefined,
id_carrera: Number(form.carrera),
genero: form.genero || undefined,
};
await apiClient.post("/student", payload);
setSaved(true);
toast.error("Alumno registrado correctamente");
toast.success("Alumno registrado correctamente");
} catch (error) {
console.error("Error al guardar alumno:", error);
toast.error("Error al guardar alumno");
@@ -73,7 +83,7 @@ export default function RegisterAlta(props: urlProp) {
const handleInscripcion = (e: React.MouseEvent) => {
e.preventDefault();
router.push("/Inscripcion");
router.push(`/Inscripcion?numAcount=${form.cuenta}`);
};
return (
@@ -150,7 +160,12 @@ export default function RegisterAlta(props: urlProp) {
<div className="containerForm">
<label className="label">Género</label>
<select name="genero" value={form.genero} onChange={handleChange} required>
<select
name="genero"
value={form.genero}
onChange={handleChange}
required
>
<option value="">Selecciona género</option>
<option value="Femenino">Femenino</option>
<option value="Masculino">Masculino</option>
@@ -160,7 +175,12 @@ export default function RegisterAlta(props: urlProp) {
<div className="containerForm">
<label className="label">Carrera</label>
<select name="carrera" value={form.carrera} onChange={handleChange} required>
<select
name="carrera"
value={form.carrera}
onChange={handleChange}
required
>
<option value="">Selecciona la carrera</option>
{listMajor.map((c) => (
<option key={c.id_carrera} value={c.id_carrera}>
@@ -180,7 +200,7 @@ export default function RegisterAlta(props: urlProp) {
</button>
<button
className="button"
className="button buttonInscription"
disabled={!saved}
onClick={handleInscripcion}
>
@@ -0,0 +1,53 @@
"use client";
import { usePathname, useSearchParams } from "next/navigation";
import { useRouter } from "next/navigation";
import { useState, ReactNode } from "react";
interface ToggleOption {
key: string;
label: string;
content: ReactNode;
}
interface ToggleProps {
options: ToggleOption[];
defaultView?: string;
}
export default function ToggleTable({ options, defaultView }: ToggleProps) {
const router = useRouter();
const searchParams = useSearchParams();
const pathname = usePathname();
const [view, setView] = useState(defaultView || options[0].key);
const handleClick = (key: string) => {
setView(key);
const params = new URLSearchParams(searchParams.toString());
params.set("key", key);
router.replace(`${pathname}?${params.toString()}`);
};
return (
<section className="toggleSection" style={{maxWidth:"none"}}>
<div className="toggleGroup">
{options.map((opt) => (
<button
key={opt.key}
className={`toggleButton ${view === opt.key ? "active" : ""}`}
onClick={() => handleClick(opt.key)}
>
{opt.label}
</button>
))}
</div>
<div className="padding toggleContent">
{options.find((opt) => opt.key === view)?.content}
</div>
</section>
);
}
//IO
+3 -3
View File
@@ -20,15 +20,15 @@ function Selection({
const options = [
{
name: "WINDOWS",
img: "https://images.icon-icons.com/2235/PNG/512/windows_os_logo_icon_134678.png",
img: "/windows.png",
},
{
name: "MACINTOSH",
img: "https://upload.wikimedia.org/wikipedia/commons/f/fa/Apple_logo_black.svg",
img: "apple.png",
},
{
name: "PROFESORES",
img: "https://cdn-icons-png.flaticon.com/512/3135/3135715.png",
img: "teacher.png",
},
];
+3 -4
View File
@@ -15,19 +15,18 @@ function SelectionCo({
const options = [
{
name: "WINDOWS",
img: "https://images.icon-icons.com/2235/PNG/512/windows_os_logo_icon_134678.png",
img: "/windows.png",
},
{
name: "MACINTOSH",
img: "https://upload.wikimedia.org/wikipedia/commons/f/fa/Apple_logo_black.svg",
img: "apple.png",
},
{
name: "PROFESORES",
img: "https://cdn-icons-png.flaticon.com/512/3135/3135715.png",
img: "teacher.png",
},
];
// ✅ SOLO las inscritas
const opcionesInscritas = options.filter((option) =>
plataformasInscritas.includes(option.name),
);
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB