Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c10a3c4b8e | |||
| bbb453bc6c | |||
| 44d5c8c60c | |||
| b9bc44b921 | |||
| c428cfcee4 | |||
| 996f6dc438 | |||
| 4493a0834c | |||
| e74619ae19 | |||
| 05b8abab76 | |||
| a919023851 | |||
| b9179d6c37 | |||
| f5c1ba8d66 | |||
| 197c035356 | |||
| b7a0f48905 | |||
| d576242bce | |||
| fe697f015b | |||
| f8650adc93 | |||
| f6878085ee | |||
| 7256791a25 | |||
| 2b86b0e02c | |||
| a56e589812 | |||
| 0ccd68674e | |||
| 4884eaca64 | |||
| d72959ddc2 | |||
| 8020d9671b | |||
| 3513fcb693 |
@@ -1,2 +1,2 @@
|
|||||||
REACT_APP_API_URL=http://192.168.100.7:3000
|
REACT_APP_API_URL=https://venus.acatlan.unam.mx/directorio_test
|
||||||
REACT_APP_PORT=3001
|
REACT_APP_PORT=3001
|
||||||
|
|||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<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>
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
+2
-64
@@ -109,17 +109,6 @@
|
|||||||
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;
|
||||||
}
|
}
|
||||||
@@ -238,24 +227,6 @@ 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;
|
||||||
@@ -315,42 +286,9 @@ 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);
|
||||||
@@ -396,7 +334,7 @@ body {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
min-width: 100vw;
|
background-color: #f5f5f7;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2.text-warning {
|
h2.text-warning {
|
||||||
@@ -423,7 +361,7 @@ p .text-center .mt-3 {
|
|||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
width: 400px;
|
width: 400px;
|
||||||
max-width: 90vw;
|
max-width: 90vw;
|
||||||
margin: 10px;
|
margin: 10px auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cargando {
|
.cargando {
|
||||||
|
|||||||
+3
-2
@@ -26,10 +26,11 @@ 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 />
|
||||||
@@ -59,7 +60,7 @@ const App = () => {
|
|||||||
path={`${PublicRoutes.DATAPROFESOR}:id_profesor`}
|
path={`${PublicRoutes.DATAPROFESOR}:id_profesor`}
|
||||||
element={<PerfilProfesor />}
|
element={<PerfilProfesor />}
|
||||||
/>
|
/>
|
||||||
<Route path={PublicRoutes.FILTER} element={<FilterProfesor />} />
|
<Route path={PublicRoutes.FILTER} element={<HomeView />} />
|
||||||
|
|
||||||
{!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 />} />
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 254 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -1,22 +1,18 @@
|
|||||||
.card {
|
|
||||||
max-width: 90vw;
|
|
||||||
width: 400px;
|
.transition{
|
||||||
height: 175px;
|
opacity: 0;
|
||||||
margin: auto;
|
transform: translateY(20px);
|
||||||
padding: 0.5em;
|
transition: opacity 0.5s ease-out, transform 0.5s ease-out;
|
||||||
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, transform 0.3s ease;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.card:hover {
|
.transition.show {
|
||||||
box-shadow: 0 8px 16px 4px rgba(0, 0, 0, 0.2);
|
display: flex;
|
||||||
transform: translateY(-5px);
|
justify-content: center;
|
||||||
|
width: 40vw;
|
||||||
|
min-width: 340px;
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-content {
|
.card-content {
|
||||||
@@ -37,6 +33,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
max-width: 130px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -56,4 +53,10 @@
|
|||||||
|
|
||||||
.status-label.inactive {
|
.status-label.inactive {
|
||||||
background-color: red;
|
background-color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profesores-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
@@ -3,13 +3,19 @@ import "../Card.css";
|
|||||||
import { PrivateRoutes, PublicRoutes } from "../../../models/routes";
|
import { PrivateRoutes, PublicRoutes } from "../../../models/routes";
|
||||||
import { useDeleteTeacher } from "../../../services/teacher.services";
|
import { useDeleteTeacher } from "../../../services/teacher.services";
|
||||||
|
|
||||||
const CardProfesor = ({ profesor, edificioNombre, permissions }) => {
|
const API_URL = process.env.REACT_APP_API_URL;
|
||||||
|
|
||||||
|
const CardProfesor = ({
|
||||||
|
profesor,
|
||||||
|
edificioNombre,
|
||||||
|
permissions,
|
||||||
|
currentPage,
|
||||||
|
}) => {
|
||||||
const [showDialog, setShowDialog] = useState(false);
|
const [showDialog, setShowDialog] = useState(false);
|
||||||
const [confirmText, setConfirmText] = useState("");
|
const [confirmText, setConfirmText] = useState("");
|
||||||
const { deleteTeacher } = useDeleteTeacher();
|
const { deleteTeacher } = useDeleteTeacher();
|
||||||
const defaultImage =
|
const defaultImage =
|
||||||
"https://static.vecteezy.com/system/resources/thumbnails/020/765/399/small_2x/default-profile-account-unknown-icon-black-silhouette-free-vector.jpg";
|
"https://static.vecteezy.com/system/resources/thumbnails/020/765/399/small_2x/default-profile-account-unknown-icon-black-silhouette-free-vector.jpg";
|
||||||
const fotoProfesor = profesor.fotografia || defaultImage;
|
|
||||||
|
|
||||||
const handleDeleteClick = () => {
|
const handleDeleteClick = () => {
|
||||||
setShowDialog(true);
|
setShowDialog(true);
|
||||||
@@ -28,20 +34,28 @@ const CardProfesor = ({ profesor, edificioNombre, permissions }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleViewProfesor = () => {
|
const handleViewProfesor = () => {
|
||||||
|
localStorage.setItem("lastPage", currentPage);
|
||||||
window.location.href = `${PublicRoutes.DATAPROFESOR}${profesor.id_profesor}`;
|
window.location.href = `${PublicRoutes.DATAPROFESOR}${profesor.id_profesor}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleImageError = (e) => {
|
||||||
|
e.target.src = defaultImage;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="card m-1">
|
<div className="card m-1">
|
||||||
<div className="image">
|
<div className="image">
|
||||||
{fotoProfesor && fotoProfesor.startsWith("http") ? (
|
<img
|
||||||
<img
|
src={
|
||||||
src={fotoProfesor}
|
profesor.fotografia && profesor.fotografia.startsWith("http")
|
||||||
className="imgProfe"
|
? profesor.fotografia
|
||||||
alt={profesor.nombre}
|
: `${API_URL}/imagenes/${profesor.fotografia}`
|
||||||
onClick={handleViewProfesor}
|
}
|
||||||
/>
|
className="imgProfe"
|
||||||
) : null}
|
alt={profesor.nombre}
|
||||||
|
onClick={handleViewProfesor}
|
||||||
|
onError={handleImageError}
|
||||||
|
/>
|
||||||
|
|
||||||
{permissions ? (
|
{permissions ? (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -29,9 +29,4 @@
|
|||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-control,
|
|
||||||
.btn {
|
|
||||||
width: 100%;
|
|
||||||
margin: 5px 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ 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(
|
||||||
|
Number(localStorage.getItem("lastPage")) || 1
|
||||||
|
);
|
||||||
|
|
||||||
const handleSubmit = (e) => {
|
const handleSubmit = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -25,86 +28,22 @@ function FilterProfesor() {
|
|||||||
categoria,
|
categoria,
|
||||||
edificio,
|
edificio,
|
||||||
});
|
});
|
||||||
|
setCurrentPage(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="main">
|
<div>
|
||||||
<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="">Adscripcion</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="">Categoria</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: "#1e3c70", color: "#fff" }}
|
|
||||||
>
|
|
||||||
Buscar
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<Mapeo filters={filters} edificios={edificios} />
|
<Mapeo
|
||||||
|
filters={filters}
|
||||||
|
edificios={edificios}
|
||||||
|
currentPage={currentPage}
|
||||||
|
setCurrentPage={setCurrentPage}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import "../../../App.css";
|
import "../../../App.css";
|
||||||
import CardProfesor from "./CardProfesor";
|
import CardProfesor from "./CardProfesor";
|
||||||
import Guard from "../../../guards/route.guard";
|
import Guard from "../../../guards/route.guard";
|
||||||
@@ -8,8 +8,8 @@ import {
|
|||||||
} from "../../../services/teacher.services";
|
} from "../../../services/teacher.services";
|
||||||
import { PrivateRoutes } from "../../../models/routes";
|
import { PrivateRoutes } from "../../../models/routes";
|
||||||
|
|
||||||
const Mapeo = ({ filters, edificios }) => {
|
const Mapeo = ({ filters, edificios, currentPage, setCurrentPage }) => {
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [shownCards, setShownCards] = useState([]);
|
||||||
const permissions = Guard();
|
const permissions = Guard();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -18,6 +18,7 @@ const Mapeo = ({ filters, edificios }) => {
|
|||||||
loading: loadingData,
|
loading: loadingData,
|
||||||
error: errorData,
|
error: errorData,
|
||||||
} = useTeachers(currentPage, filters);
|
} = useTeachers(currentPage, filters);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
profesores: profesoresActivesData,
|
profesores: profesoresActivesData,
|
||||||
totalPages: totalActivePages,
|
totalPages: totalActivePages,
|
||||||
@@ -25,6 +26,50 @@ const Mapeo = ({ filters, edificios }) => {
|
|||||||
error: errorActives,
|
error: errorActives,
|
||||||
} = useTeachersActives(currentPage, filters);
|
} = useTeachersActives(currentPage, filters);
|
||||||
|
|
||||||
|
const { profesores, totalPages } = permissions
|
||||||
|
? { profesores: profesoresData, totalPages: totalDataPages }
|
||||||
|
: { profesores: profesoresActivesData, totalPages: totalActivePages };
|
||||||
|
|
||||||
|
const [maxPagesToShow, setMaxPagesToShow] = useState(10);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const updateMaxPagesToShow = () => {
|
||||||
|
if (window.innerWidth < 650) {
|
||||||
|
setMaxPagesToShow(5);
|
||||||
|
} else {
|
||||||
|
setMaxPagesToShow(10);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener("resize", updateMaxPagesToShow);
|
||||||
|
updateMaxPagesToShow();
|
||||||
|
return () => window.removeEventListener("resize", updateMaxPagesToShow);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const storedPage = localStorage.getItem("lastPage");
|
||||||
|
if (storedPage) {
|
||||||
|
localStorage.removeItem("lastPage");
|
||||||
|
}
|
||||||
|
}, [setCurrentPage]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loadingData && !loadingActives && profesores) {
|
||||||
|
setShownCards([]);
|
||||||
|
profesores.forEach((_, index) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
setShownCards((prev) => [...prev, index]);
|
||||||
|
}, index * 120);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loadingData, loadingActives, profesores, currentPage]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
window.scrollTo({ top: 0, behavior: "smooth" });
|
||||||
|
}, 100);
|
||||||
|
}, [currentPage]);
|
||||||
|
|
||||||
if (loadingData || loadingActives) {
|
if (loadingData || loadingActives) {
|
||||||
return (
|
return (
|
||||||
<div className="perfil-profesor">
|
<div className="perfil-profesor">
|
||||||
@@ -49,10 +94,6 @@ const Mapeo = ({ filters, edificios }) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { profesores, totalPages } = permissions
|
|
||||||
? { profesores: profesoresData, totalPages: totalDataPages }
|
|
||||||
: { profesores: profesoresActivesData, totalPages: totalActivePages };
|
|
||||||
|
|
||||||
const handleNextPage = () => {
|
const handleNextPage = () => {
|
||||||
if (currentPage < totalPages) {
|
if (currentPage < totalPages) {
|
||||||
setCurrentPage((prevPage) => prevPage + 1);
|
setCurrentPage((prevPage) => prevPage + 1);
|
||||||
@@ -67,7 +108,6 @@ const Mapeo = ({ filters, edificios }) => {
|
|||||||
|
|
||||||
const renderPageNumbers = () => {
|
const renderPageNumbers = () => {
|
||||||
const pageNumbers = [];
|
const pageNumbers = [];
|
||||||
const maxPagesToShow = 5;
|
|
||||||
let startPage = Math.max(1, currentPage - Math.floor(maxPagesToShow / 2));
|
let startPage = Math.max(1, currentPage - Math.floor(maxPagesToShow / 2));
|
||||||
let endPage = Math.min(totalPages, startPage + maxPagesToShow - 1);
|
let endPage = Math.min(totalPages, startPage + maxPagesToShow - 1);
|
||||||
|
|
||||||
@@ -103,10 +143,10 @@ const Mapeo = ({ filters, edificios }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="main-content">
|
<div className="">
|
||||||
{permissions ? (
|
{permissions ? (
|
||||||
<div className="containerButton">
|
<div className="containerButton">
|
||||||
<button className="blueButton" onClick={handleRegresar}>
|
<button className="btn btn-primary" onClick={handleRegresar}>
|
||||||
Regresar
|
Regresar
|
||||||
</button>
|
</button>
|
||||||
<button className="blueButton" onClick={handleCrear}>
|
<button className="blueButton" onClick={handleCrear}>
|
||||||
@@ -114,22 +154,36 @@ const Mapeo = ({ filters, edificios }) => {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
<div className="container border">
|
||||||
{profesores.map((profesor) => {
|
<div className="row">
|
||||||
const edificio = edificios.find(
|
{profesores.map((profesor, index) => (
|
||||||
(e) => e.id_edificio === profesor.id_edificio
|
<div className="col-4">{profesor.nombre}</div>
|
||||||
);
|
))}
|
||||||
const edificioNombre = edificio ? edificio.edificio : "Desconocido";
|
</div>
|
||||||
return (
|
</div>
|
||||||
<CardProfesor
|
{/* <div className="profesores-container">
|
||||||
key={profesor.id_profesor}
|
{profesores.map((profesor, index) => {
|
||||||
profesor={profesor}
|
const edificio = edificios.find(
|
||||||
edificioNombre={edificioNombre}
|
(e) => e.id_edificio === profesor.id_edificio
|
||||||
permissions={permissions}
|
);
|
||||||
/>
|
const edificioNombre = edificio ? edificio.edificio : "Desconocido";
|
||||||
);
|
return (
|
||||||
})}
|
<div
|
||||||
|
key={profesor.id_profesor}
|
||||||
|
className={`card-wrapper transition ${
|
||||||
|
shownCards.includes(index) ? "show" : ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<CardProfesor
|
||||||
|
profesor={profesor}
|
||||||
|
edificioNombre={edificioNombre}
|
||||||
|
permissions={permissions}
|
||||||
|
currentPage={currentPage}
|
||||||
|
/>
|
||||||
|
</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" : ""}`}>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import "../../../App.css";
|
import "../../../App.css";
|
||||||
import CardUsuario from "./CardUsuario";
|
import CardUsuario from "./CardUsuario";
|
||||||
import { PrivateRoutes } from "../../../models/routes";
|
import { PrivateRoutes } from "../../../models/routes";
|
||||||
@@ -8,6 +8,25 @@ const MapeoUsuario = ({ filters }) => {
|
|||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
const { usuarios, totalPages } = useUsers(currentPage, filters);
|
const { usuarios, totalPages } = useUsers(currentPage, filters);
|
||||||
|
|
||||||
|
const [maxPagesToShow, setMaxPagesToShow] = useState(10);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const updateMaxPagesToShow = () => {
|
||||||
|
if (window.innerWidth < 650) {
|
||||||
|
setMaxPagesToShow(5);
|
||||||
|
} else {
|
||||||
|
setMaxPagesToShow(10);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener("resize", updateMaxPagesToShow);
|
||||||
|
|
||||||
|
updateMaxPagesToShow();
|
||||||
|
|
||||||
|
return () => window.removeEventListener("resize", updateMaxPagesToShow);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
if (totalPages === 0) {
|
if (totalPages === 0) {
|
||||||
return (
|
return (
|
||||||
<div className="perfil-profesor">
|
<div className="perfil-profesor">
|
||||||
@@ -36,7 +55,6 @@ const MapeoUsuario = ({ filters }) => {
|
|||||||
|
|
||||||
const renderPageNumbers = () => {
|
const renderPageNumbers = () => {
|
||||||
const pageNumbers = [];
|
const pageNumbers = [];
|
||||||
const maxPagesToShow = 5;
|
|
||||||
let startPage = Math.max(1, currentPage - Math.floor(maxPagesToShow / 2));
|
let startPage = Math.max(1, currentPage - Math.floor(maxPagesToShow / 2));
|
||||||
let endPage = Math.min(totalPages, startPage + maxPagesToShow - 1);
|
let endPage = Math.min(totalPages, startPage + maxPagesToShow - 1);
|
||||||
|
|
||||||
@@ -74,10 +92,10 @@ const MapeoUsuario = ({ filters }) => {
|
|||||||
return (
|
return (
|
||||||
<div className="main-content">
|
<div className="main-content">
|
||||||
<div className="containerButton">
|
<div className="containerButton">
|
||||||
<button className="blueButton" onClick={handleRegresar}>
|
<button className="btn btn-primary" onClick={handleRegresar}>
|
||||||
Regresar
|
Regresar
|
||||||
</button>
|
</button>
|
||||||
<button className="blueButton" onClick={handleCrear}>
|
<button className="btn btn-primary" onClick={handleCrear}>
|
||||||
Crear Usuario
|
Crear Usuario
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ function NavUsuario() {
|
|||||||
<button
|
<button
|
||||||
className="btn me-2"
|
className="btn me-2"
|
||||||
type="submit"
|
type="submit"
|
||||||
style={{ background: "#1e3c70", color: "#fff" }}
|
style={{ background: "#D59F0F", color: "#fff" }}
|
||||||
>
|
>
|
||||||
Buscar
|
Buscar
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -0,0 +1,160 @@
|
|||||||
|
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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,23 +1,17 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import "./style.css";
|
import "./style.css";
|
||||||
|
import logo1 from "../assets/img/escudo-b2.png"; // Ajusta la ruta si es necesario
|
||||||
|
import logo2 from "../assets/img/logo_unam-b.png"; // Ajusta la ruta si es necesario
|
||||||
|
|
||||||
const Header = () => {
|
const Header = () => {
|
||||||
return (
|
return (
|
||||||
<header className="header">
|
<header className="header">
|
||||||
<a href="https://www.unam.mx/">
|
<a href="https://www.unam.mx/">
|
||||||
<img
|
<img className="logo" alt="Logo 1" src={logo1} />
|
||||||
className="logo"
|
|
||||||
alt="Logo 1"
|
|
||||||
src="https://www.unam.mx/sites/all/themes/unam/logo.png"
|
|
||||||
/>
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="https://www.acatlan.unam.mx/">
|
<a href="https://www.acatlan.unam.mx/">
|
||||||
<img
|
<img className="logo" alt="Logo 2" src={logo2} />
|
||||||
className="logo"
|
|
||||||
alt="Logo 2"
|
|
||||||
src="https://www.acatlan.unam.mx/img/logo_fesa.png"
|
|
||||||
/>
|
|
||||||
</a>
|
</a>
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -20,12 +20,12 @@ const LoginForm = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="main-content">
|
<div className="flex-grow-1 d-flex flex-column justify-content-center align-items-center">
|
||||||
<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="login-form"
|
className="bg-white p-4 rounded shadow-sm"
|
||||||
style={{ background: "#f9f9f9", borderRadius: "1em" }}
|
style={{ background: "#f9f9f9", borderRadius: "1em" }}
|
||||||
>
|
>
|
||||||
<div className="input-group">
|
<div className="input-group">
|
||||||
@@ -62,12 +62,20 @@ const LoginForm = () => {
|
|||||||
Mantener la sesión
|
Mantener la sesión
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" disabled={loading}>
|
<button
|
||||||
|
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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
.nav-link .bg-warning {
|
.nav-link {
|
||||||
background-color: #002b7a !important;
|
|
||||||
color: #212529 !important;
|
color: #212529 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,14 +41,21 @@
|
|||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.red{
|
.red {
|
||||||
background-color: rgb(193, 17, 17);
|
background-color: rgb(193, 17, 17);
|
||||||
color: white;
|
color: white;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container{
|
.notButton {
|
||||||
border: 2px solid rgb(77, 77, 77);
|
text-align: start;
|
||||||
border-radius: 8px;
|
background: none;
|
||||||
margin: 10px;
|
border: none;
|
||||||
}
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notButton:hover{
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|||||||
+12
-12
@@ -92,47 +92,47 @@ const Menu = () => {
|
|||||||
|
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<li className="nav-item">
|
<li className="nav-item">
|
||||||
<a
|
<button
|
||||||
className="nav-link"
|
className="nav-link notButton"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
(window.location.href = PrivateRoutes.CREARPROFESOR)
|
(window.location.href = PrivateRoutes.CREARPROFESOR)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Crear Profesor
|
Crear Profesor
|
||||||
</a>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li className="nav-item">
|
<li className="nav-item">
|
||||||
<a
|
<button
|
||||||
className="nav-link"
|
className="nav-link notButton"
|
||||||
onClick={() => (window.location.href = PublicRoutes.FILTER)}
|
onClick={() => (window.location.href = PublicRoutes.FILTER)}
|
||||||
>
|
>
|
||||||
Editar Profesor
|
Editar Profesor
|
||||||
</a>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{permissions === 1 && (
|
{permissions === 1 && (
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<li className="nav-item">
|
<li className="nav-item">
|
||||||
<a
|
<button
|
||||||
className="nav-link"
|
className="nav-link notButton"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
(window.location.href = PrivateRoutes.CREARUSUARIO)
|
(window.location.href = PrivateRoutes.CREARUSUARIO)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Crear Usuario
|
Crear Usuario
|
||||||
</a>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li className="nav-item">
|
<li className="nav-item">
|
||||||
<a
|
<button
|
||||||
className="nav-link"
|
className="nav-link notButton"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
(window.location.href = PrivateRoutes.FILTERUSUARIO)
|
(window.location.href = PrivateRoutes.FILTERUSUARIO)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Editar Usuario
|
Editar Usuario
|
||||||
</a>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -0,0 +1,288 @@
|
|||||||
|
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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -7,7 +7,8 @@ import {
|
|||||||
useEdificio,
|
useEdificio,
|
||||||
useUploadImage,
|
useUploadImage,
|
||||||
} from "../../../services/auth.services";
|
} from "../../../services/auth.services";
|
||||||
import { useRegisterTeacher } from "../../../services/teacher.services";
|
import { useRegisterTeacher, useUpdateTeacherImage } from "../../../services/teacher.services";
|
||||||
|
import { PublicRoutes } from "../../../models/routes";
|
||||||
|
|
||||||
const FormProfesor = () => {
|
const FormProfesor = () => {
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
@@ -24,6 +25,7 @@ const FormProfesor = () => {
|
|||||||
const [fotoBase64, setFotoBase64] = useState("");
|
const [fotoBase64, setFotoBase64] = useState("");
|
||||||
const [lineasInvestigacion, setLineasInvestigacion] = useState([]);
|
const [lineasInvestigacion, setLineasInvestigacion] = useState([]);
|
||||||
const [proyectosAcademicos, setProyectosAcademicos] = useState([]);
|
const [proyectosAcademicos, setProyectosAcademicos] = useState([]);
|
||||||
|
const [datosAcademicos,setDatosAcademicos] = useState([]);
|
||||||
const [id_usuario] = useState("1");
|
const [id_usuario] = useState("1");
|
||||||
const [num_trabajador, setNum_trabajador] = useState("");
|
const [num_trabajador, setNum_trabajador] = useState("");
|
||||||
const [rfc, setRfc] = useState("");
|
const [rfc, setRfc] = useState("");
|
||||||
@@ -37,15 +39,21 @@ const FormProfesor = () => {
|
|||||||
const [mostrar, setMostrar] = useState(true);
|
const [mostrar, setMostrar] = useState(true);
|
||||||
const [nombre, setNombre] = useState("");
|
const [nombre, setNombre] = useState("");
|
||||||
const [grado_maximo, setGrado_maximo] = useState("");
|
const [grado_maximo, setGrado_maximo] = useState("");
|
||||||
const [grados_obtenidos, setGrados_obtenidos] = useState("");
|
|
||||||
|
|
||||||
const { registerTeacher } = useRegisterTeacher();
|
const { registerTeacher } = useRegisterTeacher();
|
||||||
|
const { updateTeacherImage } = useUpdateTeacherImage();
|
||||||
const { uploadImage } = useUploadImage();
|
const { uploadImage } = useUploadImage();
|
||||||
|
|
||||||
const handlePageChange = (newPage) => {
|
const handlePageChange = (newPage) => {
|
||||||
setPage(newPage);
|
setPage(newPage);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleGrados_obtenidosChange = (index, value) => {
|
||||||
|
const newGrados = [...datosAcademicos];
|
||||||
|
newGrados[index].grados_obtenidos = value;
|
||||||
|
setDatosAcademicos(newGrados);
|
||||||
|
};
|
||||||
|
|
||||||
const handleLineaInvestigacionChange = (index, value) => {
|
const handleLineaInvestigacionChange = (index, value) => {
|
||||||
const newLineas = [...lineasInvestigacion];
|
const newLineas = [...lineasInvestigacion];
|
||||||
newLineas[index].lineas_inv_html = value;
|
newLineas[index].lineas_inv_html = value;
|
||||||
@@ -58,6 +66,10 @@ const FormProfesor = () => {
|
|||||||
setProyectosAcademicos(newProyectos);
|
setProyectosAcademicos(newProyectos);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const addGrados_obtenidos = () => {
|
||||||
|
setDatosAcademicos([...datosAcademicos, { grados_obtenidos: "" }]);
|
||||||
|
};
|
||||||
|
|
||||||
const addLineaInvestigacion = () => {
|
const addLineaInvestigacion = () => {
|
||||||
setLineasInvestigacion([...lineasInvestigacion, { lineas_inv_html: "" }]);
|
setLineasInvestigacion([...lineasInvestigacion, { lineas_inv_html: "" }]);
|
||||||
};
|
};
|
||||||
@@ -66,6 +78,11 @@ const FormProfesor = () => {
|
|||||||
setProyectosAcademicos([...proyectosAcademicos, { proyecto_html: "" }]);
|
setProyectosAcademicos([...proyectosAcademicos, { proyecto_html: "" }]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const deleteGrados_obtenidos = (index) => {
|
||||||
|
const newGrados = datosAcademicos.filter((_, i) => i !== index);
|
||||||
|
setDatosAcademicos(newGrados);
|
||||||
|
};
|
||||||
|
|
||||||
const deleteLineaInvestigacion = (index) => {
|
const deleteLineaInvestigacion = (index) => {
|
||||||
const newLineas = lineasInvestigacion.filter((_, i) => i !== index);
|
const newLineas = lineasInvestigacion.filter((_, i) => i !== index);
|
||||||
setLineasInvestigacion(newLineas);
|
setLineasInvestigacion(newLineas);
|
||||||
@@ -89,7 +106,7 @@ const FormProfesor = () => {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!grado_maximo || !grados_obtenidos || !correo_pcp) {
|
if (!grado_maximo || !correo_pcp) {
|
||||||
alert(
|
alert(
|
||||||
"Por favor, complete todos los campos requeridos en Datos Académicos."
|
"Por favor, complete todos los campos requeridos en Datos Académicos."
|
||||||
);
|
);
|
||||||
@@ -116,19 +133,15 @@ const FormProfesor = () => {
|
|||||||
|
|
||||||
const handleSubmit = async (event) => {
|
const handleSubmit = async (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
if (!validateForm()) {
|
if (!validateForm()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let imageUrl = "";
|
let imageUrl = "";
|
||||||
|
|
||||||
if (fotoBase64) {
|
const id_profesor = await registerTeacher({
|
||||||
imageUrl = await uploadImage(fotoBase64, nombre);
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
nombre,
|
nombre,
|
||||||
id_usuario,
|
id_usuario,
|
||||||
num_trabajador,
|
num_trabajador,
|
||||||
@@ -147,16 +160,23 @@ const FormProfesor = () => {
|
|||||||
activo,
|
activo,
|
||||||
lineasInvestigacion,
|
lineasInvestigacion,
|
||||||
proyectosAcademicos,
|
proyectosAcademicos,
|
||||||
datosAcademicos: [
|
datosAcademicos: datosAcademicos.map(dato => ({
|
||||||
{
|
...dato,
|
||||||
grado_maximo,
|
grado_maximo: grado_maximo || dato.grado_maximo
|
||||||
grados_obtenidos,
|
})),
|
||||||
},
|
|
||||||
],
|
|
||||||
fotografia: imageUrl,
|
fotografia: imageUrl,
|
||||||
};
|
});
|
||||||
|
|
||||||
registerTeacher(data);
|
if (fotoBase64) {
|
||||||
|
imageUrl = await uploadImage(fotoBase64, id_profesor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imageUrl) {
|
||||||
|
await updateTeacherImage(id_profesor, imageUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.location.href = PublicRoutes.FILTER;
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.status === 403) {
|
if (error.response && error.response.status === 403) {
|
||||||
if (error.response.data.message === "RFC already exists") {
|
if (error.response.data.message === "RFC already exists") {
|
||||||
@@ -178,6 +198,7 @@ const FormProfesor = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const onDrop = useCallback((acceptedFiles) => {
|
const onDrop = useCallback((acceptedFiles) => {
|
||||||
const file = acceptedFiles[0];
|
const file = acceptedFiles[0];
|
||||||
@@ -204,7 +225,7 @@ const FormProfesor = () => {
|
|||||||
return (
|
return (
|
||||||
<div className="form-container">
|
<div className="form-container">
|
||||||
<div className="containerButton">
|
<div className="containerButton">
|
||||||
<button className="blueButton" onClick={handleRegresar}>
|
<button className="btn btn-primary" onClick={handleRegresar}>
|
||||||
Regresar
|
Regresar
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -305,19 +326,6 @@ const FormProfesor = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="form-group">
|
|
||||||
<label>
|
|
||||||
Grados Obtenidos <span className="required">*</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
name="grados_obtenidos"
|
|
||||||
required
|
|
||||||
value={grados_obtenidos}
|
|
||||||
onChange={(e) => setGrados_obtenidos(e.target.value)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label>
|
<label>
|
||||||
Correo Pcpuma <span className="required">*</span>
|
Correo Pcpuma <span className="required">*</span>
|
||||||
@@ -496,19 +504,56 @@ const FormProfesor = () => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{page === 4 && (
|
{page === 4 && (
|
||||||
|
<div className="form-section">
|
||||||
|
<h2>Grados obtenidos</h2>
|
||||||
|
<div className="form-group">
|
||||||
|
{datosAcademicos.map((grado, index) => (
|
||||||
|
<div key={index} className="input-with-delete">
|
||||||
|
<label>
|
||||||
|
Grado obtenido {index + 1}
|
||||||
|
<span className="required">*</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name={`grados_obtenidos_${index}`}
|
||||||
|
value={grado.grados_obtenidos}
|
||||||
|
onChange={(e) =>
|
||||||
|
handleGrados_obtenidosChange(index, e.target.value)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-danger"
|
||||||
|
onClick={() => deleteGrados_obtenidos(index)}
|
||||||
|
></button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="boton"
|
||||||
|
onClick={addGrados_obtenidos}
|
||||||
|
>
|
||||||
|
Agregar Grados de investigacion
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{page === 5 && (
|
||||||
<div className="form-section">
|
<div className="form-section">
|
||||||
<h2>Lineas de Investigacion</h2>
|
<h2>Lineas de Investigacion</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}
|
Linea de Investigacion {index + 1}
|
||||||
<span className="required">*</span>
|
<span className="required">*</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name={`lineas_inv_${index}`}
|
name={`lineas_inv_${index}`}
|
||||||
value={linea.lineas_inv}
|
value={linea.lineas_inv_html}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
handleLineaInvestigacionChange(index, e.target.value)
|
handleLineaInvestigacionChange(index, e.target.value)
|
||||||
}
|
}
|
||||||
@@ -532,7 +577,7 @@ const FormProfesor = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{page === 5 && (
|
{page === 6 && (
|
||||||
<div className="form-section">
|
<div className="form-section">
|
||||||
<h2>Proyectos Académicos</h2>
|
<h2>Proyectos Académicos</h2>
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
@@ -545,7 +590,7 @@ const FormProfesor = () => {
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name={`proyecto_${index}`}
|
name={`proyecto_${index}`}
|
||||||
value={proyecto.proyecto}
|
value={proyecto.proyecto_html}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
handleProyectoAcademicoChange(index, e.target.value)
|
handleProyectoAcademicoChange(index, e.target.value)
|
||||||
}
|
}
|
||||||
@@ -570,7 +615,7 @@ const FormProfesor = () => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="button-container">
|
<div className="button-container">
|
||||||
{page === 5 && (
|
{page === 6 && (
|
||||||
<button type="submit" className="small-button">
|
<button type="submit" className="small-button">
|
||||||
Registrar
|
Registrar
|
||||||
</button>
|
</button>
|
||||||
@@ -628,7 +673,15 @@ const FormProfesor = () => {
|
|||||||
5
|
5
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li className={`page-item ${page === 5 ? "disabled" : ""}`}>
|
<li className={`page-item ${page === 6 ? "active" : ""}`}>
|
||||||
|
<button
|
||||||
|
className="page-link buttons"
|
||||||
|
onClick={() => handlePageChange(6)}
|
||||||
|
>
|
||||||
|
6
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li className={`page-item ${page === 6 ? "disabled" : ""}`}>
|
||||||
<button
|
<button
|
||||||
className="page-link nextButtons"
|
className="page-link nextButtons"
|
||||||
onClick={() => handlePageChange(page + 1)}
|
onClick={() => handlePageChange(page + 1)}
|
||||||
@@ -642,4 +695,4 @@ const FormProfesor = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FormProfesor;
|
export default FormProfesor;
|
||||||
@@ -30,7 +30,7 @@ const FormEditProfesor = () => {
|
|||||||
const [fotoBase64, setFotoBase64] = useState("");
|
const [fotoBase64, setFotoBase64] = useState("");
|
||||||
const [lineasInvestigacion, setLineasInvestigacion] = useState([]);
|
const [lineasInvestigacion, setLineasInvestigacion] = useState([]);
|
||||||
const [proyectosAcademicos, setProyectosAcademicos] = useState([]);
|
const [proyectosAcademicos, setProyectosAcademicos] = useState([]);
|
||||||
|
const [datosAcademicos, setDatosAcademicos] = useState([]);
|
||||||
const [num_trabajador, setNum_trabajador] = useState("");
|
const [num_trabajador, setNum_trabajador] = useState("");
|
||||||
const [rfc, setRfc] = useState("");
|
const [rfc, setRfc] = useState("");
|
||||||
const [homoclave, setHomoclave] = useState("");
|
const [homoclave, setHomoclave] = useState("");
|
||||||
@@ -44,8 +44,6 @@ const FormEditProfesor = () => {
|
|||||||
const [nombre, setNombre] = useState("");
|
const [nombre, setNombre] = useState("");
|
||||||
|
|
||||||
const [grado_maximo, setGrado_maximo] = useState("");
|
const [grado_maximo, setGrado_maximo] = useState("");
|
||||||
const [grados_obtenidos, setGrados_obtenidos] = useState("");
|
|
||||||
|
|
||||||
const [errorMessage, setErrorMessage] = useState("");
|
const [errorMessage, setErrorMessage] = useState("");
|
||||||
const { teacher } = useTeacher(id_profesor);
|
const { teacher } = useTeacher(id_profesor);
|
||||||
const { updateTeacher } = useUpdateTeacher();
|
const { updateTeacher } = useUpdateTeacher();
|
||||||
@@ -65,6 +63,7 @@ const FormEditProfesor = () => {
|
|||||||
setActivo(teacher.activo);
|
setActivo(teacher.activo);
|
||||||
setLineasInvestigacion(teacher.lineasInvestigacion);
|
setLineasInvestigacion(teacher.lineasInvestigacion);
|
||||||
setProyectosAcademicos(teacher.proyectosAcademicos);
|
setProyectosAcademicos(teacher.proyectosAcademicos);
|
||||||
|
setDatosAcademicos(teacher.datosAcademicos);
|
||||||
setNum_trabajador(teacher.num_trabajador);
|
setNum_trabajador(teacher.num_trabajador);
|
||||||
setRfc(teacher.rfc);
|
setRfc(teacher.rfc);
|
||||||
setHomoclave(teacher.homoclave);
|
setHomoclave(teacher.homoclave);
|
||||||
@@ -75,11 +74,16 @@ const FormEditProfesor = () => {
|
|||||||
setCorreo_per(teacher.correo_per);
|
setCorreo_per(teacher.correo_per);
|
||||||
setUbicacion(teacher.ubicacion);
|
setUbicacion(teacher.ubicacion);
|
||||||
setGrado_maximo(teacher.datosAcademicos[0]?.grado_maximo || "");
|
setGrado_maximo(teacher.datosAcademicos[0]?.grado_maximo || "");
|
||||||
setGrados_obtenidos(teacher.datosAcademicos[0]?.grados_obtenidos || "");
|
|
||||||
setOldFoto(teacher.fotografia);
|
setOldFoto(teacher.fotografia);
|
||||||
}
|
}
|
||||||
}, [teacher]);
|
}, [teacher]);
|
||||||
|
|
||||||
|
const handleGrados_obtenidosChange = (index, value) => {
|
||||||
|
const newGrados = [...datosAcademicos];
|
||||||
|
newGrados[index].grados_obtenidos = value;
|
||||||
|
setDatosAcademicos(newGrados);
|
||||||
|
};
|
||||||
|
|
||||||
const handleLineaInvestigacionChange = (index, value) => {
|
const handleLineaInvestigacionChange = (index, value) => {
|
||||||
const newLineas = [...lineasInvestigacion];
|
const newLineas = [...lineasInvestigacion];
|
||||||
newLineas[index].lineas_inv_html = value;
|
newLineas[index].lineas_inv_html = value;
|
||||||
@@ -92,6 +96,10 @@ const FormEditProfesor = () => {
|
|||||||
setProyectosAcademicos(newProyectos);
|
setProyectosAcademicos(newProyectos);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const addGrados_obtenidos = () => {
|
||||||
|
setDatosAcademicos([...datosAcademicos, { grados_obtenidos: "" }]);
|
||||||
|
};
|
||||||
|
|
||||||
const addLineaInvestigacion = () => {
|
const addLineaInvestigacion = () => {
|
||||||
setLineasInvestigacion([...lineasInvestigacion, { lineas_inv_html: "" }]);
|
setLineasInvestigacion([...lineasInvestigacion, { lineas_inv_html: "" }]);
|
||||||
};
|
};
|
||||||
@@ -100,6 +108,11 @@ const FormEditProfesor = () => {
|
|||||||
setProyectosAcademicos([...proyectosAcademicos, { proyecto_html: "" }]);
|
setProyectosAcademicos([...proyectosAcademicos, { proyecto_html: "" }]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const deleteGrados_obtenidos = (index) => {
|
||||||
|
const newGrados = datosAcademicos.filter((_, i) => i !== index);
|
||||||
|
setDatosAcademicos(newGrados);
|
||||||
|
};
|
||||||
|
|
||||||
const deleteLineaInvestigacion = (index) => {
|
const deleteLineaInvestigacion = (index) => {
|
||||||
const newLineas = lineasInvestigacion.filter((_, i) => i !== index);
|
const newLineas = lineasInvestigacion.filter((_, i) => i !== index);
|
||||||
setLineasInvestigacion(newLineas);
|
setLineasInvestigacion(newLineas);
|
||||||
@@ -123,9 +136,14 @@ const FormEditProfesor = () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (fotoBase64) {
|
if (fotoBase64) {
|
||||||
imageUrl = await updateImage(fotoBase64, nombre);
|
imageUrl = await updateImage(fotoBase64, id_profesor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updatedDatosAcademicos = datosAcademicos.map((dato) => ({
|
||||||
|
...dato,
|
||||||
|
grado_maximo: grado_maximo || dato.grado_maximo,
|
||||||
|
}));
|
||||||
|
|
||||||
const profesorData = {
|
const profesorData = {
|
||||||
...profesor,
|
...profesor,
|
||||||
nombre,
|
nombre,
|
||||||
@@ -145,12 +163,7 @@ const FormEditProfesor = () => {
|
|||||||
activo,
|
activo,
|
||||||
lineasInvestigacion,
|
lineasInvestigacion,
|
||||||
proyectosAcademicos,
|
proyectosAcademicos,
|
||||||
datosAcademicos: [
|
datosAcademicos: updatedDatosAcademicos,
|
||||||
{
|
|
||||||
grado_maximo,
|
|
||||||
grados_obtenidos,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
fotografia: imageUrl || profesor.fotografia,
|
fotografia: imageUrl || profesor.fotografia,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -195,7 +208,7 @@ const FormEditProfesor = () => {
|
|||||||
return (
|
return (
|
||||||
<div className="form-container">
|
<div className="form-container">
|
||||||
<div className="containerButton">
|
<div className="containerButton">
|
||||||
<button className="blueButton" onClick={handleRegresar}>
|
<button className="btn btn-primary" onClick={handleRegresar}>
|
||||||
Regresar
|
Regresar
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -284,27 +297,21 @@ const FormEditProfesor = () => {
|
|||||||
<div className="form-section">
|
<div className="form-section">
|
||||||
<h2>Datos Académicos</h2>
|
<h2>Datos Académicos</h2>
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label>
|
{datosAcademicos.length > 0 && datosAcademicos[0].grado_maximo ? ( // Verifica que haya al menos un dato y que tenga grado_maximo
|
||||||
Grado Maximo <span className="required">*</span>
|
<div>
|
||||||
</label>
|
<label>
|
||||||
<input
|
Grado Máximo <span className="required">*</span>
|
||||||
type="text"
|
</label>
|
||||||
name="grado_maximo"
|
<input
|
||||||
value={grado_maximo}
|
type="text"
|
||||||
onChange={(e) => setGrado_maximo(e.target.value)}
|
name="grado_maximo"
|
||||||
/>
|
value={datosAcademicos[0].grado_maximo}
|
||||||
</div>
|
onChange={(e) => setGrado_maximo(e.target.value)}
|
||||||
|
/>
|
||||||
<div className="form-group">
|
</div>
|
||||||
<label>
|
) : (
|
||||||
Grados Obtenidos <span className="required">*</span>
|
<div>No hay grado máximo registrado.</div>
|
||||||
</label>
|
)}
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
name="grados_obtenidos"
|
|
||||||
value={grados_obtenidos}
|
|
||||||
onChange={(e) => setGrados_obtenidos(e.target.value)}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
@@ -496,6 +503,44 @@ const FormEditProfesor = () => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{page === 4 && (
|
{page === 4 && (
|
||||||
|
<div className="form-section">
|
||||||
|
<h2>Grados obtenidos</h2>
|
||||||
|
<div className="form-group">
|
||||||
|
{datosAcademicos.map((grado, index) => (
|
||||||
|
<div key={index} className="input-with-delete">
|
||||||
|
<label>
|
||||||
|
Grado obtenido {index + 1}
|
||||||
|
<span className="required">*</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name={`grados_obtenidos_${index}`}
|
||||||
|
value={grado.grados_obtenidos}
|
||||||
|
onChange={(e) =>
|
||||||
|
handleGrados_obtenidosChange(index, e.target.value)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="delete-botones"
|
||||||
|
onClick={() => deleteGrados_obtenidos(index)}
|
||||||
|
></button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="d-flex justify-content-center">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-primary"
|
||||||
|
onClick={addGrados_obtenidos}
|
||||||
|
>
|
||||||
|
Agregar Grados de investigacion
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{page === 5 && (
|
||||||
<div className="form-section">
|
<div className="form-section">
|
||||||
<h2>Lineas de Investigacion</h2>
|
<h2>Lineas de Investigacion</h2>
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
@@ -532,7 +577,7 @@ const FormEditProfesor = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{page === 5 && (
|
{page === 6 && (
|
||||||
<div className="form-section">
|
<div className="form-section">
|
||||||
<h2>Proyectos Académicos</h2>
|
<h2>Proyectos Académicos</h2>
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
@@ -572,69 +617,76 @@ const FormEditProfesor = () => {
|
|||||||
<button type="submit" className="btn btn-primary boton">
|
<button type="submit" className="btn btn-primary boton">
|
||||||
Guardar modificacion
|
Guardar modificacion
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<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 ${page === 1 ? "disabled" : ""}`}>
|
<li className={`page-item ${page === 1 ? "disabled" : ""}`}>
|
||||||
<button
|
<button
|
||||||
className="page-link prevButtons"
|
className="page-link prevButtons"
|
||||||
onClick={() => handlePageChange(page - 1)}
|
onClick={() => handlePageChange(page - 1)}
|
||||||
>
|
>
|
||||||
Anterior
|
Anterior
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li className={`page-item ${page === 1 ? "active" : ""}`}>
|
<li className={`page-item ${page === 1 ? "active" : ""}`}>
|
||||||
<button
|
<button
|
||||||
className="page-link buttons"
|
className="page-link buttons"
|
||||||
onClick={() => handlePageChange(1)}
|
onClick={() => handlePageChange(1)}
|
||||||
>
|
>
|
||||||
1
|
1
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li className={`page-item ${page === 2 ? "active" : ""}`}>
|
<li className={`page-item ${page === 2 ? "active" : ""}`}>
|
||||||
<button
|
<button
|
||||||
className="page-link buttons"
|
className="page-link buttons"
|
||||||
onClick={() => handlePageChange(2)}
|
onClick={() => handlePageChange(2)}
|
||||||
>
|
>
|
||||||
2
|
2
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li className={`page-item ${page === 3 ? "active" : ""}`}>
|
<li className={`page-item ${page === 3 ? "active" : ""}`}>
|
||||||
<button
|
<button
|
||||||
className="page-link buttons"
|
className="page-link buttons"
|
||||||
onClick={() => handlePageChange(3)}
|
onClick={() => handlePageChange(3)}
|
||||||
>
|
>
|
||||||
3
|
3
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li className={`page-item ${page === 4 ? "active" : ""}`}>
|
<li className={`page-item ${page === 4 ? "active" : ""}`}>
|
||||||
<button
|
<button
|
||||||
className="page-link buttons"
|
className="page-link buttons"
|
||||||
onClick={() => handlePageChange(4)}
|
onClick={() => handlePageChange(4)}
|
||||||
>
|
>
|
||||||
4
|
4
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li className={`page-item ${page === 5 ? "active" : ""}`}>
|
<li className={`page-item ${page === 5 ? "active" : ""}`}>
|
||||||
<button
|
<button
|
||||||
className="page-link buttons"
|
className="page-link buttons"
|
||||||
onClick={() => handlePageChange(5)}
|
onClick={() => handlePageChange(5)}
|
||||||
>
|
>
|
||||||
5
|
5
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li className={`page-item ${page === 5 ? "disabled" : ""}`}>
|
<li className={`page-item ${page === 6 ? "active" : ""}`}>
|
||||||
<button
|
<button
|
||||||
className="page-link nextButtons"
|
className="page-link buttons"
|
||||||
onClick={() => handlePageChange(page + 1)}
|
onClick={() => handlePageChange(6)}
|
||||||
>
|
>
|
||||||
Siguiente
|
6
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
<li className={`page-item ${page === 6 ? "disabled" : ""}`}>
|
||||||
</nav>
|
<button
|
||||||
|
className="page-link nextButtons"
|
||||||
|
onClick={() => handlePageChange(page + 1)}
|
||||||
|
>
|
||||||
|
Siguiente
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,13 +3,14 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
gap: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.foto {
|
.foto {
|
||||||
width: auto;
|
width: auto;
|
||||||
max-width: 40vw;
|
max-width: 40vw;
|
||||||
height: 250px;
|
height: 250px;
|
||||||
max-height: 25vh;
|
max-height: 50vh;
|
||||||
border-radius: 1em;
|
border-radius: 1em;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
@@ -27,7 +28,7 @@
|
|||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
margin: 20px auto;
|
margin: 10px auto;
|
||||||
width: 800px;
|
width: 800px;
|
||||||
max-width: 90vw;
|
max-width: 90vw;
|
||||||
}
|
}
|
||||||
@@ -38,6 +39,11 @@
|
|||||||
align-items: start;
|
align-items: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.list{
|
||||||
|
margin-left: 20px;
|
||||||
|
list-style: circle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.datos-academicos,
|
.datos-academicos,
|
||||||
.lineas-investigacion,
|
.lineas-investigacion,
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import {
|
|||||||
useTeacher,
|
useTeacher,
|
||||||
} from "../../../services/teacher.services";
|
} from "../../../services/teacher.services";
|
||||||
|
|
||||||
|
const API_URL = process.env.REACT_APP_API_URL;
|
||||||
|
|
||||||
const defaultImage =
|
const defaultImage =
|
||||||
"https://static.vecteezy.com/system/resources/thumbnails/020/765/399/small_2x/default-profile-account-unknown-icon-black-silhouette-free-vector.jpg";
|
"https://static.vecteezy.com/system/resources/thumbnails/020/765/399/small_2x/default-profile-account-unknown-icon-black-silhouette-free-vector.jpg";
|
||||||
|
|
||||||
@@ -73,18 +75,47 @@ const PerfilProfesor = () => {
|
|||||||
window.history.back();
|
window.history.back();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const splitTextToListItems = (text) => {
|
||||||
|
const parts = text.split(".").filter((part) => part.trim() !== "");
|
||||||
|
|
||||||
|
return parts.map((part, index) => {
|
||||||
|
const formattedPart = part.trim() + (index < parts.length - 1 ? "." : "");
|
||||||
|
return (
|
||||||
|
<li key={index} className="list">
|
||||||
|
{formattedPart}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleImageError = (e) => {
|
||||||
|
e.target.src = defaultImage;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="form-container">
|
<div className="form-container">
|
||||||
<div className="containerButton">
|
<div className="containerButton">
|
||||||
<button className="blueButton" onClick={handleRegresar}>
|
<button className="btn btn-primary" onClick={handleRegresar}>
|
||||||
Regresar
|
Regresar
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="perfil-profesor">
|
<div className="perfil-profesor">
|
||||||
<div className="foto-nombre">
|
<div className="foto-nombre">
|
||||||
{fotoProfesor && fotoProfesor.startsWith("http") ? (
|
{fotoProfesor && fotoProfesor.startsWith("http") ? (
|
||||||
<img src={fotoProfesor} alt={profesor.nombre} className="foto" />
|
<img
|
||||||
) : null}
|
src={fotoProfesor}
|
||||||
|
alt={profesor.nombre}
|
||||||
|
className="foto"
|
||||||
|
onError={handleImageError}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<img
|
||||||
|
src={`${API_URL}/imagenes/${profesor.fotografia}`}
|
||||||
|
alt={profesor.nombre}
|
||||||
|
className="foto"
|
||||||
|
onError={handleImageError}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="info">
|
<div className="info">
|
||||||
<div className="nombre">
|
<div className="nombre">
|
||||||
@@ -120,22 +151,34 @@ const PerfilProfesor = () => {
|
|||||||
<h4>Datos académicos</h4>
|
<h4>Datos académicos</h4>
|
||||||
</div>
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
{profesor.datosAcademicos.map((datosAcademicos, index) => (
|
<li>
|
||||||
<React.Fragment key={index}>
|
<strong>Grado Máximo:</strong>
|
||||||
<li key={`grado_maximo_${index}`}>
|
{profesor.datosAcademicos.length > 0 ? (
|
||||||
<strong>Grado Máximo:</strong>
|
profesor.datosAcademicos[0].grado_maximo ? (
|
||||||
{datosAcademicos.grado_maximo
|
<>{profesor.datosAcademicos[0].grado_maximo}</>
|
||||||
? datosAcademicos.grado_maximo
|
) : (
|
||||||
: "NO encontrado"}
|
<>No hay Grado Máximo registrado.</>
|
||||||
</li>
|
)
|
||||||
<li key={`grados_obtenidos_${index}`}>
|
) : (
|
||||||
<strong>Grados Obtenidos:</strong>
|
<li>No hay Datos Académicos registrados.</li>
|
||||||
{datosAcademicos.grados_obtenidos
|
)}
|
||||||
? datosAcademicos.grados_obtenidos
|
</li>
|
||||||
: "NO encontrado"}
|
|
||||||
</li>
|
<strong>Grados Obtenidos:</strong>
|
||||||
</React.Fragment>
|
<ul>
|
||||||
))}
|
{profesor.datosAcademicos.length > 0 ? (
|
||||||
|
profesor.datosAcademicos.map((item, index) =>
|
||||||
|
item.grados_obtenidos ? (
|
||||||
|
<li key={`grado_obtenido_${index}`}>
|
||||||
|
{splitTextToListItems(item.grados_obtenidos)}
|
||||||
|
</li>
|
||||||
|
) : null
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<li>No hay Grados registrados.</li>
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<strong>Categoría:</strong>
|
<strong>Categoría:</strong>
|
||||||
{categoriaProfesor ? categoriaProfesor.categoria : "No ubicado"}
|
{categoriaProfesor ? categoriaProfesor.categoria : "No ubicado"}
|
||||||
@@ -154,12 +197,16 @@ const PerfilProfesor = () => {
|
|||||||
<h4>Líneas de investigación</h4>
|
<h4>Líneas de investigación</h4>
|
||||||
</div>
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
|
<strong>Investigaciones:</strong>
|
||||||
{profesor.lineasInvestigacion.length > 0 ? (
|
{profesor.lineasInvestigacion.length > 0 ? (
|
||||||
profesor.lineasInvestigacion.map((linea, index) => (
|
profesor.lineasInvestigacion.map((linea, index) => (
|
||||||
<li key={index}>
|
<div key={index}>
|
||||||
<strong>Investigacion {index + 1}:</strong>
|
<ul>
|
||||||
{linea.lineas_inv_html ? linea.lineas_inv_html : "NO encontrado"}
|
{linea.lineas_inv_html
|
||||||
</li>
|
? splitTextToListItems(linea.lineas_inv_html)
|
||||||
|
: null}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<li>No hay líneas de investigación registradas.</li>
|
<li>No hay líneas de investigación registradas.</li>
|
||||||
@@ -172,12 +219,16 @@ const PerfilProfesor = () => {
|
|||||||
<h4>Proyectos académicos</h4>
|
<h4>Proyectos académicos</h4>
|
||||||
</div>
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
|
<strong>Proyectos:</strong>
|
||||||
{profesor.proyectosAcademicos.length > 0 ? (
|
{profesor.proyectosAcademicos.length > 0 ? (
|
||||||
profesor.proyectosAcademicos.map((proyecto, index) => (
|
profesor.proyectosAcademicos.map((proyecto, index) => (
|
||||||
<li key={index}>
|
<div key={index}>
|
||||||
<strong>Proyecto {index + 1}:</strong>
|
<ul>
|
||||||
{proyecto.proyecto_html ? proyecto.proyecto_html : "NO encontrado"}
|
{proyecto.proyecto_html
|
||||||
</li>
|
? splitTextToListItems(proyecto.proyecto_html)
|
||||||
|
: null}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<li>No hay proyectos académicos registrados.</li>
|
<li>No hay proyectos académicos registrados.</li>
|
||||||
@@ -207,7 +258,7 @@ const PerfilProfesor = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{showDialog && (
|
{showDialog && (
|
||||||
<div className="dialog">
|
<div className="dialog" style={{ position: "fixed" }}>
|
||||||
<p>
|
<p>
|
||||||
¿Deseas eliminar al profesor <strong>{profesor.nombre}</strong>?
|
¿Deseas eliminar al profesor <strong>{profesor.nombre}</strong>?
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import "../../../App.css";
|
import "../../../App.css";
|
||||||
import { PrivateRoutes } from "../../../models/routes";
|
|
||||||
import { useUser, useUpdateUser } from "../../../services/user.services";
|
import { useUser, useUpdateUser } from "../../../services/user.services";
|
||||||
|
|
||||||
const MDUser = () => {
|
const MDUser = () => {
|
||||||
|
|||||||
@@ -4,12 +4,14 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: #1e3c70 !important;
|
background-color: #1e3c70 !important;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
padding-left: 40px;
|
||||||
|
padding-right: 40px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
width: 300px;
|
width: 50px;
|
||||||
max-width: 40vw;
|
max-width: 10vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
@@ -20,9 +22,10 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer .container {
|
.footer .container {
|
||||||
max-width: 1200px;
|
max-width: 90%;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
@@ -7,7 +7,6 @@ const Id = () => {
|
|||||||
const jwtPermissions = () => {
|
const jwtPermissions = () => {
|
||||||
const jwtToken = localStorage.getItem("Token");
|
const jwtToken = localStorage.getItem("Token");
|
||||||
if (!jwtToken) {
|
if (!jwtToken) {
|
||||||
console.error("No se encontró el token en localStorage");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ const Guard = () => {
|
|||||||
const jwtPermissions = () => {
|
const jwtPermissions = () => {
|
||||||
const jwtToken = localStorage.getItem("Token");
|
const jwtToken = localStorage.getItem("Token");
|
||||||
if (!jwtToken) {
|
if (!jwtToken) {
|
||||||
console.error("No se encontró el token en localStorage");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,3 +11,6 @@ code {
|
|||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||||
monospace;
|
monospace;
|
||||||
}
|
}
|
||||||
|
*{
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -77,7 +77,7 @@ export const useUploadImage = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
return `${API_URL}${result.imageUrl}`;
|
return result.imageUrl;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,7 @@ export const useUpdateImage = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
return `${API_URL}${result.imageUrl}`;
|
return result.imageUrl;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,34 +117,37 @@ export const useTeachers = (currentPage, filters) => {
|
|||||||
export const useRegisterTeacher = () => {
|
export const useRegisterTeacher = () => {
|
||||||
const token = useToken();
|
const token = useToken();
|
||||||
|
|
||||||
const registerTeacher = (teacherData) => {
|
const registerTeacher = async (teacherData) => {
|
||||||
return fetch(`${API_URL}/profesor`, {
|
try {
|
||||||
method: "POST",
|
const response = await fetch(`${API_URL}/profesor`, {
|
||||||
headers: {
|
method: "POST",
|
||||||
"Content-Type": "application/json",
|
headers: {
|
||||||
Authorization: `Bearer ${token}`,
|
"Content-Type": "application/json",
|
||||||
},
|
Authorization: `Bearer ${token}`,
|
||||||
body: JSON.stringify(teacherData),
|
},
|
||||||
})
|
body: JSON.stringify(teacherData),
|
||||||
.then((response) => {
|
|
||||||
if (!response.ok) {
|
|
||||||
console.error("Error:");
|
|
||||||
}
|
|
||||||
return response.json();
|
|
||||||
})
|
|
||||||
.then((data) => {
|
|
||||||
console.log("Success:", data);
|
|
||||||
window.location.href = PublicRoutes.FILTER;
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error("Error:", error);
|
|
||||||
throw error;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
console.error("Error:");
|
||||||
|
throw new Error("Error registering teacher");
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
console.log("Success:", data);
|
||||||
|
|
||||||
|
return data.id_profesor;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return { registerTeacher };
|
return { registerTeacher };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const useTeacher = (id_profesor) => {
|
export const useTeacher = (id_profesor) => {
|
||||||
const [teacher, setTeacher] = useState(null);
|
const [teacher, setTeacher] = useState(null);
|
||||||
|
|
||||||
@@ -196,3 +199,32 @@ export const useUpdateTeacher = () => {
|
|||||||
|
|
||||||
return { updateTeacher };
|
return { updateTeacher };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useUpdateTeacherImage = () => {
|
||||||
|
const token = useToken();
|
||||||
|
|
||||||
|
const updateTeacherImage = async (id_profesor, imageUrl) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${API_URL}/profesor/${id_profesor}/image`, {
|
||||||
|
method: "PUT",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ fotografia: imageUrl }),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
console.error("Error updating teacher image");
|
||||||
|
throw new Error("Error updating teacher image");
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Image URL updated successfully");
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return { updateTeacherImage };
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user