diff --git a/src/components/CardEditProfesor.css b/src/components/CardEditProfesor/CardEditProfesor.css similarity index 100% rename from src/components/CardEditProfesor.css rename to src/components/CardEditProfesor/CardEditProfesor.css diff --git a/src/components/CardEditProfesor.js b/src/components/CardEditProfesor/CardEditProfesor.js similarity index 100% rename from src/components/CardEditProfesor.js rename to src/components/CardEditProfesor/CardEditProfesor.js diff --git a/src/components/NavUsuario.css b/src/components/CardUsuarios/NavUsuario.css similarity index 100% rename from src/components/NavUsuario.css rename to src/components/CardUsuarios/NavUsuario.css diff --git a/src/components/CrearProfesor/FormProfesor.js b/src/components/CrearProfesor/FormProfesor.js index 347d1a8..5d11ac1 100644 --- a/src/components/CrearProfesor/FormProfesor.js +++ b/src/components/CrearProfesor/FormProfesor.js @@ -107,6 +107,7 @@ const FormProfesor = () => { activo, lineasInvestigacion, proyectosAcademicos, + foto: fotoBase64, }; const token = localStorage.getItem('Token'); @@ -143,7 +144,7 @@ const FormProfesor = () => { const onDrop = useCallback(acceptedFiles => { const file = acceptedFiles[0]; setFoto(file); - + const reader = new FileReader(); reader.onloadend = () => { const base64String = reader.result; @@ -193,13 +194,11 @@ const FormProfesor = () => {

Datos Académicos

- +
- +
@@ -279,8 +278,8 @@ const FormProfesor = () => { onChange={(e) => handleSelectChange(e, setActivo)} className="form-control m-2" > - - + +
@@ -294,7 +293,7 @@ const FormProfesor = () => { )}
{foto &&

Archivo seleccionado: {foto.name}

} - {fotoBase64 && Foto seleccionada} + {fotoBase64 && Preview} )} @@ -398,5 +397,4 @@ const FormProfesor = () => { ); }; -export default FormProfesor; - +export default FormProfesor; \ No newline at end of file diff --git a/src/components/Formulario.css b/src/components/Formulario/Formulario.css similarity index 100% rename from src/components/Formulario.css rename to src/components/Formulario/Formulario.css diff --git a/src/components/Formulario.js b/src/components/Formulario/Formulario.js similarity index 100% rename from src/components/Formulario.js rename to src/components/Formulario/Formulario.js diff --git a/src/components/InterResp.css b/src/components/InterResp/InterResp.css similarity index 100% rename from src/components/InterResp.css rename to src/components/InterResp/InterResp.css diff --git a/src/components/InterResp.js b/src/components/InterResp/InterResp.js similarity index 100% rename from src/components/InterResp.js rename to src/components/InterResp/InterResp.js diff --git a/src/components/LoginForm/LoginForm.css b/src/components/LoginForm/LoginForm.css new file mode 100644 index 0000000..0005624 --- /dev/null +++ b/src/components/LoginForm/LoginForm.css @@ -0,0 +1,139 @@ +/* components/LoginForm.css */ + +.main-content { + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 20px; +} + +.login-form { + max-width: 300px; + width: 100%; + margin: auto; + padding: 1.5em; + background: white; + box-shadow: 0 4px 8px 2px rgba(0, 0, 0, 0.1); + border-radius: 1em; +} + +h1.text-warning { + color: #ffc107; + text-align: center; +} + +h2.m-3 { + margin: 20px 0; + text-align: center; +} + +.input-group { + margin-bottom: 0.75em; +} + +label { + margin-bottom: 0.5em; + color: #333333; + display: block; + font-size: 0.9em; +} + +.login input[type="text"], +.login input[type="password"] { + border: 1px solid #CCCCCC; + padding: 0.4em; + font-size: 0.9em; + width: 100%; + box-sizing: border-box; + border-radius: 5px; + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 2px 4px 1px rgba(0, 0, 0, 0.1); + transition: box-shadow 0.3s ease; +} + +.login input[type="text"]:focus, +.login input[type="password"]:focus { + box-shadow: 0 0 8px 2px rgba(0, 123, 255, 0.5); + outline: none; +} + +.remember-me-group { + display: flex; + align-items: center; + margin-bottom: 1em; +} + +.remember-me-label { + margin-left: 0.5em; +} + +input[type="checkbox"] { + width: 18px !important; /* Incremento de tamaño */ + height: 18px !important; /* Incremento de tamaño */ + border: 1px solid #CCCCCC !important; + border-radius: 3px !important; + background-color: #fff; + appearance: none; + cursor: pointer !important; + position: relative !important; + transition: background-color 0.3s ease, border-color 0.3s ease !important; +} + +input[type="checkbox"]:checked::before { + content: '✔'; + font-size: 14px; + color: #007bff !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + transform: translate(-50%, -55%) !important; /* Ajuste para centrar la paloma */ +} + +input[type="checkbox"]:focus { + box-shadow: 0 0 5px 2px rgba(0, 123, 255, 0.5); + outline: none; +} + +.btn-group .btn { + padding: 0.6em 1em; + border: 1px solid #007bff; + border-radius: 0.25em; + background-color: transparent; + color: #007bff; + cursor: pointer; + transition: background-color 0.3s, color 0.3s; +} + +.btn-group .btn.active { + background-color: #007bff; + color: #fff; +} + +button[type="submit"] { + width: 100%; + padding: 0.75em; + border: none; + border-radius: 1em; + background-color: #002B7A; + color: #fff; + font-size: 0.9em; + cursor: pointer; + transition: background-color 0.3s ease, box-shadow 0.3s ease; +} + +button[type="submit"]:hover { + background-color: #0056b3; + box-shadow: 0 6px 12px 4px rgba(0, 0, 0, 0.2); +} + +button[type="submit"]:disabled { + background-color: #007bff; + cursor: not-allowed; + opacity: 0.6; +} + +p { + text-align: center; + margin-top: 1em; +} diff --git a/src/components/LoginForm/LoginForm.js b/src/components/LoginForm/LoginForm.js new file mode 100644 index 0000000..cbc44a3 --- /dev/null +++ b/src/components/LoginForm/LoginForm.js @@ -0,0 +1,100 @@ +import React, { useState } from 'react'; +import { Link } from 'react-router-dom'; +import { PrivateRoutes } from '../../models/routes'; +import './LoginForm.css'; + +const LoginForm = () => { + const [usuario, setUsuario] = useState(''); + const [contraseña, setContraseña] = useState(''); + const [rememberMe, setRememberMe] = useState(false); // Estado para el botón de mantener sesión + const [error, setError] = useState(null); // Estado para manejar errores + const [loading, setLoading] = useState(false); // Estado para manejar el estado de carga + + const handleSubmit = async (e) => { + e.preventDefault(); + setLoading(true); // Activar el estado de carga + setError(null); // Limpiar errores previos + + // Validar si los campos están vacíos + if (!usuario || !contraseña) { + setError('Es necesario rellenar el usuario y la contraseña.'); + setLoading(false); + return; + } + + try { + const response = await fetch(`http://localhost:3000/auth/login`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ usuario, contraseña }), + }); + + if (response.status === 401) { + setError('Usuario o contraseña inválido.'); + } else if (response.status === 500) { + setError('Error con la conexión de la API.'); + } else if (!response.ok) { + throw new Error('Error en el inicio de sesión'); + } else { + const data = await response.json(); + console.log('Response:', data); + window.location.href = PrivateRoutes.INTERFACE; + localStorage.setItem('Token', data.token); + } + } catch (error) { + console.error('Error:', error); + setError('Error en el inicio de sesión'); + } finally { + setLoading(false); // Desactivar el estado de carga + } + }; + + return ( +
+ Hola mundo +

Bienvenido al directorio de profesores

+

Iniciar sesión

+
+
+ + setUsuario(e.target.value)} + disabled={loading} // Desactivar input mientras carga + required + /> +
+
+ + setContraseña(e.target.value)} + disabled={loading} // Desactivar input mientras carga + required + /> +
+
+ setRememberMe(!rememberMe)} + disabled={loading} // Desactivar checkbox mientras carga + /> + +
+ + {loading &&

Cargando...

} + {error &&

{error}

} +
+
+ ); +}; + +export default LoginForm; diff --git a/src/components/MDUser.css b/src/components/MDUser/MDUser.css similarity index 100% rename from src/components/MDUser.css rename to src/components/MDUser/MDUser.css diff --git a/src/components/MDUser.js b/src/components/MDUser/MDUser.js similarity index 100% rename from src/components/MDUser.js rename to src/components/MDUser/MDUser.js diff --git a/src/components/ModificarProfesor/FormEditProfesor.js b/src/components/ModificarProfesor/FormEditProfesor.js index 8959134..21357b3 100644 --- a/src/components/ModificarProfesor/FormEditProfesor.js +++ b/src/components/ModificarProfesor/FormEditProfesor.js @@ -1,6 +1,7 @@ import React, { useState, useEffect, useCallback } from 'react'; import { useDropzone } from 'react-dropzone'; import { useParams } from 'react-router-dom'; +import { useDropzone } from 'react-dropzone'; import './FormEditProfesor.css'; const FormEditProfesor = () => { @@ -13,13 +14,15 @@ const FormEditProfesor = () => { const [edificio, setEdificio] = useState(''); const [adscripcion, setAdscripcion] = useState(''); const [categoria, setCategoria] = useState(''); - const [activo, setActivo] = useState(); + const [activo, setActivo] = useState(true); const [foto, setFoto] = useState(null); const [fotoBase64, setFotoBase64] = useState(''); const [lineasInvestigacion, setLineasInvestigacion] = useState([]); const [proyectosAcademicos, setProyectosAcademicos] = useState([]); - + const [photo, setPhoto] = useState(null); + const [preview, setPreview] = useState(null); + const handlePageChange = (newPage) => { setPage(newPage); }; @@ -60,7 +63,6 @@ const FormEditProfesor = () => { setProyectosAcademicos(data.proyectosAcademicos); }) .catch(error => console.error('Error fetching profesor:', error)); - console.log(profesor) }, [id_profesor]); const handleInputChange = (event) => { @@ -155,9 +157,13 @@ const FormEditProfesor = () => { reader.readAsDataURL(file); }, []); - const { getRootProps, getInputProps, isDragActive } = useDropzone({ - onDrop, - accept: 'image/jpeg, image/png' + const { getRootProps, getInputProps } = useDropzone({ + accept: '.jpg,.png', + onDrop: (acceptedFiles) => { + const file = acceptedFiles[0]; + setPhoto(file); + setPreview(URL.createObjectURL(file)); + } }); return ( @@ -400,4 +406,3 @@ const FormEditProfesor = () => { }; export default FormEditProfesor; - diff --git a/src/pages/Pagina404.css b/src/pages/Pagina404/Pagina404.css similarity index 100% rename from src/pages/Pagina404.css rename to src/pages/Pagina404/Pagina404.css diff --git a/src/pages/Pagina404.js b/src/pages/Pagina404/Pagina404.js similarity index 100% rename from src/pages/Pagina404.js rename to src/pages/Pagina404/Pagina404.js