Compare commits
1 Commits
development
..
Sam
| Author | SHA1 | Date | |
|---|---|---|---|
| e2457f4cd4 |
-6
@@ -1,6 +0,0 @@
|
|||||||
<component name="InspectionProjectProfileManager">
|
|
||||||
<profile version="1.0">
|
|
||||||
<option name="myName" value="Project Default" />
|
|
||||||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
|
||||||
</profile>
|
|
||||||
</component>
|
|
||||||
+1
-1
@@ -17,7 +17,7 @@
|
|||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "set PORT=3226 && react-scripts start",
|
"start": "set PORT=3001 && react-scripts start",
|
||||||
"build": "react-scripts build",
|
"build": "react-scripts build",
|
||||||
"test": "react-scripts test",
|
"test": "react-scripts test",
|
||||||
"eject": "react-scripts eject"
|
"eject": "react-scripts eject"
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB |
+63
-1
@@ -109,6 +109,17 @@
|
|||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container-fluid {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control {
|
||||||
|
border-color: #002b7a !important;
|
||||||
|
}
|
||||||
|
|
||||||
.form-group {
|
.form-group {
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
@@ -227,6 +238,24 @@ label {
|
|||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.6em;
|
||||||
|
font-size: 1em;
|
||||||
|
color: #fff;
|
||||||
|
background-color: #007bff;
|
||||||
|
border: none;
|
||||||
|
border-radius: 12px !important;
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: 0 4px 8px 2px rgba(0, 0, 0, 0.1);
|
||||||
|
transition: background-color 0.3s ease, box-shadow 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background-color: #0056b3;
|
||||||
|
box-shadow: 0 6px 12px 4px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
.main-content {
|
.main-content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -286,9 +315,42 @@ input[type="password"] {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-radius: 5px !important;
|
border-radius: 5px !important;
|
||||||
|
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1),
|
||||||
|
0 2px 4px 1px rgba(0, 0, 0, 0.1);
|
||||||
transition: box-shadow 0.3s ease;
|
transition: box-shadow 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input[type="text"]:focus,
|
||||||
|
input[type="email"]:focus,
|
||||||
|
input[type="tel"]:focus,
|
||||||
|
input[type="password"]:focus {
|
||||||
|
box-shadow: 0 0 8px 2px rgba(0, 123, 255, 0.5);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
button[type="submit"] {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.75em;
|
||||||
|
border: none;
|
||||||
|
border-radius: 1em;
|
||||||
|
background-color: #002b7a;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 0.9em;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.3s ease, box-shadow 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
button[type="submit"]:hover {
|
||||||
|
background-color: #0056b3;
|
||||||
|
box-shadow: 0 6px 12px 4px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
button[type="submit"]:disabled {
|
||||||
|
background-color: #007bff;
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
.delete-botones {
|
.delete-botones {
|
||||||
background-image: url("https://cdn.icon-icons.com/icons2/1791/PNG/512/trashcan1_114647.png");
|
background-image: url("https://cdn.icon-icons.com/icons2/1791/PNG/512/trashcan1_114647.png");
|
||||||
filter: invert(1);
|
filter: invert(1);
|
||||||
@@ -334,7 +396,7 @@ body {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background-color: #f5f5f7;
|
min-width: 100vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2.text-warning {
|
h2.text-warning {
|
||||||
|
|||||||
+2
-3
@@ -26,11 +26,10 @@ import Login from "./components/Login/LoginForm";
|
|||||||
import { PrivateRoutes, PublicRoutes } from "./models/routes";
|
import { PrivateRoutes, PublicRoutes } from "./models/routes";
|
||||||
import Guard from "./guards/route.guard";
|
import Guard from "./guards/route.guard";
|
||||||
import Id from "./guards/id.guard";
|
import Id from "./guards/id.guard";
|
||||||
import HomeView from "./pages/Home/HomeView";
|
|
||||||
|
|
||||||
const UserGuardedRoute = ({ element, permissions, allowedId }) => {
|
const UserGuardedRoute = ({ element, permissions, allowedId }) => {
|
||||||
const { id_usuario } = useParams();
|
const { id_usuario } = useParams();
|
||||||
return permissions === 1 || id_usuario == allowedId ? ( //double equal is necessary
|
return permissions === 1 || id_usuario == allowedId ? (//double equal is necessary
|
||||||
element
|
element
|
||||||
) : (
|
) : (
|
||||||
<Pagina404 />
|
<Pagina404 />
|
||||||
@@ -60,7 +59,7 @@ const App = () => {
|
|||||||
path={`${PublicRoutes.DATAPROFESOR}:id_profesor`}
|
path={`${PublicRoutes.DATAPROFESOR}:id_profesor`}
|
||||||
element={<PerfilProfesor />}
|
element={<PerfilProfesor />}
|
||||||
/>
|
/>
|
||||||
<Route path={PublicRoutes.FILTER} element={<HomeView />} />
|
<Route path={PublicRoutes.FILTER} element={<FilterProfesor />} />
|
||||||
|
|
||||||
{!permissions && ( //only when you don't have permissions, can you pass
|
{!permissions && ( //only when you don't have permissions, can you pass
|
||||||
<Route path={PublicRoutes.LOGIN} element={<Login />} />
|
<Route path={PublicRoutes.LOGIN} element={<Login />} />
|
||||||
|
|||||||
@@ -1,4 +1,18 @@
|
|||||||
|
.card {
|
||||||
|
max-width: 90vw;
|
||||||
|
width: 400px;
|
||||||
|
height: 170px;
|
||||||
|
margin: auto;
|
||||||
|
padding: 0.5em;
|
||||||
|
border-radius: 1em !important;
|
||||||
|
background: white !important;
|
||||||
|
box-shadow: 0 4px 8px 2px rgba(0, 0, 0, 0.1);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row !important;
|
||||||
|
justify-content: left;
|
||||||
|
text-align: center;
|
||||||
|
transition: box-shadow 0.3s ease-out, transform 0.3s ease-out ;
|
||||||
|
}
|
||||||
|
|
||||||
.transition{
|
.transition{
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
@@ -15,6 +29,11 @@
|
|||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card:hover {
|
||||||
|
box-shadow: 0 8px 16px 4px rgba(0, 0, 0, 0.2);
|
||||||
|
transform: translateY(-5px);
|
||||||
|
}
|
||||||
|
|
||||||
.card-content {
|
.card-content {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -29,4 +29,9 @@
|
|||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-control,
|
||||||
|
.btn {
|
||||||
|
width: 100%;
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,9 +16,7 @@ function FilterProfesor() {
|
|||||||
const categorias = useCategoria();
|
const categorias = useCategoria();
|
||||||
const edificios = useEdificio();
|
const edificios = useEdificio();
|
||||||
const [filters, setFilters] = useState({});
|
const [filters, setFilters] = useState({});
|
||||||
const [currentPage, setCurrentPage] = useState(
|
const [currentPage, setCurrentPage] = useState(Number(localStorage.getItem("lastPage")) || 1);
|
||||||
Number(localStorage.getItem("lastPage")) || 1
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleSubmit = (e) => {
|
const handleSubmit = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -32,10 +30,80 @@ function FilterProfesor() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="main">
|
||||||
<nav className="navbar filter" style={{ backgroundColor: "#292d2f" }}>
|
<nav className="navbar filter" style={{ backgroundColor: "#292d2f" }}>
|
||||||
<div className="container-fluid justify-content-center">
|
<div className="container-fluid justify-content-center">
|
||||||
|
<form
|
||||||
|
className="d-flex align-items-center"
|
||||||
|
role="search"
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
className="form-control me-2"
|
||||||
|
type="search"
|
||||||
|
placeholder="Nombre"
|
||||||
|
name="nombre"
|
||||||
|
value={nombre}
|
||||||
|
onChange={(e) => setNombre(e.target.value)}
|
||||||
|
aria-label="Nombre"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<select
|
||||||
|
id="adscripcion"
|
||||||
|
value={adscripcion}
|
||||||
|
onChange={(e) => setAdscripcion(e.target.value)}
|
||||||
|
className="form-control me-2"
|
||||||
|
>
|
||||||
|
<option value="">Adscripción</option>
|
||||||
|
{adscripciones.map((adscripcion) => (
|
||||||
|
<option
|
||||||
|
key={adscripcion.id_adscripcion}
|
||||||
|
value={adscripcion.id_adscripcion}
|
||||||
|
>
|
||||||
|
{adscripcion.adscripcion}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select
|
||||||
|
id="categoria"
|
||||||
|
value={categoria}
|
||||||
|
onChange={(e) => setCategoria(e.target.value)}
|
||||||
|
className="form-control me-2"
|
||||||
|
>
|
||||||
|
<option value="">Categoría</option>
|
||||||
|
{categorias.map((categoria) => (
|
||||||
|
<option
|
||||||
|
key={categoria.id_categoria}
|
||||||
|
value={categoria.id_categoria}
|
||||||
|
>
|
||||||
|
{categoria.categoria}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select
|
||||||
|
id="edificio"
|
||||||
|
value={edificio}
|
||||||
|
onChange={(e) => setEdificio(e.target.value)}
|
||||||
|
className="form-control me-2"
|
||||||
|
>
|
||||||
|
<option value="">Edificio</option>
|
||||||
|
{edificios.map((edificio) => (
|
||||||
|
<option key={edificio.id_edificio} value={edificio.id_edificio}>
|
||||||
|
{edificio.edificio}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="btn me-2"
|
||||||
|
type="submit"
|
||||||
|
style={{ background: "#D59F0F", color: "#fff" }}
|
||||||
|
>
|
||||||
|
Buscar
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<Mapeo
|
<Mapeo
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ const Mapeo = ({ filters, edificios, currentPage, setCurrentPage }) => {
|
|||||||
loading: loadingData,
|
loading: loadingData,
|
||||||
error: errorData,
|
error: errorData,
|
||||||
} = useTeachers(currentPage, filters);
|
} = useTeachers(currentPage, filters);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
profesores: profesoresActivesData,
|
profesores: profesoresActivesData,
|
||||||
totalPages: totalActivePages,
|
totalPages: totalActivePages,
|
||||||
@@ -143,10 +142,10 @@ const Mapeo = ({ filters, edificios, currentPage, setCurrentPage }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="">
|
<div className="main-content">
|
||||||
{permissions ? (
|
{permissions ? (
|
||||||
<div className="containerButton">
|
<div className="containerButton">
|
||||||
<button className="btn btn-primary" onClick={handleRegresar}>
|
<button className="blueButton" onClick={handleRegresar}>
|
||||||
Regresar
|
Regresar
|
||||||
</button>
|
</button>
|
||||||
<button className="blueButton" onClick={handleCrear}>
|
<button className="blueButton" onClick={handleCrear}>
|
||||||
@@ -154,14 +153,8 @@ const Mapeo = ({ filters, edificios, currentPage, setCurrentPage }) => {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="container border">
|
|
||||||
<div className="row">
|
<div className="profesores-container">
|
||||||
{profesores.map((profesor, index) => (
|
|
||||||
<div className="col-4">{profesor.nombre}</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/* <div className="profesores-container">
|
|
||||||
{profesores.map((profesor, index) => {
|
{profesores.map((profesor, index) => {
|
||||||
const edificio = edificios.find(
|
const edificio = edificios.find(
|
||||||
(e) => e.id_edificio === profesor.id_edificio
|
(e) => e.id_edificio === profesor.id_edificio
|
||||||
@@ -183,7 +176,8 @@ const Mapeo = ({ filters, edificios, currentPage, setCurrentPage }) => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div> */}
|
</div>
|
||||||
|
|
||||||
<nav aria-label="Page navigation example">
|
<nav aria-label="Page navigation example">
|
||||||
<ul className="pagination justify-content-center">
|
<ul className="pagination justify-content-center">
|
||||||
<li className={`page-item ${currentPage === 1 ? "disabled" : ""}`}>
|
<li className={`page-item ${currentPage === 1 ? "disabled" : ""}`}>
|
||||||
|
|||||||
@@ -92,10 +92,10 @@ const MapeoUsuario = ({ filters }) => {
|
|||||||
return (
|
return (
|
||||||
<div className="main-content">
|
<div className="main-content">
|
||||||
<div className="containerButton">
|
<div className="containerButton">
|
||||||
<button className="btn btn-primary" onClick={handleRegresar}>
|
<button className="blueButton" onClick={handleRegresar}>
|
||||||
Regresar
|
Regresar
|
||||||
</button>
|
</button>
|
||||||
<button className="btn btn-primary" onClick={handleCrear}>
|
<button className="blueButton" onClick={handleCrear}>
|
||||||
Crear Usuario
|
Crear Usuario
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,160 +0,0 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import {
|
|
||||||
useAdscripcion,
|
|
||||||
useCategoria,
|
|
||||||
useEdificio,
|
|
||||||
} from "../services/auth.services";
|
|
||||||
import { useSearchParams } from "react-router-dom";
|
|
||||||
|
|
||||||
export default function Filter() {
|
|
||||||
const adscripciones = useAdscripcion();
|
|
||||||
const categorias = useCategoria();
|
|
||||||
const edificios = useEdificio();
|
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
|
||||||
|
|
||||||
const [filtro, setFiltro] = useState({
|
|
||||||
nombre: "",
|
|
||||||
adscripcion: "",
|
|
||||||
categoria: "",
|
|
||||||
edificio: "",
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const nombre = searchParams.get("nombre") || "";
|
|
||||||
const adscripcion = searchParams.get("adscripcion") || "";
|
|
||||||
const categoria = searchParams.get("categoria") || "";
|
|
||||||
const edificio = searchParams.get("edificio") || "";
|
|
||||||
|
|
||||||
setFiltro({ nombre, adscripcion, categoria, edificio });
|
|
||||||
}, [searchParams]);
|
|
||||||
|
|
||||||
const handleOnSubmit = (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
const queryParams = {};
|
|
||||||
|
|
||||||
if (filtro.nombre) queryParams.nombre = filtro.nombre;
|
|
||||||
if (filtro.adscripcion) queryParams.adscripcion = filtro.adscripcion;
|
|
||||||
if (filtro.categoria) queryParams.categoria = filtro.categoria;
|
|
||||||
if (filtro.edificio) queryParams.edificio = filtro.edificio;
|
|
||||||
|
|
||||||
// Actualizar los parámetros de la URL
|
|
||||||
setSearchParams(queryParams);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleChange = (e) => {
|
|
||||||
const { id, value } = e.target;
|
|
||||||
setFiltro({
|
|
||||||
...filtro,
|
|
||||||
[id]: value,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClear = () => {
|
|
||||||
// Limpiar los filtros en el estado
|
|
||||||
setFiltro({
|
|
||||||
nombre: "",
|
|
||||||
adscripcion: "",
|
|
||||||
categoria: "",
|
|
||||||
edificio: "",
|
|
||||||
});
|
|
||||||
|
|
||||||
// Limpiar los parámetros de la URL
|
|
||||||
setSearchParams({});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<form
|
|
||||||
onSubmit={handleOnSubmit}
|
|
||||||
className="m-2 p-2 position-sticky"
|
|
||||||
style={{ top: "10px" }}
|
|
||||||
>
|
|
||||||
<p className="text-start m-0 fs-3">Filtro</p>
|
|
||||||
|
|
||||||
<div className="mb-3">
|
|
||||||
<label htmlFor="nombre" className="form-label mb-0">
|
|
||||||
Nombre
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="form-control"
|
|
||||||
id="nombre"
|
|
||||||
value={filtro.nombre}
|
|
||||||
onChange={handleChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mb-3">
|
|
||||||
<label htmlFor="adscripcion" className="form-label mb-0">
|
|
||||||
Adscripción
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
id="adscripcion"
|
|
||||||
value={filtro.adscripcion}
|
|
||||||
onChange={handleChange}
|
|
||||||
className="form-control me-2"
|
|
||||||
>
|
|
||||||
<option value="">Selecciona Adscripción</option>
|
|
||||||
{adscripciones.map((adscripcion) => (
|
|
||||||
<option
|
|
||||||
key={adscripcion.id_adscripcion}
|
|
||||||
value={adscripcion.id_adscripcion}
|
|
||||||
>
|
|
||||||
{adscripcion.adscripcion}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mb-3">
|
|
||||||
<label htmlFor="categoria" className="form-label mb-0">
|
|
||||||
Categoría
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
id="categoria"
|
|
||||||
value={filtro.categoria}
|
|
||||||
onChange={handleChange}
|
|
||||||
className="form-control me-2"
|
|
||||||
>
|
|
||||||
<option value="">Selecciona Categoría</option>
|
|
||||||
{categorias.map((categoria) => (
|
|
||||||
<option key={categoria.id_categoria} value={categoria.id_categoria}>
|
|
||||||
{categoria.categoria}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mb-3">
|
|
||||||
<label htmlFor="edificio" className="form-label mb-0">
|
|
||||||
Edificio
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
id="edificio"
|
|
||||||
value={filtro.edificio}
|
|
||||||
onChange={handleChange}
|
|
||||||
className="form-control me-2"
|
|
||||||
>
|
|
||||||
<option value="">Selecciona Edificio</option>
|
|
||||||
{edificios.map((edificio) => (
|
|
||||||
<option key={edificio.id_edificio} value={edificio.id_edificio}>
|
|
||||||
{edificio.edificio}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="d-flex flex-column gap-2 justify-content-between">
|
|
||||||
<button type="submit" className="btn btn-primary w-45">
|
|
||||||
Filtrar
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={handleClear}
|
|
||||||
className="btn btn-secondary w-45"
|
|
||||||
>
|
|
||||||
Limpiar Filtro
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -20,12 +20,12 @@ const LoginForm = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex-grow-1 d-flex flex-column justify-content-center align-items-center">
|
<div className="main-content">
|
||||||
<h1 className="text-warning">Bienvenido al directorio de profesores</h1>
|
<h1 className="text-warning">Bienvenido al directorio de profesores</h1>
|
||||||
<h2 className="m-3">Iniciar sesión</h2>
|
<h2 className="m-3">Iniciar sesión</h2>
|
||||||
<form
|
<form
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
className="bg-white p-4 rounded shadow-sm"
|
className="login-form"
|
||||||
style={{ background: "#f9f9f9", borderRadius: "1em" }}
|
style={{ background: "#f9f9f9", borderRadius: "1em" }}
|
||||||
>
|
>
|
||||||
<div className="input-group">
|
<div className="input-group">
|
||||||
@@ -62,20 +62,12 @@ const LoginForm = () => {
|
|||||||
Mantener la sesión
|
Mantener la sesión
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button type="submit" disabled={loading}>
|
||||||
type="submit"
|
|
||||||
disabled={loading}
|
|
||||||
className="btn btn-primary w-100"
|
|
||||||
>
|
|
||||||
Ingresar
|
Ingresar
|
||||||
</button>
|
</button>
|
||||||
{loading && <p>Cargando...</p>}
|
{loading && <p>Cargando...</p>}
|
||||||
|
{error && <p style={{ color: "red" }}>{error}</p>}
|
||||||
</form>
|
</form>
|
||||||
{error && (
|
|
||||||
<div className="alert alert-danger mt-3" role="alert">
|
|
||||||
{error}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -47,6 +47,12 @@
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
border: 2px solid rgb(77, 77, 77);
|
||||||
|
border-radius: 8px;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.notButton {
|
.notButton {
|
||||||
text-align: start;
|
text-align: start;
|
||||||
background: none;
|
background: none;
|
||||||
|
|||||||
@@ -1,288 +0,0 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import { useSearchParams, useNavigate } from "react-router-dom";
|
|
||||||
import Guard from "../guards/route.guard";
|
|
||||||
import { PrivateRoutes, PublicRoutes } from "../models/routes";
|
|
||||||
import { useDeleteTeacher } from "../services/teacher.services";
|
|
||||||
import "bootstrap/dist/css/bootstrap.min.css";
|
|
||||||
|
|
||||||
const API_URL = process.env.REACT_APP_API_URL;
|
|
||||||
|
|
||||||
export default function Profesores() {
|
|
||||||
const [showDialog, setShowDialog] = useState(false);
|
|
||||||
const [confirmText, setConfirmText] = useState("");
|
|
||||||
const [profesorToDelete, setProfesorToDelete] = useState(null); // Profesor que se va a eliminar
|
|
||||||
const { deleteTeacher } = useDeleteTeacher();
|
|
||||||
const permissions = Guard();
|
|
||||||
const [searchParams] = useSearchParams();
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const [profesores, setProfesores] = useState([]);
|
|
||||||
const [loading, setLoading] = useState(true);
|
|
||||||
const [totalPages, setTotalPages] = useState(1);
|
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
|
||||||
|
|
||||||
const fetchProfesores = async (filters) => {
|
|
||||||
const validFilters = Object.fromEntries(
|
|
||||||
Object.entries(filters).filter(([_, value]) => value)
|
|
||||||
);
|
|
||||||
|
|
||||||
const queryParams = new URLSearchParams(validFilters);
|
|
||||||
setLoading(true);
|
|
||||||
try {
|
|
||||||
const res = await (
|
|
||||||
await fetch(`${API_URL}/profesor/page?${queryParams}&limit=20`)
|
|
||||||
).json();
|
|
||||||
|
|
||||||
setProfesores(res.profesores);
|
|
||||||
setTotalPages(res.totalPages);
|
|
||||||
setCurrentPage(Number(filters.page) || 1);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const nombre = searchParams.get("nombre");
|
|
||||||
const adscripcion = searchParams.get("adscripcion");
|
|
||||||
const categoria = searchParams.get("categoria");
|
|
||||||
const edificio = searchParams.get("edificio");
|
|
||||||
const page = searchParams.get("page") || "1";
|
|
||||||
|
|
||||||
fetchProfesores({ nombre, adscripcion, categoria, edificio, page });
|
|
||||||
}, [searchParams]);
|
|
||||||
|
|
||||||
const handlePageChange = (pageNumber) => {
|
|
||||||
const newParams = new URLSearchParams(searchParams);
|
|
||||||
newParams.set("page", pageNumber);
|
|
||||||
navigate(`?${newParams.toString()}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Lógica para controlar las 5 páginas visibles
|
|
||||||
const getPageNumbers = () => {
|
|
||||||
const maxPagesToShow = 5;
|
|
||||||
let startPage, endPage;
|
|
||||||
|
|
||||||
if (totalPages <= maxPagesToShow) {
|
|
||||||
startPage = 1;
|
|
||||||
endPage = totalPages;
|
|
||||||
} else {
|
|
||||||
if (currentPage <= Math.ceil(maxPagesToShow / 2)) {
|
|
||||||
startPage = 1;
|
|
||||||
endPage = maxPagesToShow;
|
|
||||||
} else if (currentPage + Math.floor(maxPagesToShow / 2) >= totalPages) {
|
|
||||||
startPage = totalPages - maxPagesToShow + 1;
|
|
||||||
endPage = totalPages;
|
|
||||||
} else {
|
|
||||||
startPage = currentPage - Math.floor(maxPagesToShow / 2);
|
|
||||||
endPage = currentPage + Math.floor(maxPagesToShow / 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Array.from(
|
|
||||||
{ length: endPage - startPage + 1 },
|
|
||||||
(_, index) => startPage + index
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleEditClick = (id) => {
|
|
||||||
window.location.href = `${PrivateRoutes.EDITARPROFESOR}${id}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleViewProfesor = (id) => {
|
|
||||||
localStorage.setItem("lastPage", currentPage);
|
|
||||||
window.location.href = `${PublicRoutes.DATAPROFESOR}${id}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleConfirmDelete = async () => {
|
|
||||||
if (confirmText.toLowerCase() === "aceptar" && profesorToDelete) {
|
|
||||||
await deleteTeacher(profesorToDelete);
|
|
||||||
setShowDialog(false);
|
|
||||||
setConfirmText("");
|
|
||||||
setProfesorToDelete(null); // Resetear el profesor a eliminar
|
|
||||||
fetchProfesores({ page: currentPage }); // Refrescar la lista después de eliminar
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDeleteClick = (id) => {
|
|
||||||
setProfesorToDelete(id); // Guardar el profesor que se va a eliminar
|
|
||||||
setShowDialog(true); // Mostrar el modal
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="my-2 p-2 position-sticky">
|
|
||||||
{loading ? (
|
|
||||||
<p>Cargando profesores...</p>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{profesores.length > 0 ? (
|
|
||||||
<div className="row">
|
|
||||||
{profesores.map((profesor, index) => (
|
|
||||||
<div
|
|
||||||
key={index}
|
|
||||||
className="col-12 col-md-6 col-xl-4 mb-4"
|
|
||||||
style={{ cursor: "pointer" }}
|
|
||||||
onClick={() => handleViewProfesor(profesor.id_profesor)}
|
|
||||||
>
|
|
||||||
<div className="card h-100 shadow-sm">
|
|
||||||
<div className="card-body">
|
|
||||||
<div className="d-flex">
|
|
||||||
<img
|
|
||||||
src={
|
|
||||||
profesor.fotografia &&
|
|
||||||
profesor.fotografia.startsWith("http")
|
|
||||||
? profesor.fotografia
|
|
||||||
: `${API_URL}/imagenes/${profesor.fotografia}`
|
|
||||||
}
|
|
||||||
alt={profesor.nombre}
|
|
||||||
className="img-fluid rounded"
|
|
||||||
style={{
|
|
||||||
width: "80px",
|
|
||||||
height: "130px",
|
|
||||||
objectFit: "cover",
|
|
||||||
}}
|
|
||||||
onError={(e) => {
|
|
||||||
e.target.src = "/default-image.png"; // Imagen por defecto si no se carga
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<div className="ms-3">
|
|
||||||
<h5 className="card-title mb-1">{profesor.nombre}</h5>
|
|
||||||
<strong className="text-muted">Ubicacion</strong>
|
|
||||||
<p className="mb-1 text-muted text-start">
|
|
||||||
{profesor.ubicacion}
|
|
||||||
</p>
|
|
||||||
<strong className="text-muted">Correo</strong>
|
|
||||||
<p className="text-break text-muted text-start m-0">
|
|
||||||
{profesor.correo_pcp}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{permissions && (
|
|
||||||
<div className="card-footer d-flex gap-2">
|
|
||||||
<button
|
|
||||||
className="btn btn-primary"
|
|
||||||
onClick={() => handleEditClick(profesor.id_profesor)}
|
|
||||||
>
|
|
||||||
Editar
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="btn btn-danger"
|
|
||||||
onClick={() =>
|
|
||||||
handleDeleteClick(profesor.id_profesor)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Borrar
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<p>No se encontraron profesores.</p>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Modal de confirmación */}
|
|
||||||
{showDialog && (
|
|
||||||
<div
|
|
||||||
className="modal fade show"
|
|
||||||
tabIndex="-1"
|
|
||||||
style={{ display: "block" }}
|
|
||||||
role="dialog"
|
|
||||||
>
|
|
||||||
<div className="modal-dialog" role="document">
|
|
||||||
<div className="modal-content">
|
|
||||||
<div className="modal-header">
|
|
||||||
<h5 className="modal-title">Confirmar Eliminación</h5>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="btn-close"
|
|
||||||
onClick={() => setShowDialog(false)}
|
|
||||||
></button>
|
|
||||||
</div>
|
|
||||||
<div className="modal-body">
|
|
||||||
<p>
|
|
||||||
Para eliminar al profesor, escribe{" "}
|
|
||||||
<strong>"aceptar"</strong> y confirma.
|
|
||||||
</p>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="form-control"
|
|
||||||
value={confirmText}
|
|
||||||
onChange={(e) => setConfirmText(e.target.value)}
|
|
||||||
placeholder="Escribe 'aceptar' para confirmar"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="modal-footer">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="btn btn-secondary"
|
|
||||||
onClick={() => setShowDialog(false)}
|
|
||||||
>
|
|
||||||
Cancelar
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="btn btn-danger"
|
|
||||||
onClick={handleConfirmDelete}
|
|
||||||
disabled={confirmText.toLowerCase() !== "aceptar"}
|
|
||||||
>
|
|
||||||
Confirmar Eliminación
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Paginación con Bootstrap */}
|
|
||||||
<nav className="d-flex justify-content-center mt-3">
|
|
||||||
<ul className="pagination">
|
|
||||||
<li className={`page-item ${currentPage === 1 && "disabled"}`}>
|
|
||||||
<button
|
|
||||||
className="page-link"
|
|
||||||
onClick={() => handlePageChange(currentPage - 1)}
|
|
||||||
disabled={currentPage === 1}
|
|
||||||
>
|
|
||||||
Anterior
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
{getPageNumbers().map((pageNumber) => (
|
|
||||||
<li
|
|
||||||
key={pageNumber}
|
|
||||||
className={`page-item ${
|
|
||||||
pageNumber === currentPage ? "active" : ""
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
className="page-link"
|
|
||||||
onClick={() => handlePageChange(pageNumber)}
|
|
||||||
>
|
|
||||||
{pageNumber}
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
|
|
||||||
<li
|
|
||||||
className={`page-item ${
|
|
||||||
currentPage === totalPages && "disabled"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
className="page-link"
|
|
||||||
onClick={() => handlePageChange(currentPage + 1)}
|
|
||||||
disabled={currentPage === totalPages}
|
|
||||||
>
|
|
||||||
Siguiente
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -114,17 +114,17 @@ const FormProfesor = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!id_categoria) {
|
if (!id_categoria) {
|
||||||
alert("Por favor, Coloque la categoria en Datos de Investigación.");
|
alert("Por favor, Coloque la categoría en Datos académicos.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!id_adscripcion) {
|
if (!id_adscripcion) {
|
||||||
alert("Por favor, Coloque la adscripcion en Datos de Investigación.");
|
alert("Por favor, Coloque la adscripción en Datos académicos.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!id_edificio) {
|
if (!id_edificio) {
|
||||||
alert("Por favor, Coloque el edificio en Datos de Investigación.");
|
alert("Por favor, Coloque el edificio en Datos académicos.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,7 +225,7 @@ const FormProfesor = () => {
|
|||||||
return (
|
return (
|
||||||
<div className="form-container">
|
<div className="form-container">
|
||||||
<div className="containerButton">
|
<div className="containerButton">
|
||||||
<button className="btn btn-primary" onClick={handleRegresar}>
|
<button className="blueButton" onClick={handleRegresar}>
|
||||||
Regresar
|
Regresar
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -408,7 +408,7 @@ const FormProfesor = () => {
|
|||||||
|
|
||||||
{page === 3 && (
|
{page === 3 && (
|
||||||
<div className="form-section">
|
<div className="form-section">
|
||||||
<h2>Datos de Investigación</h2>
|
<h2>Datos Académicos</h2>
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label>
|
<label>
|
||||||
Categoría <span className="required">*</span>
|
Categoría <span className="required">*</span>
|
||||||
@@ -523,7 +523,7 @@ const FormProfesor = () => {
|
|||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn btn-danger"
|
className="delete-botones"
|
||||||
onClick={() => deleteGrados_obtenidos(index)}
|
onClick={() => deleteGrados_obtenidos(index)}
|
||||||
></button>
|
></button>
|
||||||
</div>
|
</div>
|
||||||
@@ -535,19 +535,19 @@ const FormProfesor = () => {
|
|||||||
className="boton"
|
className="boton"
|
||||||
onClick={addGrados_obtenidos}
|
onClick={addGrados_obtenidos}
|
||||||
>
|
>
|
||||||
Agregar Grados de investigacion
|
Agregar Grados
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{page === 5 && (
|
{page === 5 && (
|
||||||
<div className="form-section">
|
<div className="form-section">
|
||||||
<h2>Lineas de Investigacion</h2>
|
<h2>Líneas de Investigación</h2>
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
{lineasInvestigacion.map((linea, index) => (
|
{lineasInvestigacion.map((linea, index) => (
|
||||||
<div key={index} className="input-with-delete">
|
<div key={index} className="input-with-delete">
|
||||||
<label>
|
<label>
|
||||||
Linea de Investigacion {index + 1}
|
Línea de Investigación {index + 1}
|
||||||
<span className="required">*</span>
|
<span className="required">*</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ const FormEditProfesor = () => {
|
|||||||
return (
|
return (
|
||||||
<div className="form-container">
|
<div className="form-container">
|
||||||
<div className="containerButton">
|
<div className="containerButton">
|
||||||
<button className="btn btn-primary" onClick={handleRegresar}>
|
<button className="blueButton" onClick={handleRegresar}>
|
||||||
Regresar
|
Regresar
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -393,7 +393,7 @@ const FormEditProfesor = () => {
|
|||||||
|
|
||||||
{page === 3 && (
|
{page === 3 && (
|
||||||
<div className="form-section">
|
<div className="form-section">
|
||||||
<h2>Datos de Investigación</h2>
|
<h2>Datos académicos</h2>
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label>
|
<label>
|
||||||
Categoría <span className="required">*</span>
|
Categoría <span className="required">*</span>
|
||||||
@@ -528,26 +528,25 @@ const FormEditProfesor = () => {
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="d-flex justify-content-center">
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn btn-primary"
|
className="boton"
|
||||||
onClick={addGrados_obtenidos}
|
onClick={addGrados_obtenidos}
|
||||||
>
|
>
|
||||||
Agregar Grados de investigacion
|
Agregar Grados
|
||||||
</button>
|
</button>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{page === 5 && (
|
{page === 5 && (
|
||||||
<div className="form-section">
|
<div className="form-section">
|
||||||
<h2>Lineas de Investigacion</h2>
|
<h2>Líneas de Investigación</h2>
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
{lineasInvestigacion.map((linea, index) => (
|
{lineasInvestigacion.map((linea, index) => (
|
||||||
<div key={index} className="input-with-delete">
|
<div key={index} className="input-with-delete">
|
||||||
<label>
|
<label>
|
||||||
Lineas de Investigacion {index + 1}
|
Líneas de Investigación {index + 1}
|
||||||
<span className="required">*</span>
|
<span className="required">*</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ const PerfilProfesor = () => {
|
|||||||
return (
|
return (
|
||||||
<div className="form-container">
|
<div className="form-container">
|
||||||
<div className="containerButton">
|
<div className="containerButton">
|
||||||
<button className="btn btn-primary" onClick={handleRegresar}>
|
<button className="blueButton" onClick={handleRegresar}>
|
||||||
Regresar
|
Regresar
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -123,23 +123,23 @@ const PerfilProfesor = () => {
|
|||||||
</div>
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<strong>Ubicación: </strong>
|
<strong>Ubicación:</strong>
|
||||||
{profesor.ubicacion ? profesor.ubicacion : "NO ubicado"}
|
{profesor.ubicacion ? profesor.ubicacion : "NO ubicado"}
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<strong>Correo: </strong>
|
<strong>Correo:</strong>
|
||||||
{profesor.correo_pcp ? profesor.correo_pcp : "No ubicado"}
|
{profesor.correo_pcp ? profesor.correo_pcp : "No ubicado"}
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<strong>Teléfono de oficina: </strong>
|
<strong>Teléfono de oficina:</strong>
|
||||||
{profesor.tel_oficina ? profesor.tel_oficina : "No ubicado"}
|
{profesor.tel_oficina ? profesor.tel_oficina : "No ubicado"}
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<strong>Extensión: </strong>
|
<strong>Extensión:</strong>
|
||||||
{profesor.extension ? profesor.extension : "No ubicado"}
|
{profesor.extension ? profesor.extension : "No ubicado"}
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<strong>Edificio: </strong>
|
<strong>Edificio:</strong>
|
||||||
{edificioProfesor ? edificioProfesor.edificio : "No ubicado"}
|
{edificioProfesor ? edificioProfesor.edificio : "No ubicado"}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import Filter from "../../components/Filter";
|
|
||||||
import Profesores from "../../components/Profesores";
|
|
||||||
|
|
||||||
export default function HomeView() {
|
|
||||||
return (
|
|
||||||
<div className="container-fluid">
|
|
||||||
<div className="row">
|
|
||||||
<aside className="col-12 col-lg-3">
|
|
||||||
<Filter />
|
|
||||||
</aside>
|
|
||||||
<main className="col-12 col-lg-9">
|
|
||||||
<Profesores />
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user