Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d318679a89 | |||
| e2457f4cd4 | |||
| b9bc44b921 | |||
| c428cfcee4 | |||
| 996f6dc438 | |||
| 4493a0834c | |||
| e74619ae19 | |||
| 05b8abab76 | |||
| a919023851 | |||
| b9179d6c37 | |||
| f5c1ba8d66 | |||
| 197c035356 | |||
| b7a0f48905 | |||
| d576242bce | |||
| fe697f015b | |||
| f8650adc93 | |||
| f6878085ee | |||
| a56e589812 | |||
| 0ccd68674e | |||
| 4884eaca64 | |||
| d72959ddc2 | |||
| 8020d9671b | |||
| 3513fcb693 |
@@ -1,2 +1,2 @@
|
||||
REACT_APP_API_URL=http://192.168.100.7:3000
|
||||
REACT_APP_PORT=3001
|
||||
REACT_APP_API_URL=https://venus.acatlan.unam.mx/directorio_test
|
||||
REACT_APP_PORT=3001
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "set PORT=3226 && react-scripts start",
|
||||
"start": "set PORT=3001 && react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
|
||||
+3
-3
@@ -31,7 +31,7 @@
|
||||
|
||||
.edit-button,
|
||||
.delete-boton {
|
||||
padding: 8px 12px;
|
||||
padding: 4px 12px;
|
||||
margin-right: 10px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
@@ -352,7 +352,7 @@ button[type="submit"]:disabled {
|
||||
}
|
||||
|
||||
.delete-botones {
|
||||
background-image: url("https://cdn.icon-icons.com/icons2/1791/PNG/512/trashcan1_114647.png");
|
||||
background-image: url("./assets/img/trashcan.png");
|
||||
filter: invert(1);
|
||||
background-color: aqua;
|
||||
position: absolute;
|
||||
@@ -423,7 +423,7 @@ p .text-center .mt-3 {
|
||||
justify-content: space-evenly;
|
||||
width: 400px;
|
||||
max-width: 90vw;
|
||||
margin: 10px;
|
||||
margin: 10px auto;
|
||||
}
|
||||
|
||||
.cargando {
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 171 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 254 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.6 KiB |
@@ -1,7 +1,7 @@
|
||||
.card {
|
||||
max-width: 90vw;
|
||||
width: 400px;
|
||||
height: 175px;
|
||||
height: 170px;
|
||||
margin: auto;
|
||||
padding: 0.5em;
|
||||
border-radius: 1em !important;
|
||||
@@ -11,7 +11,22 @@
|
||||
flex-direction: row !important;
|
||||
justify-content: left;
|
||||
text-align: center;
|
||||
transition: box-shadow 0.3s ease, transform 0.3s ease;
|
||||
transition: box-shadow 0.3s ease-out, transform 0.3s ease-out ;
|
||||
}
|
||||
|
||||
.transition{
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
transition: opacity 0.5s ease-in-out, transform 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
.transition.show {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 40vw;
|
||||
min-width: 340px;
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
@@ -37,6 +52,7 @@
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
max-width: 130px;
|
||||
}
|
||||
|
||||
|
||||
@@ -56,4 +72,10 @@
|
||||
|
||||
.status-label.inactive {
|
||||
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 { 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 [confirmText, setConfirmText] = useState("");
|
||||
const { deleteTeacher } = useDeleteTeacher();
|
||||
const defaultImage =
|
||||
"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 = () => {
|
||||
setShowDialog(true);
|
||||
@@ -28,20 +34,28 @@ const CardProfesor = ({ profesor, edificioNombre, permissions }) => {
|
||||
};
|
||||
|
||||
const handleViewProfesor = () => {
|
||||
localStorage.setItem("lastPage", currentPage);
|
||||
window.location.href = `${PublicRoutes.DATAPROFESOR}${profesor.id_profesor}`;
|
||||
};
|
||||
|
||||
const handleImageError = (e) => {
|
||||
e.target.src = defaultImage;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="card m-1">
|
||||
<div className="image">
|
||||
{fotoProfesor && fotoProfesor.startsWith("http") ? (
|
||||
<img
|
||||
src={fotoProfesor}
|
||||
className="imgProfe"
|
||||
alt={profesor.nombre}
|
||||
onClick={handleViewProfesor}
|
||||
/>
|
||||
) : null}
|
||||
<img
|
||||
src={
|
||||
profesor.fotografia && profesor.fotografia.startsWith("http")
|
||||
? profesor.fotografia
|
||||
: `${API_URL}/imagenes/${profesor.fotografia}`
|
||||
}
|
||||
className="imgProfe"
|
||||
alt={profesor.nombre}
|
||||
onClick={handleViewProfesor}
|
||||
onError={handleImageError}
|
||||
/>
|
||||
|
||||
{permissions ? (
|
||||
<div
|
||||
|
||||
@@ -16,6 +16,7 @@ function FilterProfesor() {
|
||||
const categorias = useCategoria();
|
||||
const edificios = useEdificio();
|
||||
const [filters, setFilters] = useState({});
|
||||
const [currentPage, setCurrentPage] = useState(Number(localStorage.getItem("lastPage")) || 1);
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
@@ -25,6 +26,7 @@ function FilterProfesor() {
|
||||
categoria,
|
||||
edificio,
|
||||
});
|
||||
setCurrentPage(1);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -52,7 +54,7 @@ function FilterProfesor() {
|
||||
onChange={(e) => setAdscripcion(e.target.value)}
|
||||
className="form-control me-2"
|
||||
>
|
||||
<option value="">Adscripcion</option>
|
||||
<option value="">Adscripción</option>
|
||||
{adscripciones.map((adscripcion) => (
|
||||
<option
|
||||
key={adscripcion.id_adscripcion}
|
||||
@@ -69,7 +71,7 @@ function FilterProfesor() {
|
||||
onChange={(e) => setCategoria(e.target.value)}
|
||||
className="form-control me-2"
|
||||
>
|
||||
<option value="">Categoria</option>
|
||||
<option value="">Categoría</option>
|
||||
{categorias.map((categoria) => (
|
||||
<option
|
||||
key={categoria.id_categoria}
|
||||
@@ -97,14 +99,19 @@ function FilterProfesor() {
|
||||
<button
|
||||
className="btn me-2"
|
||||
type="submit"
|
||||
style={{ background: "#1e3c70", color: "#fff" }}
|
||||
style={{ background: "#D59F0F", color: "#fff" }}
|
||||
>
|
||||
Buscar
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</nav>
|
||||
<Mapeo filters={filters} edificios={edificios} />
|
||||
<Mapeo
|
||||
filters={filters}
|
||||
edificios={edificios}
|
||||
currentPage={currentPage}
|
||||
setCurrentPage={setCurrentPage}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import "../../../App.css";
|
||||
import CardProfesor from "./CardProfesor";
|
||||
import Guard from "../../../guards/route.guard";
|
||||
@@ -8,8 +8,8 @@ import {
|
||||
} from "../../../services/teacher.services";
|
||||
import { PrivateRoutes } from "../../../models/routes";
|
||||
|
||||
const Mapeo = ({ filters, edificios }) => {
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const Mapeo = ({ filters, edificios, currentPage, setCurrentPage }) => {
|
||||
const [shownCards, setShownCards] = useState([]);
|
||||
const permissions = Guard();
|
||||
|
||||
const {
|
||||
@@ -25,6 +25,50 @@ const Mapeo = ({ filters, edificios }) => {
|
||||
error: errorActives,
|
||||
} = 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) {
|
||||
return (
|
||||
<div className="perfil-profesor">
|
||||
@@ -49,25 +93,20 @@ const Mapeo = ({ filters, edificios }) => {
|
||||
);
|
||||
}
|
||||
|
||||
const { profesores, totalPages } = permissions
|
||||
? { profesores: profesoresData, totalPages: totalDataPages }
|
||||
: { profesores: profesoresActivesData, totalPages: totalActivePages };
|
||||
|
||||
const handleNextPage = () => {
|
||||
if (currentPage < totalPages) {
|
||||
setCurrentPage((prevPage) => prevPage + 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const handlePrevPage = () => {
|
||||
if (currentPage > 1) {
|
||||
setCurrentPage((prevPage) => prevPage - 1);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const renderPageNumbers = () => {
|
||||
const pageNumbers = [];
|
||||
const maxPagesToShow = 5;
|
||||
let startPage = Math.max(1, currentPage - Math.floor(maxPagesToShow / 2));
|
||||
let endPage = Math.min(totalPages, startPage + maxPagesToShow - 1);
|
||||
|
||||
@@ -115,20 +154,29 @@ const Mapeo = ({ filters, edificios }) => {
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{profesores.map((profesor) => {
|
||||
const edificio = edificios.find(
|
||||
(e) => e.id_edificio === profesor.id_edificio
|
||||
);
|
||||
const edificioNombre = edificio ? edificio.edificio : "Desconocido";
|
||||
return (
|
||||
<CardProfesor
|
||||
key={profesor.id_profesor}
|
||||
profesor={profesor}
|
||||
edificioNombre={edificioNombre}
|
||||
permissions={permissions}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<div className="profesores-container">
|
||||
{profesores.map((profesor, index) => {
|
||||
const edificio = edificios.find(
|
||||
(e) => e.id_edificio === profesor.id_edificio
|
||||
);
|
||||
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">
|
||||
<ul className="pagination justify-content-center">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import "../../../App.css";
|
||||
import CardUsuario from "./CardUsuario";
|
||||
import { PrivateRoutes } from "../../../models/routes";
|
||||
@@ -8,6 +8,24 @@ const MapeoUsuario = ({ filters }) => {
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
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) {
|
||||
return (
|
||||
<div className="perfil-profesor">
|
||||
@@ -36,7 +54,6 @@ const MapeoUsuario = ({ filters }) => {
|
||||
|
||||
const renderPageNumbers = () => {
|
||||
const pageNumbers = [];
|
||||
const maxPagesToShow = 5;
|
||||
let startPage = Math.max(1, currentPage - Math.floor(maxPagesToShow / 2));
|
||||
let endPage = Math.min(totalPages, startPage + maxPagesToShow - 1);
|
||||
|
||||
@@ -82,9 +99,13 @@ const MapeoUsuario = ({ filters }) => {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{usuarios.map((usuario) => (
|
||||
<CardUsuario key={usuario.id_usuario} usuario={usuario} />
|
||||
))}
|
||||
<div className="profesores-container">
|
||||
{usuarios.map((usuario) => (
|
||||
<div className="transition show">
|
||||
<CardUsuario key={usuario.id_usuario} usuario={usuario} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<nav aria-label="Navegación de páginas">
|
||||
<ul className="pagination justify-content-center">
|
||||
|
||||
@@ -46,7 +46,7 @@ function NavUsuario() {
|
||||
<button
|
||||
className="btn me-2"
|
||||
type="submit"
|
||||
style={{ background: "#1e3c70", color: "#fff" }}
|
||||
style={{ background: "#D59F0F", color: "#fff" }}
|
||||
>
|
||||
Buscar
|
||||
</button>
|
||||
|
||||
+101
-11
@@ -1,18 +1,108 @@
|
||||
import React from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import "./style.css";
|
||||
import Sam from "../assets/img/Sam.png";
|
||||
import IO from "../assets/img/IO.png";
|
||||
|
||||
const konamiCode = [
|
||||
"ArrowUp",
|
||||
"ArrowUp",
|
||||
"ArrowLeft",
|
||||
"ArrowRight",
|
||||
"ArrowLeft",
|
||||
"ArrowRight",
|
||||
];
|
||||
|
||||
let codePosition = 0;
|
||||
|
||||
const Footer = () => {
|
||||
const [showImage, setShowImage] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const handleCodeInput = (key) => {
|
||||
if (key === konamiCode[codePosition]) {
|
||||
codePosition++;
|
||||
if (codePosition === konamiCode.length) {
|
||||
activateSecretScreen();
|
||||
codePosition = 0;
|
||||
}
|
||||
} else {
|
||||
codePosition = 0;
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyDown = (e) => handleCodeInput(e.key);
|
||||
document.addEventListener("keydown", handleKeyDown);
|
||||
|
||||
let touchSequence = [];
|
||||
let startX = 0;
|
||||
let startY = 0;
|
||||
|
||||
const handleTouchStart = (e) => {
|
||||
startX = e.touches[0].clientX;
|
||||
startY = e.touches[0].clientY;
|
||||
};
|
||||
|
||||
const handleTouchEnd = (e) => {
|
||||
let endX = e.changedTouches[0].clientX;
|
||||
let endY = e.changedTouches[0].clientY;
|
||||
handleSwipe(startX, startY, endX, endY);
|
||||
};
|
||||
|
||||
const handleSwipe = (startX, startY, endX, endY) => {
|
||||
const deltaX = endX - startX;
|
||||
const deltaY = endY - startY;
|
||||
|
||||
if (Math.abs(deltaX) > Math.abs(deltaY)) {
|
||||
if (deltaX > 30) touchSequence.push("ArrowRight");
|
||||
else if (deltaX < -30) touchSequence.push("ArrowLeft");
|
||||
} else {
|
||||
if (deltaY > 30) touchSequence.push("ArrowDown");
|
||||
else if (deltaY < -30) touchSequence.push("ArrowUp");
|
||||
}
|
||||
|
||||
if (
|
||||
touchSequence.slice(-konamiCode.length).join("") === konamiCode.join("")
|
||||
) {
|
||||
activateSecretScreen();
|
||||
touchSequence = [];
|
||||
} else if (touchSequence.length > konamiCode.length) {
|
||||
touchSequence.shift();
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("touchstart", handleTouchStart);
|
||||
document.addEventListener("touchend", handleTouchEnd);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("keydown", handleKeyDown);
|
||||
document.removeEventListener("touchstart", handleTouchStart);
|
||||
document.removeEventListener("touchend", handleTouchEnd);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const activateSecretScreen = () => {
|
||||
setShowImage(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<footer className="footer">
|
||||
<div className="container">
|
||||
<p>
|
||||
Hecho en México. Todos los derechos reservados 2024. Esta página puede
|
||||
ser reproducida con fines no lucrativos, siempre y cuando no se
|
||||
mutile, se cite la fuente completa y su dirección electrónica. De otra
|
||||
forma, requiere permiso previo por escrito de la institución.
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
<>
|
||||
{showImage && (
|
||||
<div className="center">
|
||||
<img className={`img S ${showImage ? 'show' : ''}`} src={Sam} alt="Sam" />
|
||||
<img className={`img I ${showImage ? 'show' : ''}`} src={IO} alt="IO" />
|
||||
</div>
|
||||
)}
|
||||
<footer className=" frow footer">
|
||||
<div className="container">
|
||||
<p>
|
||||
Hecho en México. Todos los derechos reservados 2024. Esta página
|
||||
puede ser reproducida con fines no lucrativos, siempre y cuando no
|
||||
se mutile, se cite la fuente completa y su dirección electrónica. De
|
||||
otra forma, requiere permiso previo por escrito de la institución.
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,23 +1,17 @@
|
||||
import React from "react";
|
||||
import "./style.css";
|
||||
import logo1 from "../assets/img/escudo-b2.png";
|
||||
import logo2 from "../assets/img/logo_unam-b.png";
|
||||
|
||||
const Header = () => {
|
||||
return (
|
||||
<header className="header">
|
||||
<a href="https://www.unam.mx/">
|
||||
<img
|
||||
className="logo"
|
||||
alt="Logo 1"
|
||||
src="https://www.unam.mx/sites/all/themes/unam/logo.png"
|
||||
/>
|
||||
<img className="logo" alt="Logo 1" src={logo1} />
|
||||
</a>
|
||||
|
||||
<a href="https://www.acatlan.unam.mx/">
|
||||
<img
|
||||
className="logo"
|
||||
alt="Logo 2"
|
||||
src="https://www.acatlan.unam.mx/img/logo_fesa.png"
|
||||
/>
|
||||
<img className="logo" alt="Logo 2" src={logo2} />
|
||||
</a>
|
||||
</header>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
.nav-link .bg-warning {
|
||||
background-color: #002b7a !important;
|
||||
.nav-link {
|
||||
color: #212529 !important;
|
||||
}
|
||||
|
||||
@@ -42,14 +41,27 @@
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.red{
|
||||
.red {
|
||||
background-color: rgb(193, 17, 17);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.container{
|
||||
.container {
|
||||
border: 2px solid rgb(77, 77, 77);
|
||||
border-radius: 8px;
|
||||
margin: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.notButton {
|
||||
text-align: start;
|
||||
background: none;
|
||||
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">
|
||||
<li className="nav-item">
|
||||
<a
|
||||
className="nav-link"
|
||||
<button
|
||||
className="nav-link notButton"
|
||||
onClick={() =>
|
||||
(window.location.href = PrivateRoutes.CREARPROFESOR)
|
||||
}
|
||||
>
|
||||
Crear Profesor
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
|
||||
<li className="nav-item">
|
||||
<a
|
||||
className="nav-link"
|
||||
<button
|
||||
className="nav-link notButton"
|
||||
onClick={() => (window.location.href = PublicRoutes.FILTER)}
|
||||
>
|
||||
Editar Profesor
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
</div>
|
||||
|
||||
{permissions === 1 && (
|
||||
<div className="container">
|
||||
<li className="nav-item">
|
||||
<a
|
||||
className="nav-link"
|
||||
<button
|
||||
className="nav-link notButton"
|
||||
onClick={() =>
|
||||
(window.location.href = PrivateRoutes.CREARUSUARIO)
|
||||
}
|
||||
>
|
||||
Crear Usuario
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<a
|
||||
className="nav-link"
|
||||
<button
|
||||
className="nav-link notButton"
|
||||
onClick={() =>
|
||||
(window.location.href = PrivateRoutes.FILTERUSUARIO)
|
||||
}
|
||||
>
|
||||
Editar Usuario
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -7,7 +7,8 @@ import {
|
||||
useEdificio,
|
||||
useUploadImage,
|
||||
} 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 [page, setPage] = useState(1);
|
||||
@@ -24,6 +25,7 @@ const FormProfesor = () => {
|
||||
const [fotoBase64, setFotoBase64] = useState("");
|
||||
const [lineasInvestigacion, setLineasInvestigacion] = useState([]);
|
||||
const [proyectosAcademicos, setProyectosAcademicos] = useState([]);
|
||||
const [datosAcademicos,setDatosAcademicos] = useState([]);
|
||||
const [id_usuario] = useState("1");
|
||||
const [num_trabajador, setNum_trabajador] = useState("");
|
||||
const [rfc, setRfc] = useState("");
|
||||
@@ -37,15 +39,21 @@ const FormProfesor = () => {
|
||||
const [mostrar, setMostrar] = useState(true);
|
||||
const [nombre, setNombre] = useState("");
|
||||
const [grado_maximo, setGrado_maximo] = useState("");
|
||||
const [grados_obtenidos, setGrados_obtenidos] = useState("");
|
||||
|
||||
const { registerTeacher } = useRegisterTeacher();
|
||||
const { updateTeacherImage } = useUpdateTeacherImage();
|
||||
const { uploadImage } = useUploadImage();
|
||||
|
||||
const handlePageChange = (newPage) => {
|
||||
setPage(newPage);
|
||||
};
|
||||
|
||||
const handleGrados_obtenidosChange = (index, value) => {
|
||||
const newGrados = [...datosAcademicos];
|
||||
newGrados[index].grados_obtenidos = value;
|
||||
setDatosAcademicos(newGrados);
|
||||
};
|
||||
|
||||
const handleLineaInvestigacionChange = (index, value) => {
|
||||
const newLineas = [...lineasInvestigacion];
|
||||
newLineas[index].lineas_inv_html = value;
|
||||
@@ -58,6 +66,10 @@ const FormProfesor = () => {
|
||||
setProyectosAcademicos(newProyectos);
|
||||
};
|
||||
|
||||
const addGrados_obtenidos = () => {
|
||||
setDatosAcademicos([...datosAcademicos, { grados_obtenidos: "" }]);
|
||||
};
|
||||
|
||||
const addLineaInvestigacion = () => {
|
||||
setLineasInvestigacion([...lineasInvestigacion, { lineas_inv_html: "" }]);
|
||||
};
|
||||
@@ -66,6 +78,11 @@ const FormProfesor = () => {
|
||||
setProyectosAcademicos([...proyectosAcademicos, { proyecto_html: "" }]);
|
||||
};
|
||||
|
||||
const deleteGrados_obtenidos = (index) => {
|
||||
const newGrados = datosAcademicos.filter((_, i) => i !== index);
|
||||
setDatosAcademicos(newGrados);
|
||||
};
|
||||
|
||||
const deleteLineaInvestigacion = (index) => {
|
||||
const newLineas = lineasInvestigacion.filter((_, i) => i !== index);
|
||||
setLineasInvestigacion(newLineas);
|
||||
@@ -89,7 +106,7 @@ const FormProfesor = () => {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!grado_maximo || !grados_obtenidos || !correo_pcp) {
|
||||
if (!grado_maximo || !correo_pcp) {
|
||||
alert(
|
||||
"Por favor, complete todos los campos requeridos en Datos Académicos."
|
||||
);
|
||||
@@ -97,17 +114,17 @@ const FormProfesor = () => {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -116,19 +133,15 @@ const FormProfesor = () => {
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
|
||||
if (!validateForm()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
let imageUrl = "";
|
||||
|
||||
if (fotoBase64) {
|
||||
imageUrl = await uploadImage(fotoBase64, nombre);
|
||||
}
|
||||
|
||||
const data = {
|
||||
const id_profesor = await registerTeacher({
|
||||
nombre,
|
||||
id_usuario,
|
||||
num_trabajador,
|
||||
@@ -147,16 +160,23 @@ const FormProfesor = () => {
|
||||
activo,
|
||||
lineasInvestigacion,
|
||||
proyectosAcademicos,
|
||||
datosAcademicos: [
|
||||
{
|
||||
grado_maximo,
|
||||
grados_obtenidos,
|
||||
},
|
||||
],
|
||||
datosAcademicos: datosAcademicos.map(dato => ({
|
||||
...dato,
|
||||
grado_maximo: grado_maximo || dato.grado_maximo
|
||||
})),
|
||||
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) {
|
||||
if (error.response && error.response.status === 403) {
|
||||
if (error.response.data.message === "RFC already exists") {
|
||||
@@ -178,6 +198,7 @@ const FormProfesor = () => {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const onDrop = useCallback((acceptedFiles) => {
|
||||
const file = acceptedFiles[0];
|
||||
@@ -305,19 +326,6 @@ const FormProfesor = () => {
|
||||
/>
|
||||
</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">
|
||||
<label>
|
||||
Correo Pcpuma <span className="required">*</span>
|
||||
@@ -400,7 +408,7 @@ const FormProfesor = () => {
|
||||
|
||||
{page === 3 && (
|
||||
<div className="form-section">
|
||||
<h2>Datos de Investigación</h2>
|
||||
<h2>Datos Académicos</h2>
|
||||
<div className="form-group">
|
||||
<label>
|
||||
Categoría <span className="required">*</span>
|
||||
@@ -477,6 +485,7 @@ const FormProfesor = () => {
|
||||
<p>
|
||||
Arrastra y suelta la imagen aquí, o haz clic para
|
||||
seleccionar una imagen
|
||||
Peso maximo de la imagen 2MB
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
@@ -497,18 +506,55 @@ const FormProfesor = () => {
|
||||
|
||||
{page === 4 && (
|
||||
<div className="form-section">
|
||||
<h2>Lineas de Investigacion</h2>
|
||||
<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>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="boton"
|
||||
onClick={addGrados_obtenidos}
|
||||
>
|
||||
Agregar Grados
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{page === 5 && (
|
||||
<div className="form-section">
|
||||
<h2>Líneas de Investigación</h2>
|
||||
<div className="form-group">
|
||||
{lineasInvestigacion.map((linea, index) => (
|
||||
<div key={index} className="input-with-delete">
|
||||
<label>
|
||||
Lineas de Investigacion {index + 1}
|
||||
Línea de Investigación {index + 1}
|
||||
<span className="required">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name={`lineas_inv_${index}`}
|
||||
value={linea.lineas_inv}
|
||||
value={linea.lineas_inv_html}
|
||||
onChange={(e) =>
|
||||
handleLineaInvestigacionChange(index, e.target.value)
|
||||
}
|
||||
@@ -532,7 +578,7 @@ const FormProfesor = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{page === 5 && (
|
||||
{page === 6 && (
|
||||
<div className="form-section">
|
||||
<h2>Proyectos Académicos</h2>
|
||||
<div className="form-group">
|
||||
@@ -545,7 +591,7 @@ const FormProfesor = () => {
|
||||
<input
|
||||
type="text"
|
||||
name={`proyecto_${index}`}
|
||||
value={proyecto.proyecto}
|
||||
value={proyecto.proyecto_html}
|
||||
onChange={(e) =>
|
||||
handleProyectoAcademicoChange(index, e.target.value)
|
||||
}
|
||||
@@ -570,7 +616,7 @@ const FormProfesor = () => {
|
||||
)}
|
||||
|
||||
<div className="button-container">
|
||||
{page === 5 && (
|
||||
{page === 6 && (
|
||||
<button type="submit" className="small-button">
|
||||
Registrar
|
||||
</button>
|
||||
@@ -628,7 +674,15 @@ const FormProfesor = () => {
|
||||
5
|
||||
</button>
|
||||
</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
|
||||
className="page-link nextButtons"
|
||||
onClick={() => handlePageChange(page + 1)}
|
||||
@@ -642,4 +696,4 @@ const FormProfesor = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default FormProfesor;
|
||||
export default FormProfesor;
|
||||
@@ -13,6 +13,8 @@ import {
|
||||
useUpdateTeacher,
|
||||
} from "../../../services/teacher.services";
|
||||
|
||||
const API_URL = process.env.REACT_APP_API_URL;
|
||||
|
||||
const FormEditProfesor = () => {
|
||||
const { id_profesor } = useParams();
|
||||
const [profesor, setProfesor] = useState(null);
|
||||
@@ -30,7 +32,7 @@ const FormEditProfesor = () => {
|
||||
const [fotoBase64, setFotoBase64] = useState("");
|
||||
const [lineasInvestigacion, setLineasInvestigacion] = useState([]);
|
||||
const [proyectosAcademicos, setProyectosAcademicos] = useState([]);
|
||||
|
||||
const [datosAcademicos, setDatosAcademicos] = useState([]);
|
||||
const [num_trabajador, setNum_trabajador] = useState("");
|
||||
const [rfc, setRfc] = useState("");
|
||||
const [homoclave, setHomoclave] = useState("");
|
||||
@@ -44,8 +46,6 @@ const FormEditProfesor = () => {
|
||||
const [nombre, setNombre] = useState("");
|
||||
|
||||
const [grado_maximo, setGrado_maximo] = useState("");
|
||||
const [grados_obtenidos, setGrados_obtenidos] = useState("");
|
||||
|
||||
const [errorMessage, setErrorMessage] = useState("");
|
||||
const { teacher } = useTeacher(id_profesor);
|
||||
const { updateTeacher } = useUpdateTeacher();
|
||||
@@ -65,6 +65,7 @@ const FormEditProfesor = () => {
|
||||
setActivo(teacher.activo);
|
||||
setLineasInvestigacion(teacher.lineasInvestigacion);
|
||||
setProyectosAcademicos(teacher.proyectosAcademicos);
|
||||
setDatosAcademicos(teacher.datosAcademicos);
|
||||
setNum_trabajador(teacher.num_trabajador);
|
||||
setRfc(teacher.rfc);
|
||||
setHomoclave(teacher.homoclave);
|
||||
@@ -75,11 +76,20 @@ const FormEditProfesor = () => {
|
||||
setCorreo_per(teacher.correo_per);
|
||||
setUbicacion(teacher.ubicacion);
|
||||
setGrado_maximo(teacher.datosAcademicos[0]?.grado_maximo || "");
|
||||
setGrados_obtenidos(teacher.datosAcademicos[0]?.grados_obtenidos || "");
|
||||
setOldFoto(teacher.fotografia);
|
||||
if(teacher.fotografia.startsWith("http")){
|
||||
setOldFoto(teacher.fotografia);
|
||||
}else{
|
||||
setOldFoto(`${API_URL}/imagenes/${teacher.fotografia}`);
|
||||
}
|
||||
}
|
||||
}, [teacher]);
|
||||
|
||||
const handleGrados_obtenidosChange = (index, value) => {
|
||||
const newGrados = [...datosAcademicos];
|
||||
newGrados[index].grados_obtenidos = value;
|
||||
setDatosAcademicos(newGrados);
|
||||
};
|
||||
|
||||
const handleLineaInvestigacionChange = (index, value) => {
|
||||
const newLineas = [...lineasInvestigacion];
|
||||
newLineas[index].lineas_inv_html = value;
|
||||
@@ -92,6 +102,10 @@ const FormEditProfesor = () => {
|
||||
setProyectosAcademicos(newProyectos);
|
||||
};
|
||||
|
||||
const addGrados_obtenidos = () => {
|
||||
setDatosAcademicos([...datosAcademicos, { grados_obtenidos: "" }]);
|
||||
};
|
||||
|
||||
const addLineaInvestigacion = () => {
|
||||
setLineasInvestigacion([...lineasInvestigacion, { lineas_inv_html: "" }]);
|
||||
};
|
||||
@@ -100,6 +114,11 @@ const FormEditProfesor = () => {
|
||||
setProyectosAcademicos([...proyectosAcademicos, { proyecto_html: "" }]);
|
||||
};
|
||||
|
||||
const deleteGrados_obtenidos = (index) => {
|
||||
const newGrados = datosAcademicos.filter((_, i) => i !== index);
|
||||
setDatosAcademicos(newGrados);
|
||||
};
|
||||
|
||||
const deleteLineaInvestigacion = (index) => {
|
||||
const newLineas = lineasInvestigacion.filter((_, i) => i !== index);
|
||||
setLineasInvestigacion(newLineas);
|
||||
@@ -123,9 +142,14 @@ const FormEditProfesor = () => {
|
||||
|
||||
try {
|
||||
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 = {
|
||||
...profesor,
|
||||
nombre,
|
||||
@@ -145,12 +169,7 @@ const FormEditProfesor = () => {
|
||||
activo,
|
||||
lineasInvestigacion,
|
||||
proyectosAcademicos,
|
||||
datosAcademicos: [
|
||||
{
|
||||
grado_maximo,
|
||||
grados_obtenidos,
|
||||
},
|
||||
],
|
||||
datosAcademicos: updatedDatosAcademicos,
|
||||
fotografia: imageUrl || profesor.fotografia,
|
||||
};
|
||||
|
||||
@@ -284,27 +303,21 @@ const FormEditProfesor = () => {
|
||||
<div className="form-section">
|
||||
<h2>Datos Académicos</h2>
|
||||
<div className="form-group">
|
||||
<label>
|
||||
Grado Maximo <span className="required">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="grado_maximo"
|
||||
value={grado_maximo}
|
||||
onChange={(e) => setGrado_maximo(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label>
|
||||
Grados Obtenidos <span className="required">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="grados_obtenidos"
|
||||
value={grados_obtenidos}
|
||||
onChange={(e) => setGrados_obtenidos(e.target.value)}
|
||||
/>
|
||||
{datosAcademicos.length > 0 && datosAcademicos[0].grado_maximo ? ( // Verifica que haya al menos un dato y que tenga grado_maximo
|
||||
<div>
|
||||
<label>
|
||||
Grado Máximo <span className="required">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="grado_maximo"
|
||||
value={datosAcademicos[0].grado_maximo}
|
||||
onChange={(e) => setGrado_maximo(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div>No hay grado máximo registrado.</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
@@ -386,7 +399,7 @@ const FormEditProfesor = () => {
|
||||
|
||||
{page === 3 && (
|
||||
<div className="form-section">
|
||||
<h2>Datos de Investigación</h2>
|
||||
<h2>Datos académicos</h2>
|
||||
<div className="form-group">
|
||||
<label>
|
||||
Categoría <span className="required">*</span>
|
||||
@@ -464,6 +477,7 @@ const FormEditProfesor = () => {
|
||||
<p>
|
||||
Arrastra y suelta la imagen aquí, o haz clic para
|
||||
seleccionar una imagen
|
||||
Peso maximo de la imagen 2MB
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
@@ -497,12 +511,49 @@ const FormEditProfesor = () => {
|
||||
|
||||
{page === 4 && (
|
||||
<div className="form-section">
|
||||
<h2>Lineas de Investigacion</h2>
|
||||
<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>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="boton"
|
||||
onClick={addGrados_obtenidos}
|
||||
>
|
||||
Agregar Grados
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{page === 5 && (
|
||||
<div className="form-section">
|
||||
<h2>Líneas de Investigación</h2>
|
||||
<div className="form-group">
|
||||
{lineasInvestigacion.map((linea, index) => (
|
||||
<div key={index} className="input-with-delete">
|
||||
<label>
|
||||
Lineas de Investigacion {index + 1}
|
||||
Líneas de Investigación {index + 1}
|
||||
<span className="required">*</span>
|
||||
</label>
|
||||
<input
|
||||
@@ -532,7 +583,7 @@ const FormEditProfesor = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{page === 5 && (
|
||||
{page === 6 && (
|
||||
<div className="form-section">
|
||||
<h2>Proyectos Académicos</h2>
|
||||
<div className="form-group">
|
||||
@@ -572,69 +623,76 @@ const FormEditProfesor = () => {
|
||||
<button type="submit" className="btn btn-primary boton">
|
||||
Guardar modificacion
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
||||
<nav aria-label="Page navigation example">
|
||||
<ul className="pagination justify-content-center">
|
||||
<li className={`page-item ${page === 1 ? "disabled" : ""}`}>
|
||||
<button
|
||||
className="page-link prevButtons"
|
||||
onClick={() => handlePageChange(page - 1)}
|
||||
>
|
||||
Anterior
|
||||
</button>
|
||||
</li>
|
||||
<li className={`page-item ${page === 1 ? "active" : ""}`}>
|
||||
<button
|
||||
className="page-link buttons"
|
||||
onClick={() => handlePageChange(1)}
|
||||
>
|
||||
1
|
||||
</button>
|
||||
</li>
|
||||
<li className={`page-item ${page === 2 ? "active" : ""}`}>
|
||||
<button
|
||||
className="page-link buttons"
|
||||
onClick={() => handlePageChange(2)}
|
||||
>
|
||||
2
|
||||
</button>
|
||||
</li>
|
||||
<li className={`page-item ${page === 3 ? "active" : ""}`}>
|
||||
<button
|
||||
className="page-link buttons"
|
||||
onClick={() => handlePageChange(3)}
|
||||
>
|
||||
3
|
||||
</button>
|
||||
</li>
|
||||
<li className={`page-item ${page === 4 ? "active" : ""}`}>
|
||||
<button
|
||||
className="page-link buttons"
|
||||
onClick={() => handlePageChange(4)}
|
||||
>
|
||||
4
|
||||
</button>
|
||||
</li>
|
||||
<li className={`page-item ${page === 5 ? "active" : ""}`}>
|
||||
<button
|
||||
className="page-link buttons"
|
||||
onClick={() => handlePageChange(5)}
|
||||
>
|
||||
5
|
||||
</button>
|
||||
</li>
|
||||
<li className={`page-item ${page === 5 ? "disabled" : ""}`}>
|
||||
<button
|
||||
className="page-link nextButtons"
|
||||
onClick={() => handlePageChange(page + 1)}
|
||||
>
|
||||
Siguiente
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<ul className="pagination justify-content-center">
|
||||
<li className={`page-item ${page === 1 ? "disabled" : ""}`}>
|
||||
<button
|
||||
className="page-link prevButtons"
|
||||
onClick={() => handlePageChange(page - 1)}
|
||||
>
|
||||
Anterior
|
||||
</button>
|
||||
</li>
|
||||
<li className={`page-item ${page === 1 ? "active" : ""}`}>
|
||||
<button
|
||||
className="page-link buttons"
|
||||
onClick={() => handlePageChange(1)}
|
||||
>
|
||||
1
|
||||
</button>
|
||||
</li>
|
||||
<li className={`page-item ${page === 2 ? "active" : ""}`}>
|
||||
<button
|
||||
className="page-link buttons"
|
||||
onClick={() => handlePageChange(2)}
|
||||
>
|
||||
2
|
||||
</button>
|
||||
</li>
|
||||
<li className={`page-item ${page === 3 ? "active" : ""}`}>
|
||||
<button
|
||||
className="page-link buttons"
|
||||
onClick={() => handlePageChange(3)}
|
||||
>
|
||||
3
|
||||
</button>
|
||||
</li>
|
||||
<li className={`page-item ${page === 4 ? "active" : ""}`}>
|
||||
<button
|
||||
className="page-link buttons"
|
||||
onClick={() => handlePageChange(4)}
|
||||
>
|
||||
4
|
||||
</button>
|
||||
</li>
|
||||
<li className={`page-item ${page === 5 ? "active" : ""}`}>
|
||||
<button
|
||||
className="page-link buttons"
|
||||
onClick={() => handlePageChange(5)}
|
||||
>
|
||||
5
|
||||
</button>
|
||||
</li>
|
||||
<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
|
||||
className="page-link nextButtons"
|
||||
onClick={() => handlePageChange(page + 1)}
|
||||
>
|
||||
Siguiente
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
margin-bottom: 20px;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.foto {
|
||||
width: auto;
|
||||
max-width: 40vw;
|
||||
height: 250px;
|
||||
max-height: 25vh;
|
||||
max-height: 50vh;
|
||||
border-radius: 1em;
|
||||
object-fit: cover;
|
||||
}
|
||||
@@ -27,7 +28,7 @@
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
background-color: white;
|
||||
margin: 20px auto;
|
||||
margin: 10px auto;
|
||||
width: 800px;
|
||||
max-width: 90vw;
|
||||
}
|
||||
@@ -38,6 +39,11 @@
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.list{
|
||||
margin-left: 20px;
|
||||
list-style: circle;
|
||||
}
|
||||
|
||||
|
||||
.datos-academicos,
|
||||
.lineas-investigacion,
|
||||
|
||||
@@ -13,6 +13,8 @@ import {
|
||||
useTeacher,
|
||||
} from "../../../services/teacher.services";
|
||||
|
||||
const API_URL = process.env.REACT_APP_API_URL;
|
||||
|
||||
const defaultImage =
|
||||
"https://static.vecteezy.com/system/resources/thumbnails/020/765/399/small_2x/default-profile-account-unknown-icon-black-silhouette-free-vector.jpg";
|
||||
|
||||
@@ -73,6 +75,23 @@ const PerfilProfesor = () => {
|
||||
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 (
|
||||
<div className="form-container">
|
||||
<div className="containerButton">
|
||||
@@ -83,8 +102,20 @@ const PerfilProfesor = () => {
|
||||
<div className="perfil-profesor">
|
||||
<div className="foto-nombre">
|
||||
{fotoProfesor && fotoProfesor.startsWith("http") ? (
|
||||
<img src={fotoProfesor} alt={profesor.nombre} className="foto" />
|
||||
) : null}
|
||||
<img
|
||||
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="nombre">
|
||||
@@ -92,23 +123,23 @@ const PerfilProfesor = () => {
|
||||
</div>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Ubicación: </strong>
|
||||
<strong>Ubicación:</strong>
|
||||
{profesor.ubicacion ? profesor.ubicacion : "NO ubicado"}
|
||||
</li>
|
||||
<li>
|
||||
<strong>Correo: </strong>
|
||||
<strong>Correo:</strong>
|
||||
{profesor.correo_pcp ? profesor.correo_pcp : "No ubicado"}
|
||||
</li>
|
||||
<li>
|
||||
<strong>Teléfono de oficina: </strong>
|
||||
<strong>Teléfono de oficina:</strong>
|
||||
{profesor.tel_oficina ? profesor.tel_oficina : "No ubicado"}
|
||||
</li>
|
||||
<li>
|
||||
<strong>Extensión: </strong>
|
||||
<strong>Extensión:</strong>
|
||||
{profesor.extension ? profesor.extension : "No ubicado"}
|
||||
</li>
|
||||
<li>
|
||||
<strong>Edificio: </strong>
|
||||
<strong>Edificio:</strong>
|
||||
{edificioProfesor ? edificioProfesor.edificio : "No ubicado"}
|
||||
</li>
|
||||
</ul>
|
||||
@@ -120,22 +151,34 @@ const PerfilProfesor = () => {
|
||||
<h4>Datos académicos</h4>
|
||||
</div>
|
||||
<ul>
|
||||
{profesor.datosAcademicos.map((datosAcademicos, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<li key={`grado_maximo_${index}`}>
|
||||
<strong>Grado Máximo:</strong>
|
||||
{datosAcademicos.grado_maximo
|
||||
? datosAcademicos.grado_maximo
|
||||
: "NO encontrado"}
|
||||
</li>
|
||||
<li key={`grados_obtenidos_${index}`}>
|
||||
<strong>Grados Obtenidos:</strong>
|
||||
{datosAcademicos.grados_obtenidos
|
||||
? datosAcademicos.grados_obtenidos
|
||||
: "NO encontrado"}
|
||||
</li>
|
||||
</React.Fragment>
|
||||
))}
|
||||
<li>
|
||||
<strong>Grado Máximo:</strong>
|
||||
{profesor.datosAcademicos.length > 0 ? (
|
||||
profesor.datosAcademicos[0].grado_maximo ? (
|
||||
<>{profesor.datosAcademicos[0].grado_maximo}</>
|
||||
) : (
|
||||
<>No hay Grado Máximo registrado.</>
|
||||
)
|
||||
) : (
|
||||
<li>No hay Datos Académicos registrados.</li>
|
||||
)}
|
||||
</li>
|
||||
|
||||
<strong>Grados Obtenidos:</strong>
|
||||
<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>
|
||||
<strong>Categoría:</strong>
|
||||
{categoriaProfesor ? categoriaProfesor.categoria : "No ubicado"}
|
||||
@@ -154,12 +197,16 @@ const PerfilProfesor = () => {
|
||||
<h4>Líneas de investigación</h4>
|
||||
</div>
|
||||
<ul>
|
||||
<strong>Investigaciones:</strong>
|
||||
{profesor.lineasInvestigacion.length > 0 ? (
|
||||
profesor.lineasInvestigacion.map((linea, index) => (
|
||||
<li key={index}>
|
||||
<strong>Investigacion {index + 1}:</strong>
|
||||
{linea.lineas_inv_html ? linea.lineas_inv_html : "NO encontrado"}
|
||||
</li>
|
||||
<div key={index}>
|
||||
<ul>
|
||||
{linea.lineas_inv_html
|
||||
? splitTextToListItems(linea.lineas_inv_html)
|
||||
: null}
|
||||
</ul>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<li>No hay líneas de investigación registradas.</li>
|
||||
@@ -172,12 +219,16 @@ const PerfilProfesor = () => {
|
||||
<h4>Proyectos académicos</h4>
|
||||
</div>
|
||||
<ul>
|
||||
<strong>Proyectos:</strong>
|
||||
{profesor.proyectosAcademicos.length > 0 ? (
|
||||
profesor.proyectosAcademicos.map((proyecto, index) => (
|
||||
<li key={index}>
|
||||
<strong>Proyecto {index + 1}:</strong>
|
||||
{proyecto.proyecto_html ? proyecto.proyecto_html : "NO encontrado"}
|
||||
</li>
|
||||
<div key={index}>
|
||||
<ul>
|
||||
{proyecto.proyecto_html
|
||||
? splitTextToListItems(proyecto.proyecto_html)
|
||||
: null}
|
||||
</ul>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<li>No hay proyectos académicos registrados.</li>
|
||||
@@ -207,7 +258,7 @@ const PerfilProfesor = () => {
|
||||
</div>
|
||||
|
||||
{showDialog && (
|
||||
<div className="dialog">
|
||||
<div className="dialog" style={{ position: "fixed" }}>
|
||||
<p>
|
||||
¿Deseas eliminar al profesor <strong>{profesor.nombre}</strong>?
|
||||
</p>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import "../../../App.css";
|
||||
import { PrivateRoutes } from "../../../models/routes";
|
||||
import { useUser, useUpdateUser } from "../../../services/user.services";
|
||||
|
||||
const MDUser = () => {
|
||||
|
||||
@@ -4,12 +4,14 @@
|
||||
align-items: center;
|
||||
background-color: #1e3c70 !important;
|
||||
padding: 10px;
|
||||
padding-left: 40px;
|
||||
padding-right: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 300px;
|
||||
max-width: 40vw;
|
||||
width: 50px;
|
||||
max-width: 10vw;
|
||||
}
|
||||
|
||||
.footer {
|
||||
@@ -20,9 +22,35 @@
|
||||
text-align: center;
|
||||
bottom: 0;
|
||||
margin-top: auto;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.footer .container {
|
||||
max-width: 1200px;
|
||||
max-width: 90%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.center{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.img {
|
||||
max-width: 100px;
|
||||
height: auto;
|
||||
object-fit: cover;
|
||||
z-index: -1;
|
||||
opacity: 0;
|
||||
filter: drop-shadow(0 0 8px black);
|
||||
transition: transform 1s ease-in-out, opacity 1s ease-in;
|
||||
}
|
||||
|
||||
.S.show {
|
||||
transform: translateY(24px);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.I.show {
|
||||
transform: translateY(15px);
|
||||
opacity: 1;
|
||||
}
|
||||
@@ -7,7 +7,6 @@ const Id = () => {
|
||||
const jwtPermissions = () => {
|
||||
const jwtToken = localStorage.getItem("Token");
|
||||
if (!jwtToken) {
|
||||
console.error("No se encontró el token en localStorage");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ const Guard = () => {
|
||||
const jwtPermissions = () => {
|
||||
const jwtToken = localStorage.getItem("Token");
|
||||
if (!jwtToken) {
|
||||
console.error("No se encontró el token en localStorage");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,3 +11,6 @@ code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
}
|
||||
*{
|
||||
scrollbar-width: none;
|
||||
}
|
||||
@@ -77,7 +77,7 @@ export const useUploadImage = () => {
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
return `${API_URL}${result.imageUrl}`;
|
||||
return result.imageUrl;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
@@ -112,7 +112,7 @@ export const useUpdateImage = () => {
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
return `${API_URL}${result.imageUrl}`;
|
||||
return result.imageUrl;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -117,34 +117,37 @@ export const useTeachers = (currentPage, filters) => {
|
||||
export const useRegisterTeacher = () => {
|
||||
const token = useToken();
|
||||
|
||||
const registerTeacher = (teacherData) => {
|
||||
return fetch(`${API_URL}/profesor`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
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;
|
||||
const registerTeacher = async (teacherData) => {
|
||||
try {
|
||||
const response = await fetch(`${API_URL}/profesor`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
body: JSON.stringify(teacherData),
|
||||
});
|
||||
|
||||
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 };
|
||||
};
|
||||
|
||||
|
||||
export const useTeacher = (id_profesor) => {
|
||||
const [teacher, setTeacher] = useState(null);
|
||||
|
||||
@@ -196,3 +199,32 @@ export const useUpdateTeacher = () => {
|
||||
|
||||
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