import React, { useState } from 'react';
import { useTheme } from '../../Contexts/UserContext';
import { useUser } from '../../Contexts/UserContext';
import InputContainer from '../Input/InputContainer';
import Alerta from '../Alerta/Alerta';
import './Modal.scss';
/**
* Componente Modal que muestra un modal interactivo para eliminar o editar datos, como observaciones, actividades o notas.
* El modal cambia de diseño dependiendo del tipo de acción (eliminar, editar).
*
* @component
*
* @param {boolean} isOpen - Indica si el modal está abierto o cerrado.
* @param {function} recargar - Función para recargar los datos después de realizar una acción.
* @param {function} closeModal - Función para cerrar el modal.
* @param {string} tipo - Tipo de acción a realizar (puede ser 'eliminar', 'actividad', 'observacion').
* @param {string} [modalTitulo='Eliminar'] - Título del modal, por defecto 'Eliminar'.
* @param {string} [modalTexto='Estas seguro de eliminar...'] - Texto del modal que describe la acción que se va a realizar.
* @param {string} [valorAct=''] - Valor de la actividad, usado para editar o eliminar actividades.
* @param {string} [ValorPeso=''] - Valor del peso de la actividad, usado para editar actividades.
* @param {string} [valorNota=''] - Valor de la nota, usado para registrar o editar la nota de un estudiante.
* @param {string} [valorObs=''] - Valor de la observación, usado para editar o eliminar observaciones.
* @param {Object} [extraData={}] - Datos adicionales para el procesamiento del modal (como ID de la observación o actividad).
* @param {ReactNode} children - Elementos hijos que se pasan al modal para su personalización.
*
* @returns {JSX.Element} Un modal con diferentes funcionalidades dependiendo del tipo de acción.
*/
const Modal = ({
isOpen,
recargar,
closeModal,
tipo,
modalTitulo = 'Eliminar',
modalTexto = 'Estas seguro de eliminar...',
valorAct = '',
ValorPeso = '',
valorNota = '',
valorObs = '',
extraData = {},
children,
}) => {
function capitalizeWords(str) {
return str
.split(' ') // Divide en palabras
.map((word) =>
word.length > 0 ? word.charAt(0).toUpperCase() + word.slice(1).toLowerCase() : ''
)
.join(' ');
}
const API_URL = process.env.REACT_APP_API_URL;
const token = localStorage.getItem('token');
const { theme } = useTheme();
const { bloqueoDemo } = useUser();
//La logica del modal eliminar se le hace es al boton que llega por children.
//Envio datos modal actividad.
const [step, setStep] = useState('form');
const [nombreAct, setNonombreAct] = useState(valorAct); // Estado para manejar el valor de la actividad
const [pesoAct, setPesoAct] = useState(ValorPeso); // Estado para manejar el valor del peso
const [observacionEditada, setObservacionEditada] = useState(valorObs || '');
const [cargando, setCargando] = useState(false); // Estado para manejar si la observación está siendo editada
const handleEliminarObservacion = async () => {
if (!bloqueoDemo) {
try {
const response = await fetch(`${API_URL}comentarios/${extraData.id_observacion}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message || 'Error al eliminar observación');
}
Alerta.success('Observación eliminada');
closeModal();
recargar();
} catch (error) {
console.error('Error al eliminar observación:', error);
Alerta.error(error.message);
}
}
};
const handleNombreChange = (newNombre) => {
setNonombreAct(capitalizeWords(newNombre)); // Actualiza el estado 'email'
};
const handlePesoChange = (newPeso) => {
setPesoAct(newPeso); // Actualiza el estado 'email'
};
const handleSubmit1 = async (e) => {
e.preventDefault();
// Crear el objeto JSON con los valores de los inputs
const formData = {
...extraData,
nombreAct: nombreAct,
pesoAct: pesoAct,
};
console.log('Datos del formulario ACTIVIDAD:', JSON.stringify(formData));
if (parseInt(formData.pesoTotalActual - parseInt(ValorPeso)) + parseInt(formData.pesoAct) > 100) {
Alerta.error('Excederas el 100%');
return;
}
if (!bloqueoDemo) {
try {
const response = await fetch(`${API_URL}actividad/actualizar/${formData.id_act}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
nombre: formData.nombreAct,
peso: formData.pesoAct,
id_docente: formData.id_docente,
}),
});
if (!response.ok) {
const errorData = await response.json(); // Obtiene respuesta del servidor
throw new Error(`${errorData.message || response.status}`);
}
Alerta.success('Actividad actualizada');
closeModal();
recargar();
} catch (error) {
console.error('Error al crear actividad', error);
Alerta.error(error.message);
}
}
// Mostrar el objeto JSON en la consola (o enviarlo al servidor)
// Aquí puedes agregar lógica para enviar el JSON a un servidor o hacer algo más con él
};
const abrirConfirmacion = () => setStep('confirm');
const volverAlForm = () => setStep('form');
//Envio datos modal notas
const [nota, setNota] = useState(valorNota); // Estado para manejar el valor del email
// Función para manejar el cambio en el campo del email
const handleNotaChange = (newNota) => {
setNota(newNota); // Actualiza el estado 'email' con el nuevo valor
};
const handleSubmit2 = async (e) => {
e.preventDefault();
// Crear el objeto JSON con los valores de los inputs
// Validación: solo números entre 0 y 5, incluyendo decimales
const notaNumerica = parseFloat(nota);
if (isNaN(notaNumerica) || notaNumerica < 0 || notaNumerica > 5) {
Alerta.error('La nota debe ser un número entre 0 y 5');
return;
}
const formData = {
...extraData,
nota: nota,
};
if (!bloqueoDemo) {
if (formData.notaOriginal === '0') {
try {
setCargando(true);
const response = await fetch(`${API_URL}calificacion/asignar`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
id_actividad: formData.id_actividad,
id_estudiante: formData.id_estudiante,
nota: formData.nota,
}),
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message || 'Error al registrar nota');
}
Alerta.success('Nota registrada correctamente');
setCargando(false);
} catch (error) {
console.error('Error al guardar nota:', error);
Alerta.error(error.message);
setCargando(false);
}
} else {
try {
const response = await fetch(
`${API_URL}calificacion/actualizar/${formData.id_nota}`,
{
method: 'PUT',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
id_actividad: formData.id_actividad,
id_estudiante: formData.id_estudiante,
nota: formData.nota,
}),
}
);
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message || 'Error al editar nota');
}
Alerta.success('Nota registrada correctamente');
} catch (error) {
console.error('Error al guardar nota:', error);
Alerta.error(error.message);
}
}
}
// Mostrar el objeto JSON en la consola (o enviarlo al servidor)
console.log('Datos del formulario NOTAS:', JSON.stringify(formData));
closeModal();
recargar();
// Aquí puedes agregar lógica para enviar el JSON a un servidor o hacer algo más con él
};
const handleObservacionChange = (value) => {
setObservacionEditada(value); // Cambia el estado
};
const handleSubmit3 = async (e) => {
e.preventDefault();
if (!bloqueoDemo) {
setCargando(true);
try {
const response = await fetch(`${API_URL}comentarios/${extraData.id_observacion}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({ comentario: observacionEditada }),
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message || response.status);
}
Alerta.success('Observación actualizada correctamente');
closeModal();
setCargando(false);
recargar(); // Actualiza la lista de observaciones si quieres
} catch (error) {
setCargando(false);
console.error('Error al actualizar observación', error);
Alerta.error(error.message);
}
}
};
//MANEJO LOGICA MODAL
if (!isOpen) return null; // No renderiza el modal si isOpen es false
const handleClickOutside = (e) => {
// Cerrar modal si se hace clic fuera del área del modal
if (e.target.classList.contains('modal-overlay')) {
closeModal();
}
};
const handleEliminarAct = async () => {
const formData = {
...extraData,
nombreAct: nombreAct,
pesoAct: pesoAct,
};
console.log('Datos del formulario ELIMINAR:', JSON.stringify(formData));
if (!bloqueoDemo) {
try {
const response = await fetch(`${API_URL}actividad/eliminar/${formData.id_act}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
});
if (!response.ok) {
const errorData = await response.json(); // Obtiene respuesta del servidor
throw new Error(`${errorData.message || response.status}`);
}
Alerta.success('Actividad eliminada');
closeModal();
recargar();
} catch (error) {
console.error('Error al crear actividad', error);
Alerta.error(error.message);
}
}
};
return (
<div
className={`modal-overlay ${tipo} ${theme} ${step}`}
onClick={handleClickOutside}
>
<div className={`modal-content ${theme}`}>
{tipo === 'eliminar' ? (
<div className='modalContenedor'>
<div className='titulo'>
<p className='bold'>{modalTitulo.toUpperCase()} </p>
</div>
<p className='lato textoEli'>{modalTexto} </p>
{children}
</div>
) : tipo === 'actividad' ? (
<>
{step === 'form' ? (
<div className='modalAct'>
<div className='titulo'>
<p className='bold'>{modalTitulo}</p>
</div>
<form
onSubmit={handleSubmit1}
className='crearAct'
>
<div className='campos'>
<InputContainer
titulo='Nombre Actividad'
inputType='text'
value={nombreAct} // El valor del input viene del estado del componente padre
onChange={handleNombreChange} // Pasamos la función que actualizará el estado
required={true} // Hacemos que el campo sea obligatorio
/>
<InputContainer
titulo='Peso'
placeholder='Nuevo Peso'
inputType='number'
min='0'
max='5'
step='0.01'
value={pesoAct} // El valor del input viene del estado del componente padre
onChange={handlePesoChange} // Pasamos la función que actualizará el estado
required={true} // Hacemos que el campo sea obligatorio
/>
<button
type='submit'
disabled={bloqueoDemo}
>
Editar
</button>
<button
type='button'
className='rojo'
disabled={bloqueoDemo}
onClick={abrirConfirmacion}
>
Eliminar
</button>
</div>
</form>
</div>
) : (
<div className='modalContenedor'>
<div className='titulo'>
<p className='bold'> CONFIRMACIÓN </p>
</div>
<p className='lato textoEli'>
Esta acción no se podra revertir.
</p>
<button
disabled={bloqueoDemo}
type='button'
className='rojo'
onClick={() => handleEliminarAct()}
>
Si, Eliminar
</button>
<button
type='button'
onClick={volverAlForm}
>
Cancelar
</button>
</div>
)}
</>
) : tipo === 'observacion' ? (
step === 'form' ? (
<div className='modalObservacion'>
<div className='titulo'>
<p className='bold'>{modalTitulo}</p>
</div>
<form
onSubmit={handleSubmit3}
className='crearObservacion'
>
<div className='campos'>
<textarea
titulo='Observación'
placeholder='Escribe tu observación'
inputType='text'
value={observacionEditada} // Asegúrate de pasar el valor del estado aquí
onChange={(e) =>
handleObservacionChange(
e.target.value
)
} // La función que actualizará el estado del componente principal
required={true}
className='campo-observacion'
/>
<div className='botones-acciones'>
<button
type='submit'
disabled={
bloqueoDemo || cargando
}
>
{cargando
? 'Editando'
: 'Editar'}
</button>
<button
type='button'
className='rojo'
onClick={() =>
setStep('confirm')
}
>
Eliminar
</button>
</div>
</div>
</form>
</div>
) : (
<div className='modalContenedor'>
<div className='titulo'>
<p className='bold'>CONFIRMACIÓN</p>
</div>
<p className='lato textoEli'>
¿Deseas eliminar esta observación? Esta acción no se
puede revertir.
</p>
<button
disabled={bloqueoDemo}
type='button'
className='rojo'
onClick={handleEliminarObservacion}
>
Sí, Eliminar
</button>
<button
type='button'
onClick={() => setStep('form')}
>
Cancelar
</button>
</div>
)
) : (
<div className='modalAct'>
<div className='titulo'>
<p className='bold'>{modalTitulo}</p>
</div>
<div className='crearAct'>
<div className='campos'>
<InputContainer
titulo='Nota'
placeholder='Nueva nota'
inputType='text'
value={nota} // El valor del input viene del estado del componente padre
onChange={handleNotaChange} // Pasamos la función que actualizará el estado
required={true} // Hacemos que el campo sea obligatorio
/>
<button
onClick={handleSubmit2}
disabled={bloqueoDemo || cargando}
>
{cargando ? 'cargando...' : 'Ingresar'}
</button>
</div>
</div>
</div>
)}
</div>
</div>
);
};
export default Modal;