fixed style and added new select whit div and fixed date to mx

This commit is contained in:
2026-02-10 18:42:41 -06:00
parent 733304a622
commit 81eade6a4d
13 changed files with 273 additions and 70 deletions
@@ -160,7 +160,6 @@ export default function PlaticaGate({ inscripcion, numAcount }: Props) {
>
{equipoSeleccionado ? (
<span
className={equipoSeleccionado?.plataforma?.nombre?.toUpperCase()}
>
{equipoSeleccionado.ubicacion}{" "}
{equipoSeleccionado.nombre_equipo}
@@ -3,8 +3,9 @@
border-radius: 6px;
position: relative;
flex: 1;
width: 100%;
width: 100%;
font-size: 14px;
margin-bottom: 1rem;
}
.customSelect.disabled {
+86
View File
@@ -0,0 +1,86 @@
'use client';
type EstadoPC = 'libre' | 'ocupada' | 'fallo';
const colores: Record<EstadoPC, string> = {
libre: '#22c55e', // verde
ocupada: '#ef4444', // rojo
fallo: '#facc15', // amarillo
};
const pcs = [
{
id: 'PC-01',
x: 120,
y: 180,
width: 40,
height: 40,
estado: 'libre' as EstadoPC,
},
{
id: 'PC-02',
x: 170,
y: 180,
width: 40,
height: 40,
estado: 'ocupada' as EstadoPC,
},
{
id: 'PC-03',
x: 220,
y: 180,
width: 40,
height: 40,
estado: 'fallo' as EstadoPC,
},
];
export default function DSC() {
return (
<svg viewBox="0 0 1500 900" width="100%" height="auto">
{/* FONDO */}
<image
href="/plano.svg"
width="100%"
height="100%"
preserveAspectRatio="xMidYMid meet"
pointerEvents="none"
/>
{/* CAPA INTERACTIVA */}
<g>
{pcs.map(pc => (
<g key={pc.id}>
{/* CUADRO */}
<rect
x={pc.x}
y={pc.y}
width={pc.width}
height={pc.height}
fill={colores[pc.estado]}
stroke="#bb4242"
strokeWidth={1}
rx={4}
style={{ cursor: 'pointer' }}
onClick={() => console.log(pc.id)}
/>
{/* NÚMERO */}
<text
x={pc.x + pc.width / 2}
y={pc.y + pc.height / 2 + 5}
textAnchor="middle"
fontSize={12}
fill="#000"
pointerEvents="none"
>
{pc.id.replace('PC-', '')}
</text>
</g>
))}
</g>
</svg>
);
}
+1 -1
View File
@@ -1,8 +1,8 @@
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";
import DSC from "./DSC";
export default async function Page(props: {
searchParams?: Promise<{ numAcount: string; key: string }>;
@@ -29,7 +29,6 @@ function Mesas() {
<form className="containerForm" onSubmit={handleConfirmar}>
<label className="label">Mesas disponibles:</label>
<div className="groupInput" style={{display:"flex", flexDirection:"column"}}>
{/* Select de mesas */}
<select value={mesa} onChange={(e) => setMesa(e.target.value)}>
<option value="">-- Mesas disponibles --</option>
<option value="1">1</option>
@@ -28,13 +28,36 @@ export default function MesasDisponibles() {
}
};
const toggleEquipo = async (id_mesa: number) => {
try {
await fetch(`${envConfig.apiUrl}/mesa/${id_mesa}/activo`, {
method: "PATCH",
});
setMesas((prev) =>
prev
? prev.map((e) =>
e.id_mesa === id_mesa
? {
...e,
activo: e.activo === 1 ? 0 : 1,
}
: e,
)
: prev,
);
} catch (error) {
console.error("Error al cambiar estado del equipo", error);
}
};
return (
<section className="containerSection">
<div
style={{
overflow: "auto",
height: "430px",
width:"100%",
width: "100%",
scrollbarColor: "#2563eb white",
}}
>
@@ -58,7 +81,6 @@ export default function MesasDisponibles() {
<td>Mesa {mesa.id_mesa}</td>
<td
className={isActivo ? "activo" : "inactivo"}
style={{
display: "flex",
alignItems: "center",
@@ -67,12 +89,11 @@ export default function MesasDisponibles() {
}}
>
<span>{isActivo ? "Sí" : "No"}</span>
<input
type="checkbox"
checked={isActivo}
readOnly
style={{ height: "2.5rem", maxWidth:"50px"}}
style={{ height: "2.5rem", maxWidth: "50px" }}
onChange={() => toggleEquipo(mesa.id_mesa)}
/>
</td>
</tr>
+1 -1
View File
@@ -24,7 +24,7 @@ export default function TableEquipos() {
const toggleEquipo = async (id_equipo: number) => {
try {
await fetch(`${envConfig.apiUrl}/equipo/${id_equipo}/activo`, {
await fetch(`${envConfig.apiUrl}/mesa/${id_equipo}/activo`, {
method: "PATCH",
});
+53 -19
View File
@@ -4,6 +4,8 @@ import { useEffect, useState } from "react";
import axios from "axios";
import { envConfig } from "@/app/lib/config";
import "../../(private)/AsignacionEquipo/asignacion.css";
interface Equipo {
id_equipo: number;
id_plataforma: number;
@@ -22,15 +24,16 @@ interface EnviarMensajeProps {
const EnviarMensaje = ({ titulo }: EnviarMensajeProps) => {
const [equipos, setEquipos] = useState<Equipo[]>([]);
const [equipoSeleccionado, setEquipoSeleccionado] = useState("");
const [equipoSeleccionado, setEquipoSeleccionado] = useState<any>(null);
const [loadingEquipos, setLoadingEquipos] = useState(false);
const [open, setOpen] = useState(false);
const [mensaje, setMensaje] = useState("");
const [customMsg, setCustomMsg] = useState("");
// 🔹 Traer equipos desde API
useEffect(() => {
const fetchEquipos = async () => {
try {
const response = await axios.get(`${envConfig.apiUrl}/equipo`);
const response = await axios.get(`${envConfig.apiUrl}/equipo/busy`);
setEquipos(response.data);
} catch (error) {
console.error("Error cargando equipos:", error);
@@ -50,28 +53,59 @@ const EnviarMensaje = ({ titulo }: EnviarMensajeProps) => {
console.log(payload);
// aquí puedes enviar al backend
// axios.post(...)
};
return (
<form className="containerForm" onSubmit={handleSubmit}>
<label className="label">{titulo}</label>
<div className="groupInput">
<select
value={equipoSeleccionado}
onChange={(e) => setEquipoSeleccionado(e.target.value)}
<div
className={`customSelect ${open ? "open" : ""} ${loadingEquipos ? "disabled" : ""}`}
>
<div
className={`selectHeader ${equipoSeleccionado && equipoSeleccionado.plataforma?.nombre?.toUpperCase()}`}
onClick={() => !loadingEquipos && setOpen(!open)}
>
<option value="">-- Selecciona un equipo --</option>
{equipoSeleccionado ? (
<span
>
{equipoSeleccionado.ubicacion}{" "}
{equipoSeleccionado.nombre_equipo}{" "}
{equipoSeleccionado.areaUbicacion.area}
</span>
) : (
<span className="placeholder">
{loadingEquipos
? "Cargando equipos..."
: "Seleccione un equipo"}
</span>
)}
{equipos.map((eq) => (
<option key={eq.id_equipo} value={eq.id_equipo}>
{eq.ubicacion} {eq.nombre_equipo} {eq.plataforma.nombre}{" "}
{eq.areaUbicacion.area}
</option>
))}
</select>
<span className="arrow">{open ? "▲" : "▼"}</span>
</div>
{open && (
<div className="options">
{equipos.length === 0 && (
<div className="option disabled">
No hay equipos disponibles
</div>
)}
{equipos.map((eq) => (
<div
key={eq.id_equipo}
className={`option ${eq.plataforma?.nombre?.toUpperCase()}`}
onClick={() => {
setEquipoSeleccionado(eq);
setOpen(false);
}}
>
{eq.ubicacion} {eq.nombre_equipo} {eq.areaUbicacion.area}
</div>
))}
</div>
)}
</div>
<label className="label">Seleccione el mensaje</label>
@@ -86,7 +120,7 @@ const EnviarMensaje = ({ titulo }: EnviarMensajeProps) => {
</select>
</div>
<label className="label">Mensaje personalizado</label>
<div className="groupInput">
@@ -98,7 +132,7 @@ const EnviarMensaje = ({ titulo }: EnviarMensajeProps) => {
/>
</div>
<button
className="button buttonSearch"
type="submit"
@@ -4,6 +4,8 @@ import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { useEffect, useState } from "react";
import axios from "axios";
import "../../(private)/AsignacionEquipo/asignacion.css";
interface Equipos {
id_equipo: number;
id_plataforma: number;
@@ -21,60 +23,99 @@ interface Props {
}
export default function SelectorEquipo({ onSearch }: Props) {
const [sala, setSala] = useState<Equipos[]>();
const [equipos, setEquipos] = useState<Equipos[]>([]);
const searchParams = useSearchParams();
const pathname = usePathname();
const router = useRouter();
const paramSala = Number(searchParams.get("equipo")) || 0;
const [selected, setSelected] = useState<number>(paramSala);
const handleChangeEquipo = (e: React.ChangeEvent<HTMLSelectElement>) => {
const value = e.target.value;
const numberValue = Number(e.target.value);
setSelected(numberValue);
if (numberValue === 0) {
onSearch('');
} else {
onSearch(value);
}
const params = new URLSearchParams(searchParams.toString());
if (numberValue === 0) {
params.delete("equipo");
} else {
params.set("equipo", value);
}
router.push(`${pathname}?${params.toString()}`);
};
const paramEquipo = Number(searchParams.get("equipo")) || 0;
const [selected, setSelected] = useState<Equipos | null>(null);
const [loadingEquipos, setLoadingEquipos] = useState(false);
const [open, setOpen] = useState(false);
useEffect(() => {
const fetchData = async () => {
setLoadingEquipos(true);
const response = await axios.get(`${envConfig.apiUrl}/equipo`);
setSala(response.data);
setEquipos(response.data);
setLoadingEquipos(false);
};
fetchData();
}, []);
useEffect(() => {
if (paramEquipo && equipos.length > 0) {
const eq = equipos.find(e => e.id_equipo === paramEquipo);
if (eq) {
setSelected(eq);
onSearch(eq.ubicacion);
}
}
}, [paramEquipo, equipos]);
return (
<form className="form-container">
<label>Ubicacion de equipo</label>
<select value={selected} onChange={handleChangeEquipo}>
<option value={0}>-- Selecciona una equipo --</option>
{sala &&
sala.map((eq) => (
<option key={eq.id_equipo} value={eq.ubicacion}>
{eq.ubicacion} {eq.nombre_equipo} {eq.plataforma.nombre}{" "}
{eq.areaUbicacion.area}
</option>
))}
</select>
<div
className={`customSelect ${open ? "open" : ""} ${loadingEquipos ? "disabled" : ""}`}
>
<div
className={`selectHeader ${selected && selected.plataforma?.nombre?.toUpperCase()}`}
onClick={() => !loadingEquipos && setOpen(!open)}
>
{selected ? (
<span
>
{selected.ubicacion}{" "}
{selected.nombre_equipo}{" "}
{selected.areaUbicacion.area}
</span>
) : (
<span className="placeholder">
{loadingEquipos
? "Cargando equipos..."
: "Seleccione un equipo"}
</span>
)}
<span className="arrow">{open ? "▲" : "▼"}</span>
</div>
{open && (
<div className="options" style={{ bottom: "auto"}}>
{equipos.length === 0 && (
<div className="option disabled">
No hay equipos disponibles
</div>
)}
{equipos.map((eq) => (
<div
key={eq.id_equipo}
className={`option ${eq.plataforma?.nombre?.toUpperCase()}`}
onClick={() => {
setSelected(eq);
setOpen(false);
const params = new URLSearchParams(searchParams.toString());
if (eq.id_equipo === 0) {
params.delete("equipo");
} else {
params.set("equipo", String(eq.id_equipo));
}
router.push(`${pathname}?${params.toString()}`);
}}
>
{eq.ubicacion} {eq.nombre_equipo} {eq.areaUbicacion.area}
</div>
))}
</div>
)}
</div>
</form>
);
}
+15 -1
View File
@@ -46,6 +46,19 @@ function PorRecibos({ desde, hasta }: Props) {
fetchRecibos();
}, [desde, hasta]);
const formatearFechaMX = (fechaISO: string) => {
return new Date(fechaISO).toLocaleString("es-MX", {
timeZone: "America/Mexico_City",
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
});
};
return (
<div style={{ position: "relative" }}>
{recibos.length > 0 && <DownloadReporteXLSX />}
@@ -81,7 +94,8 @@ function PorRecibos({ desde, hasta }: Props) {
<td>{recibo.folio_recibo}</td>
<td>${Number(recibo.monto).toFixed(2)}</td>
<td>{recibo.fecha_recibo}</td>
<td>{recibo.fecha_registro}</td>
<td>{formatearFechaMX(recibo.fecha_registro)}</td>
<td>{recibo.user.usuario}</td>
</tr>
))}
+7
View File
@@ -57,6 +57,13 @@
transform: translate(0, -50%);
}
.userName{
position: absolute;
top: 0px;
right: 50px;
}
}
@media(max-width:450px){
.userName{
position: absolute;
top: 50px;
+2 -2
View File
@@ -374,7 +374,6 @@ a {
top: 0;
left: 0;
width: 100%;
min-height: 45px;
font-size: 2.5rem;
font-weight: bold;
text-align: start;
@@ -692,6 +691,7 @@ table td:last-child {
.toggleSection {
margin-top: 2rem;
overflow: auto;
}
}
@@ -702,7 +702,7 @@ table td:last-child {
}
}
@media (max-width: 450px) {
@media (max-width: 700px) {
.title {
max-width: 250px;
overflow-wrap: break-word;
+1
View File
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.2 MiB