This commit is contained in:
Alejandra-Guzman-Mendez
2025-10-27 13:09:31 -06:00
27 changed files with 1157 additions and 211 deletions
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 311 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 373 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 692 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 474 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 575 KiB

+248
View File
@@ -0,0 +1,248 @@
"use client";
import { useState } from "react";
import "../styles/layout/agregarEquipo.scss"; // Asegúrate de crear este archivo
export default function page() {
const [formData, setFormData] = useState({
serie: "",
marca: "",
modelo: "",
tipoEquipo: "", // Nuevo campo
estado: "",
sistemaOperativo: "",
procesador: "",
tipoUso: "",
observaciones: "",
adscripcion: "",
lugar: "",
responsable: "",
});
// Estado para saber si mostramos los campos de SO y Procesador
const mostrarCamposComputadora = formData.tipoEquipo !== "Impresora";
const handleGuardar = () => {
console.log("Formulario enviado:", formData);
alert("Equipo guardado (vista solo)");
};
const handleCancelar = () => {
alert("Acción cancelada");
};
// Función para actualizar el estado y limpiar campos si es impresora
const handleChange = (e) => {
const { name, value } = e.target;
setFormData((prev) => {
let updated = { ...prev, [name]: value };
// Si es impresora, limpiamos SO y Procesador
if (value === "Impresora") {
updated.sistemaOperativo = "";
updated.procesador = "";
}
return updated;
});
};
return (
<div className="agregarEquipoContainer">
<div className="innerContainer">
<h2>Agregar Nuevo Equipo</h2>
<form className="equipoForm">
{/* Columna Izquierda */}
<div className="column">
<div className="formGroup">
<label>Serie</label>
<input
type="text"
placeholder="Ingresa serie"
value={formData.serie}
onChange={(e) =>
setFormData({ ...formData, serie: e.target.value })
}
/>
</div>
<div className="formGroup">
<label>Marca</label>
<select
value={formData.marca}
onChange={(e) =>
setFormData({ ...formData, marca: e.target.value })
}
>
<option value="">Ingresa marca</option>
<option value="Dell">Dell</option>
<option value="HP">HP</option>
<option value="Lenovo">Lenovo</option>
</select>
</div>
<div className="formGroup">
<label>Modelo</label>
<select
value={formData.modelo}
onChange={(e) =>
setFormData({ ...formData, modelo: e.target.value })
}
>
<option value="">Ingresa modelo</option>
<option value="XPS 15">XPS 15</option>
<option value="EliteBook">EliteBook</option>
<option value="ThinkPad">ThinkPad</option>
</select>
</div>
<div className="formGroup">
<label>Tipo de equipo</label>
<select
name="tipoEquipo"
value={formData.tipoEquipo}
onChange={handleChange}
>
<option value="">Selecciona tipo</option>
<option value="PC">PC</option>
<option value="Laptop">Laptop</option>
<option value="Impresora">Impresora</option>
</select>
</div>
<div className="formGroup">
<label>Estado</label>
<select
value={formData.estado}
onChange={(e) =>
setFormData({ ...formData, estado: e.target.value })
}
>
<option value="">Selecciona estado</option>
<option value="Activado">Activado</option>
<option value="Desactivado">Desactivado</option>
<option value="En reparación">En reparación</option>
</select>
</div>
</div>
{/* Columna Centro */}
<div className="column">
<div className="formGroup">
<label>Tipo uso</label>
<select
value={formData.tipoUso}
onChange={(e) =>
setFormData({ ...formData, tipoUso: e.target.value })
}
>
<option value="">Ingresa tipo de uso</option>
<option value="administrativo">administrativo</option>
<option value="educacional">educacional</option>
<option value="laboratorio">laboratorio</option>
</select>
</div>
{/* Mostrar SO y Procesador solo si NO es impresora */}
{mostrarCamposComputadora && (
<>
<div className="formGroup">
<label>Procesador</label>
<select
value={formData.procesador}
onChange={(e) =>
setFormData({ ...formData, procesador: e.target.value })
}
>
<option value="">Selecciona procesador</option>
<option value="Ryzen 3">Ryzen 3</option>
<option value="Intel i5">Intel i5</option>
<option value="AMD Ryzen 5">AMD Ryzen 5</option>
</select>
</div>
<div className="formGroup">
<label>Sistema operativo</label>
<select
value={formData.sistemaOperativo}
onChange={(e) =>
setFormData({ ...formData, sistemaOperativo: e.target.value })
}
>
<option value="">Selecciona sistema operativo</option>
<option value="Windows 10">Windows 10</option>
<option value="Windows 11">Windows 11</option>
<option value="Linux">Linux</option>
<option value="macOS">macOS</option>
</select>
</div>
</>
)}
<div className="formGroup">
<label>Adscripción</label>
<select
value={formData.adscripcion}
onChange={(e) =>
setFormData({ ...formData, adscripcion: e.target.value })
}
>
<option value="">Selecciona adscripción</option>
<option value="Cedetec">Cedetec</option>
<option value="Laboratorio">Laboratorio</option>
<option value="Administración">Administración</option>
</select>
</div>
<div className="formGroup">
<label>Responsable</label>
<select
value={formData.responsable}
onChange={(e) =>
setFormData({ ...formData, responsable: e.target.value })
}
>
<option value="">Selecciona responsable</option>
<option value="Lino">Lino</option>
<option value="Ana">Ana</option>
<option value="Carlos">Carlos</option>
</select>
</div>
</div>
{/* Columna Derecha */}
<div className="column">
<div className="formGroup">
<label>Lugar</label>
<textarea
placeholder="Ingresa lugar"
value={formData.lugar}
onChange={(e) =>
setFormData({ ...formData, lugar: e.target.value })
}
rows={4}
className="textAreaLarge"
/>
</div>
<div className="formGroup">
<label>Observaciones</label>
<textarea
placeholder="Ingresa observaciones"
value={formData.observaciones}
onChange={(e) =>
setFormData({ ...formData, observaciones: e.target.value })
}
rows={4}
className="textAreaLarge"
/>
</div>
</div>
</form>
{/* Botones */}
<div className="formActions">
<button type="button" className="btnGuardar" onClick={handleGuardar}>
Guardar
</button>
<button type="button" className="btnCancelar" onClick={handleCancelar}>
Cancelar
</button>
</div>
</div>
</div>
);
}
+2 -33
View File
@@ -1,37 +1,6 @@
import "../styles/components/editar";
import "../styles/layout/editar.scss";
export default function Page() {
return (
<form className="editar">
<div className="columna">
<label htmlFor="serie">Serie</label>
<input type="text" id="serie" />
<label htmlFor="marca">Marca</label>
<input type="text" id="marca" />
<label htmlFor="modelo">Modelo</label>
<input type="text" id="modelo" />
<label htmlFor="estado">Estado</label>
<input type="text" id="estado" />
</div>
<div className="columna">
<label htmlFor="so">Sistema Operativo</label>
<input type="text" id="so" />
<label htmlFor="procesador">Procesador</label>
<input type="text" id="procesador" />
<label htmlFor="tipoUso">Tipo de uso</label>
<input type="text" id="tipoUso" />
<label htmlFor="observaciones">Observaciones</label>
<input type="text" id="observaciones" />
</div>
<div className="columna">
<label htmlFor="adscripcion">Adscripción</label>
<input type="text" id="adscripcion" />
<label htmlFor="responsable">Responsable</label>
<input type="text" id="responsable" />
<label htmlFor="lugar">Lugar</label>
<input type="text" id="lugar" />
</div>
</form>
<></>
);
}
+86
View File
@@ -0,0 +1,86 @@
"use client";
import { useState } from "react";
import { useRouter } from "next/navigation";
import "../styles/layout/escaner.scss"; // Importación global
// Tipos
type Equipo = {
id: string;
nombre: string;
estado: string;
};
const initialEquipos: Equipo[] = [
{ id: "001", nombre: "PC Aula 1", estado: "Disponible" },
{ id: "002", nombre: "PC Aula 2", estado: "En reparación" },
];
export default function Dashboard() {
const router = useRouter();
const [equipos, setEquipos] = useState<Equipo[]>(initialEquipos);
const [search, setSearch] = useState("");
const [lastScan, setLastScan] = useState("");
const buscarEquipo = () => {
const resultado = equipos.filter(
(e) =>
e.id.includes(search) ||
e.nombre.toLowerCase().includes(search.toLowerCase())
);
setEquipos(resultado);
};
const cerrarSesion = () => {
localStorage.removeItem("loggedIn");
router.push("/");
};
const handleScan = (code: string) => {
setLastScan(code);
const encontrado = equipos.find((e) => e.id === code);
if (encontrado) {
alert(`Equipo encontrado: ${encontrado.nombre} (${encontrado.estado})`);
} else {
const codigo = prompt("Equipo no registrado. Ingresa el codigo:");
if (codigo) {
setEquipos([...equipos, { id: code, nombre: codigo, estado: "Disponible" }]);
alert("Equipo agregado al inventario");
}
}
};
return (
<div className="dashboardContainer">
{/* VISTA DE ESCANEO */}
<main className="scanView">
<h3>Escanear Inventario</h3>
<div className="scannerFrame">
<img src="/barcode_scanner.png" alt="Marco de escaneo" />
</div>
<p className="instructions">
Enfoca el código de barras dentro del marco
</p>
<button className="scanButton">
<img src="/photo_camera.png" alt="camara" /> Escanear
</button>
<div className="searchBox">
<input
type="text"
placeholder="Buscar por inventario..."
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
<button onClick={buscarEquipo} className="searchButton">
<img src="/search.png" alt="Buscar" />
</button>
</div>
</main>
</div>
);
}
+21 -5
View File
@@ -1,14 +1,30 @@
import Header from "../components/header";
import { Inter, Montserrat } from "next/font/google";
import "../app/styles/base/globales.scss"; // si tienes estilos globales
// Carga optimizada de fuentes
const inter = Inter({
subsets: ["latin"],
weight: ["400", "500", "600", "700"],
variable: "--font-inter",
});
const montserrat = Montserrat({
subsets: ["latin"],
weight: ["400", "700"],
variable: "--font-montserrat",
});
export default function RootLayout({ children }: { children: React.ReactNode }) {
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="es">
<html lang="es" className={`${inter.variable} ${montserrat.variable}`}>
<body>
<Header />
{children}
{children}
</body>
</html>
)
);
}
+5 -39
View File
@@ -1,40 +1,6 @@
"use client"; // <-- OBLIGATORIO
import Login from "@/components/Login";
import "../app/styles/base/globales.scss";
import { useState } from "react";
import { useRouter } from "next/navigation";
import "../app/styles/components/login.scss";
export default function Login() {
const router = useRouter();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const mockUsers = [
{ email: "admin@escuela.com", password: "1234" },
{ email: "usuario@escuela.com", password: "abcd" },
];
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const user = mockUsers.find(u => u.email === email && u.password === password);
if (user) {
localStorage.setItem("loggedIn", "true");
router.push("/dashboard");
} else {
setError("Usuario o contraseña incorrectos");
}
};
return (
<div className="login-container">
<h2>Iniciar sesión</h2>
{error && <p className="error">{error}</p>}
<form onSubmit={handleSubmit}>
<input type="email" placeholder="Correo" value={email} onChange={(e) => setEmail(e.target.value)} required />
<input type="password" placeholder="Contraseña" value={password} onChange={(e) => setPassword(e.target.value)} required />
<button type="submit">Ingresar</button>
</form>
</div>
);
}
export default function page() {
return <Login />;
}
+10
View File
@@ -0,0 +1,10 @@
// Colores
$color-primary: #003e79;
$color-secondary: #fab403;
$color-background: #f5f5f7;
$color-text: #000000;
// Tipografía
$font-primary: "Inter", sans-serif;
$font-titles: "Montserrat", sans-serif;
+76
View File
@@ -0,0 +1,76 @@
@import "variables";
html {
font-size: 62.5%;
box-sizing: border-box;
scroll-padding-top: 0rem;
scrollbar-width: none;
}
*,
*:before,
*:after {
margin: 0;
padding: 0;
box-sizing: inherit;
}
body {
display: grid;
grid-template-rows: auto 1fr;
background-color: $color-background;
font-family: $font-primary;
font-style: normal;
font-size: 2rem;
font-optical-sizing: auto;
min-height: 100dvh;
width: 100vw;
color: $color-text;
}
p {
font-size: 2rem;
line-height: 1.5;
}
a {
color: $color-primary;
display: block;
text-decoration: none;
margin: 10px 5px;
&:hover {
color: $color-secondary;
}
}
h1,
h2,
h3 {
margin: 0 0 5rem 0;
font-weight: 600;
font-family: $font-titles;
}
h1 {
font-size: 2rem;
}
h2 {
font-size: 3rem;
}
h3 {
font-size: 4rem;
text-align: center;
}
label {
display: block;
text-align: start;
width: 100%;
}
img {
object-fit: cover;
}
+37 -40
View File
@@ -19,15 +19,11 @@
transition: all 0.3s ease;
cursor: pointer;
color: white;
width: 100%;
width: auto;
transition: background-color 0.3s ease;
font-size: 1.5rem;
}
.barNavigation li:hover {
background-color: #bd8c01;
}
.barNavigation ul.active {
display: flex;
width: 100%;
@@ -66,10 +62,10 @@
max-height: 0;
position: absolute;
flex-direction: column;
top: 100%;
width: 100%;
min-width: 200px;
max-width: 300px;
left: 0;
background-color: #003e79;
transition: color 0.3s ease;
transition: opacity 0.4s ease, max-height 0.4s ease;
}
@@ -77,15 +73,6 @@
display: none;
}
.subMenu.open ul {
display: flex;
color: rgba(0, 61, 121, 1);
}
.subMenu ul:hover {
color: #5b8cc9;
}
.subMenu:hover ul {
opacity: 1;
max-height: 500px;
@@ -109,16 +96,6 @@
font-size: 1.5rem;
}
.subMenu:hover > span,
.subMenu > a:hover > span {
color: white;
}
.containerLinks {
padding: 0 !important;
border-radius: 0 0 4px 4px;
}
.links {
display: flex;
justify-content: center;
@@ -129,11 +106,28 @@
font-size: 1.5rem;
}
thead,
tbody {
font-size: 1.25rem;
/* Estilo del botón de cierre de sesión */
.logout-button {
background-color: #ff4d4d;
color: white;
border: none;
padding: 8px 16px;
border-radius: 6px;
cursor: pointer;
font-weight: bold;
font-size: 1.2rem;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
max-width: 200px;
&:hover {
background-color: #e63939;
}
}
/* ✅ Ajustes para móvil */
@media (max-width: 800px) {
.menuToggle {
display: flex;
@@ -141,18 +135,12 @@ tbody {
align-items: end;
transition: transform 0.3s ease;
}
.barNavigation {
width: 100vw;
}
.menuToggle.center {
align-items: center;
margin: 0;
}
.barNavigation {
font-size: 15px;
display: block;
padding: 0;
width: 100%;
}
.barNavigation ul {
@@ -164,10 +152,11 @@ tbody {
display: none;
z-index: 1;
height: auto;
width: 100%;
}
.barNavigation {
padding: 0;
.barNavigation ul.active {
display: flex;
}
.barNavigation li:hover {
@@ -184,6 +173,14 @@ tbody {
background-color: rgb(1, 92, 184);
}
.logout-button {
margin-top: 10px;
font-size: 1rem;
padding: 6px 12px;
max-width: 180px;
}
thead,
tbody {
font-size: 1rem;
+160
View File
@@ -0,0 +1,160 @@
.agregarEquipoContainer {
background-color: #ffffff;
padding: 0;
margin: 0;
width: 100%;
max-width: 100%;
display: flex;
align-items: center;
justify-content: center;
.innerContainer {
max-width: 1000px;
width: 1000px;
margin: 0 auto;
padding: 20px;
}
h2 {
margin-top: 1rem;
text-align: center;
color: #0056b3;
margin-bottom: 20px;
font-size: 1.8rem;
}
}
.equipoForm {
display: flex;
gap: 30px;
.column {
flex: 1;
display: flex;
flex-direction: column;
gap: 15px;
.formGroup {
display: flex;
flex-direction: column;
min-width: 0;
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
color: #333;
font-size: 14px;
}
input,
select,
textarea {
width: 100%;
padding: 10px;
border: 1px solid #ccc; /* Borde azul como en la imagen */
border-radius: 6px;
font-size: 15px;
transition: border-color 0.2s ease;
height: 40px;
&:focus {
outline: none;
border-color: #007bff;
box-shadow: 0 0 0 2px rgba(0, 86, 179, 0.2);
}
}
textarea.textAreaLarge {
height: auto;
min-height: 80px;
max-height: 150px;
resize: none;
padding: 12px;
font-family: inherit;
}
select {
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3e%3cpath d='M7 10l5 5 5-5z'/%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: right 10px center;
background-size: 12px;
padding-right: 30px;
}
}
}
}
.formActions {
display: flex;
justify-content: flex-end;
gap: 30px;
.btnGuardar {
background-color: #ffb700;
color: #000;
border: none;
padding: 10px 20px;
border-radius: 6px;
font-weight: bold;
cursor: pointer;
font-size: 16px;
&:hover {
background-color: #ffcc33;
}
}
.btnCancelar {
background-color: #0056b3;
color: white;
border: none;
padding: 10px 20px;
border-radius: 6px;
font-weight: bold;
cursor: pointer;
font-size: 16px;
&:hover {
background-color: #004494;
}
}
}
/* Responsive: en móvil, una columna */
@media (max-width: 768px) {
.agregarEquipoContainer .innerContainer {
padding: 15px;
}
.equipoForm {
flex-direction: column;
gap: 20px;
.column {
flex: 1 1 100%;
min-width: auto;
.formGroup {
input,
select {
width: 100%;
font-size: 16px;
}
}
}
}
.formActions {
flex-direction: column;
align-items: stretch;
button {
width: 100%;
font-size: 18px;
padding: 12px;
}
}
}
+11
View File
@@ -0,0 +1,11 @@
.editar{
max-width: 1000px;
display: flex;
gap: 20px;
}
.columna{
display: flex ;
flex-direction: column;
}
+135
View File
@@ -0,0 +1,135 @@
.dashboardContainer {
display: flex;
flex-direction: column;
padding: 0;
margin: 0;
background-color: #ffffff;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 24px;
background-color: #ffffff;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
position: sticky;
top: 0;
z-index: 10;
h2 {
margin: 0;
font-size: 1.5rem;
color: #0056b3;
}
}
.scanView {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 30px 20px;
gap: 20px;
width: 100%;
height: 100%;
h3 {
font-size: 16px;
font-weight:500;
margin: 0;
}
}
.scannerFrame {
width: 90%;
max-width: 500px;
height: 300px;
border: 2px solid #0056b3;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
background-color: #f9f9f9;
font-size: 80px;
color: #000;
img{
width: 150px;
height: auto;
}
}
.instructions {
text-align: center;
font-size: 14px;
color: #666;
margin: 0;
}
.scanButton {
background-color: #ffb700;
color: #000;
border: none;
padding: 10px 24px;
border-radius: 20px;
font-weight: bold;
font-size: 16px;
cursor: pointer;
display: flex;
align-items: center;
gap: 8px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
color:#003E79 ;
&:hover {
background-color: #ffcc33;
}
}
.searchBox {
display: flex;
align-items: center;
gap: 8px;
width: 80%;
max-width: 400px;
border: 2px solid #0056b3;
border-radius: 20px;
overflow: hidden;
input {
flex: 1;
padding: 12px 16px;
border: none;
outline: none;
font-size: 16px;
background: transparent;
}
.searchButton {
background-color: #0056b3;
color: white;
border-radius: 10px;
border: none;
padding: 0 5px;
cursor: pointer;
font-size: 18px;
margin-right: 10px;
display: flex; // ← Activa Flexbox
align-items: center; // ← Centra verticalmente
justify-content: center; // ← Centra horizontalmente
width: 36px; // ← Opcional: da un ancho fijo para que sea cuadrado
height: 36px; // ← Opcional: altura igual al ancho
&:hover {
background-color: #004494;
}
img {
display: block;
width: 20px; // ← Ajusta el tamaño del icono
height: auto; // ← Mantiene proporción
}
}
}
+9 -8
View File
@@ -1,6 +1,5 @@
.logo {
position: relative;
filter: invert(1);
z-index: 3;
margin: 5px;
}
@@ -26,17 +25,19 @@
content: "";
top: 0;
left: -20px;
width: 65%;
width: 100%;
height: 30px;
min-width: 300px;
background: #bd8c01;
background: linear-gradient(to right, #bd8c01 40%, #fff 100%);
transform: skew(-45deg);
z-index: 0;
}
.header {
background-color: #fff;
display: grid;
grid-template-columns: auto 1fr;
padding: 0 40px;
padding: 0 10px;
position: relative;
z-index: 1;
height: 90px;
@@ -45,11 +46,11 @@
.header::after {
content: "";
top: 0;
left: -40px;
left: -60px;
position: absolute;
background-color: #003e79;
height: 100%;
min-width: 300px;
min-width: 400px;
transform: skew(45deg);
z-index: 2;
}
@@ -57,12 +58,12 @@
.header::before {
content: "";
top: 0;
left: -20px;
left: -40px;
position: absolute;
background-color: rgb(1, 92, 184);
height: 100%;
width: 10%;
min-width: 300px;
min-width: 400px;
transform: skew(45deg);
z-index: 2;
}
+255 -11
View File
@@ -1,20 +1,28 @@
.containerGrid {
display: flex;
justify-content: center;
align-items: center;
gap: 10vw;
width: 100%;
}
.login-container {
width: 300px;
margin: 100px auto;
padding: 30px;
border: 1px solid #ccc;
border-radius: 10px;
background: #f8f9fa;
width: 350px;
padding: 1.5rem;
text-align: center;
h2 { margin-bottom: 20px; color: #004aad; }
h2 {
margin-bottom: 20px;
color: #bd8c01;
}
input {
width: 100%;
padding: 10px;
margin-bottom: 15px;
border-radius: 5px;
border: 1px solid #ccc;
border-radius: 10px;
border: 1px solid #003e79;
font-size: 2rem;
}
button {
@@ -23,9 +31,245 @@
background-color: #004aad;
color: white;
border: none;
border-radius: 5px;
border-radius: 4px;
cursor: pointer;
}
.error { color: red; margin-bottom: 10px; }
.error {
color: red;
margin-bottom: 10px;
}
}
.imageContainer {
display: flex;
flex-wrap: wrap;
max-width: 500px;
max-height: 450px;
border-radius: 10px;
overflow: hidden;
height: min-content;
}
.login-page {
display: flex;
grid-template-columns: 1fr 1fr;
min-height: 100%;
margin: 0 100px;
justify-content: center;
align-items: center;
gap: 150px;
.login-form-container {
width: 100%;
max-width: 400px;
padding: 2rem 1.5rem;
display: flex;
flex-direction: column;
align-items: center;
h2 {
color: #bd8c01;
font-size: 1.8rem;
margin-bottom: 1.5rem;
font-weight: 600;
text-align: center;
}
.input-group {
width: 100%;
margin-bottom: 1.2rem;
label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
color: #333;
}
input {
width: 100%;
padding: 12px 15px;
border: 2px solid #003e79;
border-radius: 8px;
font-size: 1rem;
transition: border-color 0.2s;
&:focus {
outline: none;
border-color: #004aad;
}
}
}
button[type="submit"] {
width: 100%;
padding: 12px;
background-color: #004aad;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 1rem;
font-weight: 600;
margin-bottom: 1rem;
transition: background-color 0.2s;
&:hover {
background-color: #003e79;
}
}
.forgot-password,
.create-account {
color: #004aad;
text-decoration: none;
font-size: 1rem;
margin: 0.3rem 0;
font-weight: 500;
text-align: center;
&:hover {
text-decoration: underline;
}
}
.create-account {
font-weight: 600;
font-size: 1rem;
}
.divider {
width: 100%;
text-align: center;
margin: 1.5rem 0;
position: relative;
span {
background: white;
padding: 0 10px;
color: #888;
font-size: 0.9rem;
}
&::before {
content: "";
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 1px;
background: #ddd;
z-index: -1;
}
}
.error {
color: red;
margin-bottom: 1rem;
font-size: 0.9rem;
}
}
}
.image-collage {
display: flex;
justify-content: center;
align-items: center;
position: relative;
width: 500px; /* o el tamaño que desees */
height: 450px;
overflow: hidden;
border-radius: 10px;
.collage-item {
position: absolute;
border-radius: 0;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease;
display: flex;
justify-content: center;
align-items: center;
img {
object-fit: cover;
object-position: sta;
}
}
.collage-1 {
top: -30px;
left: 0;
width: 60%;
height: 60%;
clip-path: polygon(0 0, 100% 0, 80% 68%, 0 68%);
}
.collage-2 {
top: 0;
right: 0;
width: 60%;
height: 35%;
clip-path: polygon(30% 0, 100% 0, 100% 90%, 13.5% 90%);
}
.collage-3 {
bottom: 35%;
left: 0;
width: 60%;
height: 35%;
clip-path: polygon(0 0, 80% 0, 100% 100%, 0 100%);
}
.collage-4 {
bottom: 35%;
right: 0;
width: 60%;
height: 35%;
clip-path: polygon(13% 0, 100% 0, 100% 100%, 30% 100%);
}
.collage-5 {
bottom: 0%;
left: 0;
width: 60%;
height: 35%;
clip-path: polygon(0 0, 97% 0, 80% 100%, 0 100%);
}
.collage-6 {
bottom: 0%;
right: 0;
width: 52%;
height: 35%;
clip-path: polygon(19.5% 0, 100% 0, 100% 100%, 0% 100%);
}
}
// Responsive para pantallas pequeñas
@media (max-width: 768px) {
.login-page {
flex-direction: column;
.login-form-container {
width: 100%;
padding: 1.5rem;
margin-bottom: 1rem;
}
.image-collage {
width: 100%;
height: 300px;
.collage-item {
position: static;
width: 100%;
height: 100%;
clip-path: none;
border-radius: 8px;
}
}
}
}
+23 -69
View File
@@ -1,9 +1,12 @@
"use client";
import { useState } from "react";
import "../app/styles/components/BarNavigation.scss";
import { useRouter } from "next/navigation"; // ✅ Importa useRouter
import "../app/styles/layout/BarNavigation.scss";
import Link from "next/link";
function BarNavigation() {
const router = useRouter(); // ✅ Para redirigir
const [openMenu, setOpenMenu] = useState(false);
const [openSubMenu, setOpenSubMenu] = useState<number | null>(null);
@@ -14,91 +17,42 @@ function BarNavigation() {
}
};
const cerrarSesion = () => {
if (typeof window !== "undefined") {
localStorage.removeItem("loggedIn");
router.push("/"); // ✅ Redirige al inicio
}
setOpenMenu(false); // Cierra menú móvil
};
return (
<nav className="barNavigation">
<div className={`menuToggle ${openMenu ? "" : ""}`} onClick={toggleMenu}>
<div className="menuToggle" onClick={toggleMenu}>
<div></div>
<div></div>
<div></div>
</div>
<ul className={openMenu ? "active" : ""}>
<li className={`subMenu ${openSubMenu === 0 ? "open" : ""}`}>
<span onClick={() => toggleSubMenu(0)}>Inscripciónes</span>
<ul className="containerLinks" onClick={toggleMenu}>
<Link href="/AgregarTiempo" className="links">
<li>Agregar Tiempo</li>
</Link>
<Link href="/Inscripcion" className="links">
<li>Inscripción Usuario</li>
</Link>
</ul>
</li>
<li className={`subMenu ${openSubMenu === 1 ? "open" : ""}`}>
<span onClick={() => toggleSubMenu(1)}>Servicios</span>
<ul onClick={toggleMenu}>
<Link href="/Impresiones" className="links">
<li>Impresiones y Ploteo</li>
</Link>
<Link href="/AsignacionMesas" className="links">
<li>Asignacion de Mesas</li>
</Link>
<Link href="/AsignacionEquipo" className="links">
<li>Asignacion de Equipos</li>
</Link>
<Link href="/Monitor" className="links">
<li>Monitor</li>
</Link>
</ul>
</li>
<li className={`subMenu ${openSubMenu === 2 ? "open" : ""}`}>
<span onClick={() => toggleSubMenu(2)}>Equipo</span>
<ul onClick={toggleMenu}>
<Link href="/InformacionEquipo" className="links">
<li>Informacion de Equipos</li>
</Link>
<Link href="/ActivosMantenimiento" className="links">
<li>Activos y en Mantenimiento</li>
</Link>
<Link href="/Mensajes" className="links">
<li>Mensajes</li>
</Link>
<Link href="/Programas" className="links">
<li>Programas</li>
</Link>
</ul>
</li>
<li className={`subMenu ${openSubMenu === 3 ? "open" : ""}`}>
<span onClick={() => toggleSubMenu(3)}>Reportes</span>
<ul onClick={toggleMenu}>
<Link href="/Reportes" className="links">
<li>Reportes</li>
</Link>
<Link href="/Inscritos" className="links">
<li>Inscritos</li>
</Link>
<Link href="/BitacoraSanciones" className="links">
<li>Bitacora y sanciones</li>
</Link>
</ul>
</li>
<li className="subMenu" onClick={toggleMenu}>
<Link href="/QuitarSancion" className="links">
<span>Quitar sanción</span>
<Link href="/Escaner" className="links">
<span>Escanear</span>
</Link>
</li>
<li className="subMenu" onClick={toggleMenu}>
<Link href="/CambiarPass" className="links">
<span> Cambiar contraseña</span>
<Link href="/AgregarEquipo" className="links">
<span>Agregar equipo</span>
</Link>
</li>
{/* ✅ Botón directo, sin onClick en el <li> */}
<li>
<button className="logout-button" onClick={cerrarSesion}>
Cerrar sesión
</button>
</li>
</ul>
</nav>
);
}
export default BarNavigation;
//IO
+73
View File
@@ -0,0 +1,73 @@
"use client";
import { useState } from "react";
import "../app/styles/layout/login.scss";
import "../app/styles/base/globales.scss";
import Image from "next/image";
import Link from "next/link";
export default function Login() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
// Autenticacion simulada
};
return (
<section className="containerGrid">
<div className="login-container">
<h2>Inicio de sesión</h2>
{error && <p className="error">{error}</p>}
<form onSubmit={handleSubmit}>
<div>
<label>Usuario</label>
<input
type="email"
placeholder="Correo"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
</div>
<div>
<label>Contraseña</label>
<input
type="password"
placeholder="Contraseña"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
</div>
<button type="submit">Iniciar sesión</button>
<Link href={"#"}>Olvidaste Contraseña?</Link>
<Link href={"#"}>Crear Cuenta</Link>
</form>
</div>
<div className="image-collage">
<div className="collage-item collage-1">
<Image src="/Piedra.jpg" alt="UNAM Icatlán" fill style={{ objectFit: 'cover' }} />
</div>
<div className="collage-item collage-2">
<Image src="/image 1.png" alt="UNAM Icatlán" fill style={{ objectFit: 'cover' }} />
</div>
<div className="collage-item collage-3">
<Image src="/estrella.jpg" alt="UNAM Icatlán" fill style={{ objectFit: 'cover' }} />
</div>
<div className="collage-item collage-4">
<Image src="/sorjuana.jpg" alt="UNAM Icatlán" fill style={{ objectFit: 'cover' }} />
</div>
<div className="collage-item collage-5">
<Image src="/fes.jpg" alt="UNAM Icatlán" fill style={{ objectFit: 'cover' }} />
</div>
<div className="collage-item collage-6">
<Image src="/picachu.jpg" alt="UNAM Icatlán" fill style={{ objectFit: 'cover' }} />
</div>
</div>
</section>
);
}
+6 -6
View File
@@ -1,6 +1,6 @@
"use client";
import Image from "next/image";
import header from "../app/styles/components/header.module.scss";
import header from "../app/styles/layout/header.module.scss";
import Link from "next/link";
import BarNavigation from "./BarNavigation";
@@ -18,10 +18,10 @@ function Header() {
>
<Image
className={header.logo}
src="/logo_fes.png"
src="/logo-blanco.png"
alt="Logo FES"
width={200}
height={50}
width={250}
height={70}
/>
</Link>
<div className={header.yellowPart}></div>
@@ -30,7 +30,7 @@ function Header() {
display: "flex",
width: "100%",
marginLeft: "40px",
marginTop: "45px",
marginTop: "40px",
maxHeight: "50%",
alignItems: "end",
}}
@@ -43,4 +43,4 @@ function Header() {
}
export default Header;
//IO
//IO