TableDocentes_TableDocentes.jsx

import React, { useState, useEffect } from 'react';
import { useUser } from '../../Contexts/UserContext';
import PildoraMateriaGrado from '../PildoraMateriaGrado/PildoraMateriaGrado';
import InputContainer from '../Input/InputContainer';
import PildoraTitulo from '../PildoraTitulo/PildoraTitulo';
import { playSound } from 'react-sounds'; 
import Celda from '../Celda/Celda';
import Modal from '../Modal/Modal';
import Alerta from '../Alerta/Alerta';
import Line from '../Line/Line';
import './TableDocentes.scss';

/**
 * Componente TableDocentes que renderiza una tabla interactiva con la información de los estudiantes, actividades y notas de un curso asignado a un docente.
 * Muestra las actividades de los estudiantes, permite agregar nuevas actividades y editar las notas de los estudiantes.
 *
 * @component
 *
 * @param {Object} infoCurso - Información sobre el curso, incluyendo el ID de la materia, curso y nombre.
 * @param {string} infoDocente - El ID del docente para obtener sus actividades y notas.
 *
 * @returns {JSX.Element} Una tabla con las actividades, estudiantes y sus notas, con opciones para editar y agregar actividades.
 */

const TableDocentes = ({ infoCurso, infoDocente }) => {

	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 { user, bloqueoDemo } = useUser();

	const [info, setInfo] = useState([]);
	const [infoNota, setInfoNota] = useState([]);

	const [reload, setReload] = useState(false);

	const [cargando, setCargando] = useState(false);

	const [configurado, setConfigurado] = useState(true);

	useEffect(() => {
		const infoPeriodos = async () => {
			try {
				const response = await fetch(`${API_URL}periodosAcademicos/actual`, {
					method: 'GET',
					headers: {
						'Content-Type': 'application/json',
						Authorization: `Bearer ${token}`,
					},
				});

				if (!response.ok) {
					const errorData = await response.json();
					throw new Error(`${errorData.error || response.status}`);
				}

				const getPeriodos = await response.json();
				console.log(getPeriodos);
				const getPeriodosBloqueo = getPeriodos[0].bloqueado;

				console.log('Respuesta del servidor periodos:', getPeriodosBloqueo);
				setConfigurado(getPeriodosBloqueo);
			} catch (error) {
				console.error(error);
			}
		};

		infoPeriodos();
	}, [API_URL, token]);

	useEffect(() => {
		const notasCursoDocente = async () => {
			try {
				const response = await fetch(
					`${API_URL}calificacion/materia/${infoCurso.id_materia}/curso/${infoCurso.id_curso}/docente/${infoDocente}/institucion/${user.institucion.id_institucion}`,
					{
						method: 'GET',
						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}`);
				}

				const data = await response.json();
				console.log('AAAAAA', data);
				const listaData = Object.values(data);
				console.log('infoooo', listaData);

				if (listaData.length > 0) {
					setInfo(listaData);
				}
			} catch (error) {
				console.error(error);
				Alerta.error(`Error al obtener notas: ${error.message}`, true);
			}
		};

		notasCursoDocente();
	}, [
		reload,
		API_URL,
		token,
		user.institucion.id_institucion,
		infoCurso.id_curso,
		infoCurso.id_materia,
		infoDocente,
	]);

	useEffect(() => {
		const promedioCurso = async () => {
			try {
				const response = await fetch(
					`${API_URL}calificacion/promedio/materia/${infoCurso.id_materia}/curso/${infoCurso.id_curso}`,
					{
						method: 'GET',
						headers: {
							'Content-Type': 'application/json',
							Authorization: `Bearer ${token}`,
						},
					}
				);

				if (!response.ok) {
					const errorData = await response.json(); // Obtiene respuesta del servidor
					console.log(errorData);
					throw new Error(`${errorData.error || response.status}`);
				}

				const data = await response.json();
				console.log('fff', data);
				setInfoNota(data.promedio);
			} catch (error) {
				Alerta.error(`Error al obtener nota promedio: ${error.message}`, true);
			}
		};

		promedioCurso();
	}, [reload, API_URL, token, user.institucion.id_institucion, infoCurso.id_curso, infoCurso.id_materia]);

	//CREAR ACTIVIDAD BACK
	const [nombreAct, setNonombreAct] = useState({
		actividad: '',
		peso: '',
	});

	//captar info de los inputs
	const handleChange = (titulo, value) => {
		setNonombreAct({
			...nombreAct,
			[titulo]: value, // Convierte el título en key (puedes ajustarlo según tus necesidades)
		});
	};

	const handleSubmit = async (e, totalPesoPorcentaje) => {
		e.preventDefault();

		const peso = parseFloat(nombreAct.peso);

		if (isNaN(peso) || peso < 0 || peso > 100) {
			
			Alerta.error('El peso debe ser un número entre 0 y 100.');
			return;
		}

		if (totalPesoPorcentaje + peso > 100) {
			
			Alerta.error('Excederas el 100%');
			return;
		}

		if (!bloqueoDemo) {
			try {
				setCargando(true);
				const response = await fetch(`${API_URL}actividad/crear`, {
					method: 'POST',
					headers: {
						'Content-Type': 'application/json',
						Authorization: `Bearer ${token}`,
					},
					body: JSON.stringify({
						nombre: nombreAct.actividad,
						peso: nombreAct.peso,
						id_materia: infoCurso.id_materia,
						id_docente: infoDocente,
						id_curso: infoCurso.id_curso,
					}),
				});

				if (!response.ok) {
					const errorData = await response.json(); // Obtiene respuesta del servidor
					throw new Error(`${errorData.message || response.status}`);
				}

				
				Alerta.success('Actividad realizada correctamente');
				setCargando(false);
				setReload(!reload);
				console.log(nombreAct);
				setNonombreAct({
					actividad: '',
					peso: '',
				});
			} catch (error) {
				
				console.error('Error al crear actividad', error);
				Alerta.error(error.message);
				setCargando(false);
			}
		}
	};

	///MODALES

	const [modalIndexAbierto, setModalIndexAbierto] = useState({
		periodoIndex: null,
		actividadIndex: null,
	}); // Guardar el índice de la actividad que tiene el modal abierto

	const openModalAct = (periodoIndex, actividadIndex) => setModalIndexAbierto({ periodoIndex, actividadIndex }); // Establecer el índice de la actividad que se abre
	const closeModalAct = () => setModalIndexAbierto({ periodoIndex: null, actividadIndex: null }); // Cerrar el modal

	// Cambiar el estado modalIndexNota para que sea un objeto con los índices de actividad y estudiante
	const [modalIndexNota, setModalIndexNota] = useState({
		periodoIndex: null,
		actividadIndex: null,
		estudianteIndex: null,
	});

	const openModalNota = (periodoIndex, actividadIndex, estudianteIndex) => {
		setModalIndexNota({ periodoIndex, actividadIndex, estudianteIndex });
	};

	const closeModalNota = () => {
		setModalIndexNota({ periodoIndex: null, actividadIndex: null, estudianteIndex: null });
	};

	const handleReload = () => {
		setReload((prev) => !prev);
	};

	const [expandir, setExpandir] = useState({});
	const [primerClick, setPrimerClick] = useState(false);

	const handlePrimerClick = (index) => {
		if (!primerClick) {
			setPrimerClick(true); // Establecer que el primer clic ha ocurrido
			setExpandir((prevState) => ({
				...prevState,
				[index]: !prevState[index], // Si es true, se pone false, y viceversa
			}));
		} else {
			setExpandir((prevState) => ({
				...prevState,
				[index]: !prevState[index], // Si es true, se pone false, y viceversa
			}));
		}

		playSound('ui/radio_select');
	};

	return configurado ? (
		<div className='contenedorNotas'>
			{console.log('infooo', infoNota)}
			{/* PILDORA CON PROMEDIO TOTAL DEL AÑO Y PERIODOS */}
			<PildoraTitulo
				nota={infoNota ? infoNota.promedioGeneral : '-'}
				materia={infoCurso.materia}
				nombre={infoCurso.nombre_completo}
				color={infoCurso.color}
				grado={infoCurso.curso}
			></PildoraTitulo>
			<Line></Line>

			{/* las 4 tablas por periodos */}
			{info.length > 0 && info[0].estudiantes.length > 0 ? (
				info.map((periodo, idx) => {
					const listadoEst = periodo.estudiantes.map(
						(item) => ` ${item.apellido} ${item.nombre}`
					);
					const soloApellidos = periodo.estudiantes.map((item) => ` ${item.apellido}`);
					const soloNombre = periodo.estudiantes.map((item) => ` ${item.nombre}`);
					const actividadesUnicas = periodo.estudiantes
						.map((est) =>
							est.actividades.map((act) => [
								{
									actividad: act.actividad,
									peso: act.peso,
									idAct: act.id_actividad,
									idNota: act.id_calificacion,
								},
							])
						)[0]
						.flat()
						.sort((a, b) => a.actividad.localeCompare(b.actividad));

					const totalPorcentajes = periodo.estudiantes
						.map((est) => est.actividades.map((act) => [{ peso: act.peso }]))[0]
						.flat()
						.reduce((sum, actividad) => sum + actividad.peso, 0); // Suma los pesos

					const promedioBase =
						infoNota.promediosPorPeriodo.filter(
							(p) => p.periodo === periodo.nombre
						)[0] || null;
					//console.log('DDDDD', promedioBase);
					return (
						<div
							className='grupo'
							key={idx}
						>
							{/* titulo Periodo y si promedio con % */}
							<PildoraMateriaGrado
								texto={
									periodo.nombre.toUpperCase() +
									':\u00A0\u00A0\u00A0'+
									(promedioBase?.promedioPonderado ?? '0') +
									'%'
								}
								color={infoCurso.color}
								onClick={() => handlePrimerClick(idx)}
							></PildoraMateriaGrado>

							{/* tabla */}
							<div
								className={`contenedor ${
									primerClick
										? expandir[idx]
											? 'expandir'
											: 'noExpandir'
										: 'noMostrar'
								}`}
							>
								{/* titulo tabla con pormedio de ese periodo  */}
								<PildoraTitulo
									nota={
										promedioBase
											? promedioBase.promedioBase
											: '-'
									}
									materia={infoCurso.materia}
									nombre={infoCurso.nombre_completo}
									color={infoCurso.color}
									grado={infoCurso.curso}
								></PildoraTitulo>

								{/* tabla */}
								<div className='tabla'>
									{/* listado */}
									<div className='col colListado'>
										<Celda
											txt='Listado'
											color={infoCurso.color}
											tipo='titulo'
											rol='NoVer'
										></Celda>
										{listadoEst.map((nombre, index) => (
											<Celda
												key={index}
												tipo='titulo2'
												color={infoCurso.color}
												txt={nombre}
												rol='NoVer'
											></Celda>
										))}
									</div>

									{/* actividades y notas  */}
									<div className={`notas ${infoCurso.color}`}>
										{actividadesUnicas.map(
											(actividad, i) => (
												<div
													key={i}
													className='col nota'
												>
													<Celda
														color={
															infoCurso.color
														}
														txt={
															actividad.actividad +
															' - ' +
															actividad.peso +
															' % '
														}
														tipo='titulo'
														onClick={() =>
															openModalAct(
																idx,
																i
															)
														}
													/>
													{/* Modal específico para la actividad seleccionada */}
													{modalIndexAbierto.periodoIndex ===
														idx &&
														modalIndexAbierto.actividadIndex ===
															i && (
															<Modal
																isOpen={
																	true
																}
																closeModal={
																	closeModalAct
																}
																recargar={
																	handleReload
																}
																tipo='actividad'
																modalTitulo='EDITAR ACTIVIDAD'
																modalTexto='Edita los parametros de tu actividad'
																valorAct={
																	actividad.actividad
																}
																ValorPeso={
																	actividad.peso
																}
																extraData={{
																	materia: infoCurso.materia,
																	profesor: infoCurso.nombre_completo,
																	grado: infoCurso.curso,
																	id_act: actividad.idAct,
																	id_docente: infoDocente,
																	pesoTotalActual:
																		totalPorcentajes,
																}}
															/>
														)}
													{periodo.estudiantes.map(
														(
															estudiante,
															j
														) => {
															const actividadEncontrada =
																estudiante.actividades.find(
																	(
																		act
																	) =>
																		act.id_actividad ===
																		actividad.idAct
																);

															return (
																<div
																	className='full'
																	key={
																		j
																	}
																>
																	<Celda
																		tipo='normal'
																		color={
																			infoCurso.color
																		}
																		txt={
																			actividadEncontrada
																				? actividadEncontrada.nota
																				: 'N/A'
																		}
																		onClick={() =>
																			openModalNota(
																				idx,
																				i,
																				j
																			)
																		} // Ahora pasa ambos índices
																	/>

																	{/* Modal de nota específico para la combinación de actividad y estudiante */}
																	{modalIndexNota.periodoIndex ===
																		idx &&
																		modalIndexNota.actividadIndex ===
																			i &&
																		modalIndexNota.estudianteIndex ===
																			j && (
																			<Modal
																				isOpen={
																					true
																				}
																				closeModal={
																					closeModalNota
																				}
																				tipo='nota'
																				valorNota={
																					actividadEncontrada
																						? actividadEncontrada.nota
																						: 'N/A'
																				}
																				modalTitulo='EDITAR NOTA'
																				modalTexto='Edita la nota de esta actividad'
																				recargar={
																					handleReload
																				}
																				extraData={{
																					notaOriginal:
																						actividadEncontrada.nota,
																					id_nota: actividadEncontrada.id_calificacion,
																					materia: infoCurso.materia,
																					profesor: infoCurso.nombre_completo,
																					grado: infoCurso.curso,
																					nombreEst: soloNombre[
																						j
																					],
																					apellidosEst:
																						soloApellidos[
																							j
																						],
																					actividad: actividadesUnicas[
																						i
																					][0],
																					id_actividad:
																						actividad.idAct,
																					id_estudiante:
																						estudiante.documento_identidad,
																				}}
																			/>
																		)}
																</div>
															);
														}
													)}
												</div>
											)
										)}
									</div>
								</div>
								{periodo.estado && (
									<form
										onSubmit={(e) =>
											handleSubmit(
												e,
												totalPorcentajes
											)
										}
										className='contenedorAct'
									>
										<div className='titulo'>
											<p className='bold'>
												CREAR ACTIVIDAD:
											</p>
											<p>
												Total de porcentaje
												ocupado:{' '}
												{totalPorcentajes}%,
												disponible para asignar:{' '}
												{100 - totalPorcentajes}
												%
											</p>
											{totalPorcentajes === 100 && (
												<p className='alertaTxt'>
													Edita el peso de
													actividades para
													poder asignar
													más.
												</p>
											)}
										</div>
										<div className='crearAct'>
											<div className='campos'>
												<InputContainer
													titulo='Nombre'
													placeholder='Nombre de la actividad'
													inputType='text'
													value={
														nombreAct.actividad
													}
													onChange={(
														value
													) =>
														handleChange(
															'actividad',
															capitalizeWords(
																value
															)
														)
													} // Pasamos la función que actualizará el estado
													required={true} // Hacemos que el campo sea obligatorio
												/>
												<InputContainer
													titulo='Peso'
													placeholder='Valor entre 0 - 100'
													inputType='text'
													value={
														nombreAct.peso
													} // El valor del input viene del estado del componente padre
													onChange={(
														value
													) =>
														handleChange(
															'peso',
															value
														)
													} // Pasamos la función que actualizará el estado
													required={true} // Hacemos que el campo sea obligatorio
												/>
												<button
													type='submit'
													disabled={
														bloqueoDemo ||
														cargando ||
														totalPorcentajes ===
															100
													}
												>
													{cargando
														? 'cargando...'
														: totalPorcentajes ===
														  100
														? 'Sin Espacio'
														: 'Crear'}{' '}
												</button>
											</div>
										</div>
									</form>
								)}
							</div>
							<Line></Line>
						</div>
					);
				})
			) : info.length <= 0 ? (
				<p>Actualmente no hay periodos {info.length}</p>
			) : (
				<p>Todavia no hay estudiantes</p>
			)}
		</div>
	) : (
		<p className='lato'>Primero debes configurar PERIODOS.</p>
	);
};

export default TableDocentes;