2 Commits

Author SHA1 Message Date
TheManus88 415075a959 port updated 2024-08-08 02:56:56 -06:00
TheManus88 a3a7fce6bf update spaces into profesor description 2024-07-30 22:32:48 -06:00
29 changed files with 295 additions and 732 deletions
+2 -2
View File
@@ -1,2 +1,2 @@
REACT_APP_API_URL=https://venus.acatlan.unam.mx/directorio_test
REACT_APP_PORT=3001
REACT_APP_API_URL=http://192.168.100.7:3000
REACT_APP_PORT=3001
+1 -1
View File
@@ -17,7 +17,7 @@
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "set PORT=3001 && react-scripts start",
"start": "set PORT=3226 && react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
+3 -3
View File
@@ -31,7 +31,7 @@
.edit-button,
.delete-boton {
padding: 4px 12px;
padding: 8px 12px;
margin-right: 10px;
border: none;
cursor: pointer;
@@ -352,7 +352,7 @@ button[type="submit"]:disabled {
}
.delete-botones {
background-image: url("./assets/img/trashcan.png");
background-image: url("https://cdn.icon-icons.com/icons2/1791/PNG/512/trashcan1_114647.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 auto;
margin: 10px;
}
.cargando {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 254 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

+2 -24
View File
@@ -1,7 +1,7 @@
.card {
max-width: 90vw;
width: 400px;
height: 170px;
height: 175px;
margin: auto;
padding: 0.5em;
border-radius: 1em !important;
@@ -11,22 +11,7 @@
flex-direction: row !important;
justify-content: left;
text-align: center;
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);
transition: box-shadow 0.3s ease, transform 0.3s ease;
}
.card:hover {
@@ -52,7 +37,6 @@
display: flex;
justify-content: center;
align-items: center;
max-width: 130px;
}
@@ -72,10 +56,4 @@
.status-label.inactive {
background-color: red;
}
.profesores-container {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
@@ -3,19 +3,13 @@ import "../Card.css";
import { PrivateRoutes, PublicRoutes } from "../../../models/routes";
import { useDeleteTeacher } from "../../../services/teacher.services";
const API_URL = process.env.REACT_APP_API_URL;
const CardProfesor = ({
profesor,
edificioNombre,
permissions,
currentPage,
}) => {
const CardProfesor = ({ profesor, edificioNombre, permissions }) => {
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);
@@ -34,28 +28,20 @@ const CardProfesor = ({
};
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">
<img
src={
profesor.fotografia && profesor.fotografia.startsWith("http")
? profesor.fotografia
: `${API_URL}/imagenes/${profesor.fotografia}`
}
className="imgProfe"
alt={profesor.nombre}
onClick={handleViewProfesor}
onError={handleImageError}
/>
{fotoProfesor && fotoProfesor.startsWith("http") ? (
<img
src={fotoProfesor}
className="imgProfe"
alt={profesor.nombre}
onClick={handleViewProfesor}
/>
) : null}
{permissions ? (
<div
@@ -16,7 +16,6 @@ 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();
@@ -26,7 +25,6 @@ function FilterProfesor() {
categoria,
edificio,
});
setCurrentPage(1);
};
return (
@@ -54,7 +52,7 @@ function FilterProfesor() {
onChange={(e) => setAdscripcion(e.target.value)}
className="form-control me-2"
>
<option value="">Adscripción</option>
<option value="">Adscripcion</option>
{adscripciones.map((adscripcion) => (
<option
key={adscripcion.id_adscripcion}
@@ -71,7 +69,7 @@ function FilterProfesor() {
onChange={(e) => setCategoria(e.target.value)}
className="form-control me-2"
>
<option value="">Categoría</option>
<option value="">Categoria</option>
{categorias.map((categoria) => (
<option
key={categoria.id_categoria}
@@ -99,19 +97,14 @@ function FilterProfesor() {
<button
className="btn me-2"
type="submit"
style={{ background: "#D59F0F", color: "#fff" }}
style={{ background: "#1e3c70", color: "#fff" }}
>
Buscar
</button>
</form>
</div>
</nav>
<Mapeo
filters={filters}
edificios={edificios}
currentPage={currentPage}
setCurrentPage={setCurrentPage}
/>
<Mapeo filters={filters} edificios={edificios} />
</div>
);
}
+24 -72
View File
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react";
import React, { useState } 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, currentPage, setCurrentPage }) => {
const [shownCards, setShownCards] = useState([]);
const Mapeo = ({ filters, edificios }) => {
const [currentPage, setCurrentPage] = useState(1);
const permissions = Guard();
const {
@@ -25,50 +25,6 @@ const Mapeo = ({ filters, edificios, currentPage, setCurrentPage }) => {
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">
@@ -93,20 +49,25 @@ const Mapeo = ({ filters, edificios, currentPage, setCurrentPage }) => {
);
}
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);
@@ -154,29 +115,20 @@ const Mapeo = ({ filters, edificios, currentPage, setCurrentPage }) => {
</div>
) : null}
<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>
{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}
/>
);
})}
<nav aria-label="Page navigation example">
<ul className="pagination justify-content-center">
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import React, { useState } from "react";
import "../../../App.css";
import CardUsuario from "./CardUsuario";
import { PrivateRoutes } from "../../../models/routes";
@@ -8,24 +8,6 @@ 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">
@@ -54,6 +36,7 @@ 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);
@@ -99,13 +82,9 @@ const MapeoUsuario = ({ filters }) => {
</button>
</div>
<div className="profesores-container">
{usuarios.map((usuario) => (
<div className="transition show">
<CardUsuario key={usuario.id_usuario} usuario={usuario} />
</div>
))}
</div>
{usuarios.map((usuario) => (
<CardUsuario key={usuario.id_usuario} usuario={usuario} />
))}
<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: "#D59F0F", color: "#fff" }}
style={{ background: "#1e3c70", color: "#fff" }}
>
Buscar
</button>
+11 -101
View File
@@ -1,108 +1,18 @@
import React, { useState, useEffect } from "react";
import React 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 (
<>
{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>
</>
<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>
);
};
+10 -4
View File
@@ -1,17 +1,23 @@
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={logo1} />
<img
className="logo"
alt="Logo 1"
src="https://www.unam.mx/sites/all/themes/unam/logo.png"
/>
</a>
<a href="https://www.acatlan.unam.mx/">
<img className="logo" alt="Logo 2" src={logo2} />
<img
className="logo"
alt="Logo 2"
src="https://www.acatlan.unam.mx/img/logo_fesa.png"
/>
</a>
</header>
);
+5 -17
View File
@@ -1,4 +1,5 @@
.nav-link {
.nav-link .bg-warning {
background-color: #002b7a !important;
color: #212529 !important;
}
@@ -41,27 +42,14 @@
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
View File
@@ -92,47 +92,47 @@ const Menu = () => {
<div className="container">
<li className="nav-item">
<button
className="nav-link notButton"
<a
className="nav-link"
onClick={() =>
(window.location.href = PrivateRoutes.CREARPROFESOR)
}
>
Crear Profesor
</button>
</a>
</li>
<li className="nav-item">
<button
className="nav-link notButton"
<a
className="nav-link"
onClick={() => (window.location.href = PublicRoutes.FILTER)}
>
Editar Profesor
</button>
</a>
</li>
</div>
{permissions === 1 && (
<div className="container">
<li className="nav-item">
<button
className="nav-link notButton"
<a
className="nav-link"
onClick={() =>
(window.location.href = PrivateRoutes.CREARUSUARIO)
}
>
Crear Usuario
</button>
</a>
</li>
<li className="nav-item">
<button
className="nav-link notButton"
<a
className="nav-link"
onClick={() =>
(window.location.href = PrivateRoutes.FILTERUSUARIO)
}
>
Editar Usuario
</button>
</a>
</li>
</div>
)}
@@ -7,8 +7,7 @@ import {
useEdificio,
useUploadImage,
} from "../../../services/auth.services";
import { useRegisterTeacher, useUpdateTeacherImage } from "../../../services/teacher.services";
import { PublicRoutes } from "../../../models/routes";
import { useRegisterTeacher } from "../../../services/teacher.services";
const FormProfesor = () => {
const [page, setPage] = useState(1);
@@ -25,7 +24,6 @@ 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("");
@@ -39,21 +37,15 @@ 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;
@@ -66,10 +58,6 @@ const FormProfesor = () => {
setProyectosAcademicos(newProyectos);
};
const addGrados_obtenidos = () => {
setDatosAcademicos([...datosAcademicos, { grados_obtenidos: "" }]);
};
const addLineaInvestigacion = () => {
setLineasInvestigacion([...lineasInvestigacion, { lineas_inv_html: "" }]);
};
@@ -78,11 +66,6 @@ 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);
@@ -106,7 +89,7 @@ const FormProfesor = () => {
return false;
}
if (!grado_maximo || !correo_pcp) {
if (!grado_maximo || !grados_obtenidos || !correo_pcp) {
alert(
"Por favor, complete todos los campos requeridos en Datos Académicos."
);
@@ -114,17 +97,17 @@ const FormProfesor = () => {
}
if (!id_categoria) {
alert("Por favor, Coloque la categoría en Datos académicos.");
alert("Por favor, Coloque la categoria en Datos de Investigación.");
return false;
}
if (!id_adscripcion) {
alert("Por favor, Coloque la adscripción en Datos académicos.");
alert("Por favor, Coloque la adscripcion en Datos de Investigación.");
return false;
}
if (!id_edificio) {
alert("Por favor, Coloque el edificio en Datos académicos.");
alert("Por favor, Coloque el edificio en Datos de Investigación.");
return false;
}
@@ -133,15 +116,19 @@ const FormProfesor = () => {
const handleSubmit = async (event) => {
event.preventDefault();
if (!validateForm()) {
return;
}
try {
let imageUrl = "";
const id_profesor = await registerTeacher({
if (fotoBase64) {
imageUrl = await uploadImage(fotoBase64, nombre);
}
const data = {
nombre,
id_usuario,
num_trabajador,
@@ -160,23 +147,16 @@ const FormProfesor = () => {
activo,
lineasInvestigacion,
proyectosAcademicos,
datosAcademicos: datosAcademicos.map(dato => ({
...dato,
grado_maximo: grado_maximo || dato.grado_maximo
})),
datosAcademicos: [
{
grado_maximo,
grados_obtenidos,
},
],
fotografia: imageUrl,
});
if (fotoBase64) {
imageUrl = await uploadImage(fotoBase64, id_profesor);
}
if (imageUrl) {
await updateTeacherImage(id_profesor, imageUrl);
}
window.location.href = PublicRoutes.FILTER;
};
registerTeacher(data);
} catch (error) {
if (error.response && error.response.status === 403) {
if (error.response.data.message === "RFC already exists") {
@@ -198,7 +178,6 @@ const FormProfesor = () => {
}
}
};
const onDrop = useCallback((acceptedFiles) => {
const file = acceptedFiles[0];
@@ -326,6 +305,19 @@ 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>
@@ -408,7 +400,7 @@ const FormProfesor = () => {
{page === 3 && (
<div className="form-section">
<h2>Datos Académicos</h2>
<h2>Datos de Investigación</h2>
<div className="form-group">
<label>
Categoría <span className="required">*</span>
@@ -485,7 +477,6 @@ const FormProfesor = () => {
<p>
Arrastra y suelta la imagen aquí, o haz clic para
seleccionar una imagen
Peso maximo de la imagen 2MB
</p>
)}
</div>
@@ -506,55 +497,18 @@ const FormProfesor = () => {
{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>
<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>
<h2>Lineas de Investigacion</h2>
<div className="form-group">
{lineasInvestigacion.map((linea, index) => (
<div key={index} className="input-with-delete">
<label>
Línea de Investigación {index + 1}
Lineas de Investigacion {index + 1}
<span className="required">*</span>
</label>
<input
type="text"
name={`lineas_inv_${index}`}
value={linea.lineas_inv_html}
value={linea.lineas_inv}
onChange={(e) =>
handleLineaInvestigacionChange(index, e.target.value)
}
@@ -578,7 +532,7 @@ const FormProfesor = () => {
</div>
)}
{page === 6 && (
{page === 5 && (
<div className="form-section">
<h2>Proyectos Académicos</h2>
<div className="form-group">
@@ -591,7 +545,7 @@ const FormProfesor = () => {
<input
type="text"
name={`proyecto_${index}`}
value={proyecto.proyecto_html}
value={proyecto.proyecto}
onChange={(e) =>
handleProyectoAcademicoChange(index, e.target.value)
}
@@ -616,7 +570,7 @@ const FormProfesor = () => {
)}
<div className="button-container">
{page === 6 && (
{page === 5 && (
<button type="submit" className="small-button">
Registrar
</button>
@@ -674,15 +628,7 @@ const FormProfesor = () => {
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" : ""}`}>
<li className={`page-item ${page === 5 ? "disabled" : ""}`}>
<button
className="page-link nextButtons"
onClick={() => handlePageChange(page + 1)}
@@ -696,4 +642,4 @@ const FormProfesor = () => {
);
};
export default FormProfesor;
export default FormProfesor;
@@ -13,8 +13,6 @@ 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);
@@ -32,7 +30,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("");
@@ -46,6 +44,8 @@ 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,7 +65,6 @@ 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);
@@ -76,20 +75,11 @@ const FormEditProfesor = () => {
setCorreo_per(teacher.correo_per);
setUbicacion(teacher.ubicacion);
setGrado_maximo(teacher.datosAcademicos[0]?.grado_maximo || "");
if(teacher.fotografia.startsWith("http")){
setOldFoto(teacher.fotografia);
}else{
setOldFoto(`${API_URL}/imagenes/${teacher.fotografia}`);
}
setGrados_obtenidos(teacher.datosAcademicos[0]?.grados_obtenidos || "");
setOldFoto(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;
@@ -102,10 +92,6 @@ const FormEditProfesor = () => {
setProyectosAcademicos(newProyectos);
};
const addGrados_obtenidos = () => {
setDatosAcademicos([...datosAcademicos, { grados_obtenidos: "" }]);
};
const addLineaInvestigacion = () => {
setLineasInvestigacion([...lineasInvestigacion, { lineas_inv_html: "" }]);
};
@@ -114,11 +100,6 @@ 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);
@@ -142,14 +123,9 @@ const FormEditProfesor = () => {
try {
if (fotoBase64) {
imageUrl = await updateImage(fotoBase64, id_profesor);
imageUrl = await updateImage(fotoBase64, nombre);
}
const updatedDatosAcademicos = datosAcademicos.map((dato) => ({
...dato,
grado_maximo: grado_maximo || dato.grado_maximo,
}));
const profesorData = {
...profesor,
nombre,
@@ -169,7 +145,12 @@ const FormEditProfesor = () => {
activo,
lineasInvestigacion,
proyectosAcademicos,
datosAcademicos: updatedDatosAcademicos,
datosAcademicos: [
{
grado_maximo,
grados_obtenidos,
},
],
fotografia: imageUrl || profesor.fotografia,
};
@@ -303,21 +284,27 @@ const FormEditProfesor = () => {
<div className="form-section">
<h2>Datos Académicos</h2>
<div className="form-group">
{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>
)}
<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)}
/>
</div>
<div className="form-group">
@@ -399,7 +386,7 @@ const FormEditProfesor = () => {
{page === 3 && (
<div className="form-section">
<h2>Datos académicos</h2>
<h2>Datos de Investigación</h2>
<div className="form-group">
<label>
Categoría <span className="required">*</span>
@@ -477,7 +464,6 @@ const FormEditProfesor = () => {
<p>
Arrastra y suelta la imagen aquí, o haz clic para
seleccionar una imagen
Peso maximo de la imagen 2MB
</p>
)}
</div>
@@ -511,49 +497,12 @@ const FormEditProfesor = () => {
{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>
<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>
<h2>Lineas de Investigacion</h2>
<div className="form-group">
{lineasInvestigacion.map((linea, index) => (
<div key={index} className="input-with-delete">
<label>
Líneas de Investigación {index + 1}
Lineas de Investigacion {index + 1}
<span className="required">*</span>
</label>
<input
@@ -583,7 +532,7 @@ const FormEditProfesor = () => {
</div>
)}
{page === 6 && (
{page === 5 && (
<div className="form-section">
<h2>Proyectos Académicos</h2>
<div className="form-group">
@@ -623,76 +572,69 @@ 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 === 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>
<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>
</div>
);
};
@@ -3,14 +3,13 @@
align-items: center;
justify-content: space-evenly;
margin-bottom: 20px;
gap: 20px;
}
.foto {
width: auto;
max-width: 40vw;
height: 250px;
max-height: 50vh;
max-height: 25vh;
border-radius: 1em;
object-fit: cover;
}
@@ -28,7 +27,7 @@
border: 1px solid #ccc;
border-radius: 5px;
background-color: white;
margin: 10px auto;
margin: 20px auto;
width: 800px;
max-width: 90vw;
}
@@ -39,11 +38,6 @@
align-items: start;
}
.list{
margin-left: 20px;
list-style: circle;
}
.datos-academicos,
.lineas-investigacion,
@@ -13,8 +13,6 @@ 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";
@@ -75,23 +73,6 @@ 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">
@@ -102,20 +83,8 @@ const PerfilProfesor = () => {
<div className="perfil-profesor">
<div className="foto-nombre">
{fotoProfesor && fotoProfesor.startsWith("http") ? (
<img
src={fotoProfesor}
alt={profesor.nombre}
className="foto"
onError={handleImageError}
/>
) : (
<img
src={`${API_URL}/imagenes/${profesor.fotografia}`}
alt={profesor.nombre}
className="foto"
onError={handleImageError}
/>
)}
<img src={fotoProfesor} alt={profesor.nombre} className="foto" />
) : null}
<div className="info">
<div className="nombre">
@@ -123,23 +92,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>
@@ -151,34 +120,22 @@ const PerfilProfesor = () => {
<h4>Datos académicos</h4>
</div>
<ul>
<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>
{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>Categoría:</strong>
{categoriaProfesor ? categoriaProfesor.categoria : "No ubicado"}
@@ -197,16 +154,12 @@ const PerfilProfesor = () => {
<h4>Líneas de investigación</h4>
</div>
<ul>
<strong>Investigaciones:</strong>
{profesor.lineasInvestigacion.length > 0 ? (
profesor.lineasInvestigacion.map((linea, index) => (
<div key={index}>
<ul>
{linea.lineas_inv_html
? splitTextToListItems(linea.lineas_inv_html)
: null}
</ul>
</div>
<li key={index}>
<strong>Investigacion {index + 1}:</strong>
{linea.lineas_inv_html ? linea.lineas_inv_html : "NO encontrado"}
</li>
))
) : (
<li>No hay líneas de investigación registradas.</li>
@@ -219,16 +172,12 @@ const PerfilProfesor = () => {
<h4>Proyectos académicos</h4>
</div>
<ul>
<strong>Proyectos:</strong>
{profesor.proyectosAcademicos.length > 0 ? (
profesor.proyectosAcademicos.map((proyecto, index) => (
<div key={index}>
<ul>
{proyecto.proyecto_html
? splitTextToListItems(proyecto.proyecto_html)
: null}
</ul>
</div>
<li key={index}>
<strong>Proyecto {index + 1}:</strong>
{proyecto.proyecto_html ? proyecto.proyecto_html : "NO encontrado"}
</li>
))
) : (
<li>No hay proyectos académicos registrados.</li>
@@ -258,7 +207,7 @@ const PerfilProfesor = () => {
</div>
{showDialog && (
<div className="dialog" style={{ position: "fixed" }}>
<div className="dialog">
<p>
¿Deseas eliminar al profesor <strong>{profesor.nombre}</strong>?
</p>
@@ -1,6 +1,7 @@
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 = () => {
+3 -31
View File
@@ -4,14 +4,12 @@
align-items: center;
background-color: #1e3c70 !important;
padding: 10px;
padding-left: 40px;
padding-right: 40px;
text-align: center;
}
.logo {
width: 50px;
max-width: 10vw;
width: 300px;
max-width: 40vw;
}
.footer {
@@ -22,35 +20,9 @@
text-align: center;
bottom: 0;
margin-top: auto;
padding: 10px;
}
.footer .container {
max-width: 90%;
max-width: 1200px;
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;
}
+1
View File
@@ -7,6 +7,7 @@ const Id = () => {
const jwtPermissions = () => {
const jwtToken = localStorage.getItem("Token");
if (!jwtToken) {
console.error("No se encontró el token en localStorage");
return;
}
+1
View File
@@ -7,6 +7,7 @@ const Guard = () => {
const jwtPermissions = () => {
const jwtToken = localStorage.getItem("Token");
if (!jwtToken) {
console.error("No se encontró el token en localStorage");
return;
}
-3
View File
@@ -11,6 +11,3 @@ code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
*{
scrollbar-width: none;
}
+2 -2
View File
@@ -77,7 +77,7 @@ export const useUploadImage = () => {
}
const result = await response.json();
return result.imageUrl;
return `${API_URL}${result.imageUrl}`;
} catch (error) {
throw error;
}
@@ -112,7 +112,7 @@ export const useUpdateImage = () => {
}
const result = await response.json();
return result.imageUrl;
return `${API_URL}${result.imageUrl}`;
} catch (error) {
throw error;
}
+22 -54
View File
@@ -117,37 +117,34 @@ export const useTeachers = (currentPage, filters) => {
export const useRegisterTeacher = () => {
const token = useToken();
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),
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;
});
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);
@@ -199,32 +196,3 @@ 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 };
};