diff --git a/api/alumnos-cursos.php b/api/alumnos-cursos.php index 32165b3..a055224 100644 --- a/api/alumnos-cursos.php +++ b/api/alumnos-cursos.php @@ -14,27 +14,27 @@ $profesorId = $_SESSION['profesor']['id'] ?? null; try { switch ($method) { case 'GET': - $alumnoId = $_GET['alumno_id'] ?? null; - + $alumnoId = $_GET['alumno_id'] ?? null; + if ($alumnoId) { - // Obtener cursos de un alumno específico - $query = "SELECT c.* FROM cursos c - JOIN alumnos_cursos ac ON c.id = ac.curso_id - WHERE ac.alumno_id = ? AND c.profesor_id = ?"; + // Obtener cursos de un alumno específico (con tipo) + $query = "SELECT c.id, c.nombre, c.tipo FROM cursos c + JOIN alumnos_cursos ac ON c.id = ac.curso_id + WHERE ac.alumno_id = ? AND c.profesor_id = ?"; $stmt = $pdo->prepare($query); $stmt->execute([$alumnoId, $profesorId]); } else { - // Obtener todos los alumnos - $query = "SELECT * FROM alumnos"; - $stmt = $pdo->prepare($query); - $stmt->execute(); - } - - echo json_encode([ - 'success' => true, - 'data' => $stmt->fetchAll(PDO::FETCH_ASSOC) - ]); - break; + // Obtener todos los alumnos + $query = "SELECT * FROM alumnos"; + $stmt = $pdo->prepare($query); + $stmt->execute(); + } + + echo json_encode([ + 'success' => true, + 'data' => $stmt->fetchAll(PDO::FETCH_ASSOC) + ]); + break; case 'POST': $data = json_decode(file_get_contents('php://input'), true); diff --git a/api/alumnos.php b/api/alumnos.php index 27adf55..f34a914 100644 --- a/api/alumnos.php +++ b/api/alumnos.php @@ -27,31 +27,51 @@ try { ]); break; - case 'POST': - $data = json_decode(file_get_contents('php://input'), true); + case 'POST': + $data = json_decode(file_get_contents('php://input'), true); - if (empty($data['nombre']) || empty($data['email'])) { - http_response_code(400); - echo json_encode(['success' => false, 'error' => 'Nombre y email son requeridos']); - exit; - } + if (empty($data['nombre']) || empty($data['email'])) { + http_response_code(400); + echo json_encode(['success' => false, 'error' => 'Nombre y email son requeridos']); + exit; + } - $stmt = $pdo->prepare(" - INSERT INTO alumnos (nombre, email, telefono) - VALUES (?, ?, ?) - "); - $stmt->execute([ - $data['nombre'], - $data['email'], - $data['telefono'] ?? null - ]); + $pdo->beginTransaction(); + try { + // Insertar alumno + $stmt = $pdo->prepare(" + INSERT INTO alumnos (nombre, email, telefono) + VALUES (?, ?, ?) + "); + $stmt->execute([ + $data['nombre'], + $data['email'], + $data['telefono'] ?? null + ]); - echo json_encode([ - 'success' => true, - 'id' => $pdo->lastInsertId(), - 'message' => 'Alumno creado exitosamente' - ]); - break; + $alumnoId = $pdo->lastInsertId(); + + // Si viene curso_id, asignar también a curso + if (!empty($data['curso_id'])) { + $stmt = $pdo->prepare(" + INSERT INTO alumnos_cursos (alumno_id, curso_id, estado) + VALUES (?, ?, 'cursando') + "); + $stmt->execute([$alumnoId, $data['curso_id']]); + } + + $pdo->commit(); + echo json_encode([ + 'success' => true, + 'id' => $alumnoId, + 'message' => 'Alumno creado y asignado exitosamente' + ]); + } catch (PDOException $e) { + $pdo->rollBack(); + http_response_code(500); + echo json_encode(['success' => false, 'error' => 'Error al registrar: ' . $e->getMessage()]); + } + break; case 'PUT': $data = json_decode(file_get_contents('php://input'), true); @@ -75,6 +95,30 @@ try { $data['telefono'] ?? null, $data['id'] ]); + + // Si curso_id viene en la actualización, actualizar también el curso + if (!empty($data['curso_id'])) { + // Verifica si ya tiene una relación previa + $check = $pdo->prepare("SELECT id FROM alumnos_cursos WHERE alumno_id = ?"); + $check->execute([$data['id']]); + + if ($check->fetch()) { + // Si ya tiene relación, actualizamos el curso asignado + $updateCurso = $pdo->prepare(" + UPDATE alumnos_cursos SET curso_id = ?, estado = 'cursando' + WHERE alumno_id = ? + "); + $updateCurso->execute([$data['curso_id'], $data['id']]); + } else { + // Si no tiene relación previa, la insertamos + $insertCurso = $pdo->prepare(" + INSERT INTO alumnos_cursos (alumno_id, curso_id, estado) + VALUES (?, ?, 'cursando') + "); + $insertCurso->execute([$data['id'], $data['curso_id']]); + } + } + echo json_encode([ 'success' => true, diff --git a/api/cursos.php b/api/cursos.php index ba0a6da..3ada92b 100644 --- a/api/cursos.php +++ b/api/cursos.php @@ -14,15 +14,22 @@ $profesorId = $_SESSION['profesor']['id']; switch ($method) { case 'GET': try { - $query = "SELECT * FROM cursos WHERE profesor_id = ?"; - $stmt = $pdo->prepare($query); - $stmt->execute([$profesorId]); - echo json_encode($stmt->fetchAll()); + $tipo = $_GET['tipo'] ?? null; + if ($tipo) { + $query = "SELECT * FROM cursos WHERE profesor_id = ? AND tipo = ?"; + $stmt = $pdo->prepare($query); + $stmt->execute([$profesorId, $tipo]); + } else { + $query = "SELECT * FROM cursos WHERE profesor_id = ?"; + $stmt = $pdo->prepare($query); + $stmt->execute([$profesorId]); + } + echo json_encode(['success' => true, 'data' => $stmt->fetchAll()]); } catch (PDOException $e) { http_response_code(500); echo json_encode(['error' => 'Error al cargar cursos']); } - break; + break; case 'POST': $data = json_decode(file_get_contents('php://input'), true); @@ -50,8 +57,9 @@ switch ($method) { echo json_encode(['success' => true, 'id' => $pdo->lastInsertId()]); } catch (PDOException $e) { http_response_code(500); - echo json_encode(['error' => 'Error al crear curso']); + echo json_encode(['error' => $e->getMessage()]); } + break; case 'PUT': diff --git a/api/importar_csv.php b/api/importar_csv.php new file mode 100644 index 0000000..0ce5be5 --- /dev/null +++ b/api/importar_csv.php @@ -0,0 +1,67 @@ + false, 'error' => 'No autenticado']); + exit; +} + +$data = json_decode(file_get_contents('php://input'), true); +$alumnos = $data['alumnos'] ?? []; + +if (empty($alumnos)) { + http_response_code(400); + echo json_encode(['success' => false, 'error' => 'No se enviaron alumnos']); + exit; +} + +// Paso 1: Validar todos los cursos +$errores = []; +$profesorId = $_SESSION['profesor']['id'] ?? null; + +foreach ($alumnos as $index => $alumno) { + $nombreCurso = trim($alumno['nombreCurso']); + $tipoCurso = trim($alumno['tipoCurso']); + + $stmt = $pdo->prepare("SELECT id FROM cursos WHERE nombre = ? AND tipo = ? AND profesor_id = ?"); + $stmt->execute([$nombreCurso, $tipoCurso, $profesorId]); + $curso = $stmt->fetch(); + + if (!$curso) { + $errores[] = "El curso \"{$nombreCurso}\" de tipo \"{$tipoCurso}\" en {$alumno['nombre']} ({$alumno['email']}) es inválido."; + } else { + $alumnos[$index]['curso_id'] = $curso['id']; // Guardamos para usar después + } +} + +if (!empty($errores)) { + echo json_encode([ + 'success' => false, + 'error' => "Error en cursos: " . count($errores) . " conflictos encontrados", + 'conflicts' => $errores + ]); + exit; +} + +// Paso 2: Insertar alumnos +try { + $pdo->beginTransaction(); + + foreach ($alumnos as $a) { + $stmt = $pdo->prepare("INSERT INTO alumnos (nombre, email, telefono) VALUES (?, ?, ?)"); + $stmt->execute([$a['nombre'], $a['email'], $a['telefono'] ?? null]); + $alumnoId = $pdo->lastInsertId(); + + $stmt = $pdo->prepare("INSERT INTO alumnos_cursos (alumno_id, curso_id, estado) VALUES (?, ?, 'cursando')"); + $stmt->execute([$alumnoId, $a['curso_id']]); + } + + $pdo->commit(); + echo json_encode(['success' => true, 'message' => 'Todos los alumnos fueron importados correctamente.']); +} catch (PDOException $e) { + $pdo->rollBack(); + http_response_code(500); + echo json_encode(['success' => false, 'error' => 'Error al guardar en la base de datos: ' . $e->getMessage()]); +} diff --git a/assets/js/main copy.js b/assets/js/main copy.js new file mode 100644 index 0000000..f6dd55c --- /dev/null +++ b/assets/js/main copy.js @@ -0,0 +1,1333 @@ +document.addEventListener("DOMContentLoaded", function () { + // Manejo del formulario de login + const loginForm = document.getElementById("loginForm"); + if (loginForm) { + loginForm.addEventListener("submit", handleLogin); + } + + // Configuración inicial del dashboard + if (document.body.classList.contains("admin")) { + initializeDashboard(); + } +}); + +// Función para manejar el login +function handleLogin(e) { + e.preventDefault(); + const formData = new FormData(this); + + fetch(this.action, { + method: "POST", + body: formData, + }) + .then((response) => response.json()) + .then((data) => { + if (data.success) { + window.location.href = data.redirect; + } else { + alert(data.message); + } + }) + .catch((error) => console.error("Error:", error)); +} + +// Inicialización del dashboard +function initializeDashboard() { + setupSidebarNavigation(); + loadInitialData(); + + const activeSection = document.querySelector(".sidebar-menu li.active"); + if (activeSection) { + const sectionId = activeSection.getAttribute("data-section"); + showSection(sectionId, true); + } +} + +// Configuración del menú lateral +function setupSidebarNavigation() { + document.querySelectorAll(".sidebar-menu li").forEach((item) => { + if (item.getAttribute("data-section")) { + item.addEventListener("click", function () { + const section = this.getAttribute("data-section"); + showSection(section); + }); + } + }); +} + +// Carga de datos iniciales +function loadInitialData() { + const profesorId = getProfesorId(); + + if (!profesorId) { + console.error("No se pudo obtener el ID del profesor"); + return; + } + + fetch(`api/cursos.php?profesor_id=${profesorId}`) + .then((response) => response.json()) + .then((courses) => { + // Cargar estudiantes y diplomas + Promise.all([ + fetch(`api/alumnos.php?profesor_id=${profesorId}`).then((res) => + res.json() + ), + fetch(`api/diplomas.php?profesor_id=${profesorId}`).then((res) => + res.json() + ), + ]).then(([students, diplomas]) => { + updateProfessorStats(courses, students, diplomas); + }); + }) + .catch((error) => console.error("Error:", error)); +} + +// Actualización de estadísticas +function updateProfessorStats(courses, students, diplomas) { + document.getElementById("active-courses-count").textContent = courses.length; + document.getElementById("students-count").textContent = students.length; + document.getElementById("diplomas-count").textContent = diplomas.length || 0; +} + +// Obtención del ID del profesor +function getProfesorId() { + try { + // 1. Verificar en el elemento del DOM (primera opción) + const profesorElement = document.getElementById("current-profesor"); + if (profesorElement && profesorElement.dataset.id) { + return profesorElement.dataset.id; + } + + // 2. Verificar en sessionStorage/localStorage + const storedUser = + sessionStorage.getItem("currentUser") || + localStorage.getItem("currentUser"); + if (storedUser) { + const user = JSON.parse(storedUser); + if (user && user.profesor_id) { + return user.profesor_id; + } + } + + console.log( + "No se encontró el ID del profesor en el DOM o en el almacenamiento" + ); + return null; + } catch (error) { + console.error("Error en getProfesorId:", error); + return null; + } +} + +function showModal(title, content, buttons = []) { + const modalHtml = ` + + `; + + const modalContainer = document.createElement("div"); + modalContainer.innerHTML = modalHtml; + document.body.appendChild(modalContainer); + document.body.style.overflow = "hidden"; +} + +function closeModal() { + const modal = document.getElementById("modal-overlay"); + if (modal) { + modal.remove(); + document.body.style.overflow = ""; + } +} + +function showToast(type, message) { + const toast = document.createElement("div"); + toast.className = `toast toast-${type}`; + toast.textContent = message; + document.body.appendChild(toast); + + setTimeout(() => { + toast.classList.add("fade-out"); + setTimeout(() => toast.remove(), 300); + }, 3000); +} + +// Manejo de secciones +function showSection(sectionId, isInitialLoad = false) { + updateActiveMenu(sectionId); + + const sectionElement = document.getElementById(`${sectionId}-content`); + if (!sectionElement) return; + + document.querySelectorAll(".content-section").forEach((s) => { + s.classList.remove("active"); + }); + sectionElement.classList.add("active"); + + // Cargar siempre los datos del dashboard al acceder + if (sectionId === "dashboard") { + loadInitialData(); + } else { + loadDynamicContent(sectionId, sectionElement); + } +} + +function updateActiveMenu(sectionId) { + document.querySelectorAll(".sidebar-menu li").forEach((li) => { + li.classList.remove("active"); + }); + + const activeItem = document.querySelector( + `.sidebar-menu li[data-section="${sectionId}"]` + ); + if (activeItem) activeItem.classList.add("active"); +} + +// Carga de contenido dinámico +function loadDynamicContent(sectionId, container) { + container.innerHTML = '
Cargando...
'; + + switch (sectionId) { + case "dashboard": + loadDashboardContent(container); + break; + case "courses": + loadProfessorCourses(container); + break; + case "students": + loadStudentsManagement(container); + break; + case "diplomas": + loadDiplomasSection(container); + break; + default: + container.innerHTML = + '

Sección no implementada

'; + } +} + +// Carga del dashboard +async function loadDashboardContent(container, forceReload = false) { + try { + // Mostrar loader + container.innerHTML = '
Cargando datos...
'; + + // Obtener siempre los datos frescos del servidor + const profesorId = getProfesorId(); + if (!profesorId) { + throw new Error("Debes iniciar sesión nuevamente"); + } + + // Usar caché solo si no es un forceReload + const cacheKey = `dashboardData-${profesorId}`; + if (!forceReload && sessionStorage.getItem(cacheKey)) { + const cachedData = JSON.parse(sessionStorage.getItem(cacheKey)); + renderDashboard(container, cachedData); + return; + } + + // Obtener datos frescos + const [coursesRes, studentsRes, diplomasRes] = await Promise.all([ + fetch(`api/cursos.php?profesor_id=${profesorId}&t=${Date.now()}`), + fetch(`api/alumnos.php?t=${Date.now()}`), + fetch(`api/diplomas.php?profesor_id=${profesorId}&t=${Date.now()}`), + ]); + + const [coursesData, studentsData, diplomasData] = await Promise.all([ + coursesRes.json(), + studentsRes.json(), + diplomasRes.json(), + ]); + + if ( + !coursesData.success || + !studentsData.success || + !diplomasData.success + ) { + throw new Error("Error en los datos recibidos"); + } + + const dashboardData = { + cursos: coursesData.data, + alumnos: studentsData.data, + diplomas: diplomasData.data, + lastUpdated: new Date().toLocaleTimeString(), + }; + + // Guardar en caché y renderizar + sessionStorage.setItem(cacheKey, JSON.stringify(dashboardData)); + renderDashboard(container, dashboardData); + } catch (error) { + console.error("Error:", error); + container.innerHTML = ` +
+

Error al cargar datos

+

${error.message}

+ +
`; + } +} +function renderDashboard(container, data) { + const activeCourses = data.cursos.filter((c) => c.estado === "activo"); + const totalStudents = data.alumnos.length; + const totalDiplomas = data.diplomas.length; + + container.innerHTML = ` +
+
+

Resumen General

+ Actualizado: ${ + data.lastUpdated + } + +
+
+

Resumen:

+

${ + activeCourses.length + } cursos activos

+

${totalStudents} alumnos registrados

+

${totalDiplomas} diplomas emitidos

+
+
+
+

Mis Cursos Activos

+ ${renderCoursesPreview(activeCourses)} +
`; +} + +// Gestión de cursos +function loadProfessorCourses(container) { + fetch(`api/cursos.php?profesor_id=${getProfesorId()}`) + .then((response) => response.json()) + .then((res) => { + if (!res.success) throw new Error("No se pudieron cargar los cursos"); + const courses = res.data; + + container.innerHTML = ` +
+

Mis Cursos

+
+ + + + + + + + + +
+ + +
+ + + + +
+ + +
+
+
+
+

Lista de Cursos

+
+ + + + + + + + + + + + ${courses + .map( + (course) => ` + + + + + + + + ` + ) + .join("")} + +
NombreDescripciónTipoEstadoAcciones
${course.nombre}${course.descripcion || "-"}${formatCourseType(course.tipo)} + ${course.estado} + +
+ + +
+
+
+
`; + + setupCourseForm(); + }) + .catch((err) => { + console.error("Error al cargar cursos:", err); + container.innerHTML = `
No se pudieron cargar los cursos
`; + }); +} + +function formatCourseType(type) { + const types = { + pildora: "Píldora", + inyeccion: "Inyección", + tratamiento: "Tratamiento" + }; + return types[type] || type; +} + +function setupCourseForm() { + const courseTypeSelect = document.getElementById('courseType'); + const competencesField = document.getElementById('competencesField'); + const competenciasInput = competencesField + ? competencesField.querySelector('input[name="competencias"]') + : null; + + if (courseTypeSelect && competenciasInput) { + courseTypeSelect.addEventListener('change', function () { + const isTratamiento = this.value === 'tratamiento'; + competencesField.classList.toggle('oculto', !isTratamiento); + competenciasInput.required = isTratamiento; + if (!isTratamiento) { + competenciasInput.value = ''; + } + }); + + const isTratamiento = courseTypeSelect.value === 'tratamiento'; + competencesField.classList.toggle('oculto', !isTratamiento); + competenciasInput.required = isTratamiento; + } + + const form = document.getElementById("courseForm"); + if (!form) return; + + const cancelBtn = document.getElementById("cancelCourseBtn"); + if (cancelBtn) { + cancelBtn.addEventListener("click", function () { + form.reset(); + competencesField.classList.add("oculto"); + form.dataset.editing = "false"; + delete form.dataset.courseId; + form.querySelector("button[type='submit']").textContent = "Guardar"; + cancelBtn.style.display = "none"; + }); + } + + form.addEventListener("submit", function (e) { + e.preventDefault(); + const formData = new FormData(this); + const jsonData = { + nombre: formData.get("nombre"), + descripcion: formData.get("descripcion"), + competencias: formData.get("competencias"), + tipo: formData.get("tipo"), + estado: formData.get("estado"), + profesor_id: getProfesorId(), + }; + + const isEdit = form.dataset.editing === "true"; + const courseId = form.dataset.courseId; + + if (isEdit) { + updateCourse(courseId, jsonData); + } else { + createCourse(jsonData); + } + }); +} + +window.createCourse = function (data) { + fetch("api/cursos.php", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(data), + }) + .then((response) => response.json()) + .then((data) => { + if (data.success) { + showSection("courses"); + } + }) + .catch((error) => console.error("Error:", error)); +}; + +window.updateCourse = function (id, data) { + data.id = id; + + fetch("api/cursos.php", { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(data), + }) + .then((response) => response.json()) + .then((data) => { + if (data.success) { + showSection("courses"); + } + }) + .catch((error) => console.error("Error:", error)); +}; + +window.editCourse = function (id) { + fetch(`api/cursos.php?profesor_id=${getProfesorId()}`) + .then((response) => response.json()) + .then((res) => { + const course = res.data.find((c) => c.id == id); + if (!course) return; + + const form = document.getElementById("courseForm"); + form.nombre.value = course.nombre; + form.descripcion.value = course.descripcion || ""; + form.tipo.value = course.tipo; + form.estado.value = course.estado || "activo"; + + const competencesField = document.getElementById("competencesField"); + const competenciasInput = competencesField.querySelector('input[name="competencias"]'); + if (course.tipo === "tratamiento") { + competencesField.classList.remove("oculto"); + competenciasInput.value = course.competencias || ""; + competenciasInput.required = true; + } else { + competencesField.classList.add("oculto"); + competenciasInput.value = ""; + competenciasInput.required = false; + } + + form.dataset.editing = "true"; + form.dataset.courseId = id; + form.querySelector("button[type='submit']").textContent = "Actualizar Curso"; + document.getElementById("cancelCourseBtn").style.display = "inline-block"; + form.scrollIntoView({ behavior: "smooth" }); + }); +}; + + +window.deleteCourse = function (id) { + if (!confirm("¿Estás seguro de eliminar este curso?")) return; + + fetch(`api/cursos.php?id=${id}`, { + method: "DELETE", + }) + .then((response) => response.json()) + .then((data) => { + if (data.success) { + showSection("courses"); + } + }) + .catch((error) => console.error("Error:", error)); +}; + +// Gestión de alumnos +function loadStudentsManagement(container) { + container.innerHTML = '
Cargando alumnos...
'; + + fetch("api/alumnos.php") + .then((response) => { + if (!response.ok) throw new Error("Error en la respuesta del servidor"); + return response.json(); + }) + .then((data) => { + if (!data.success) + throw new Error(data.error || "Error al obtener alumnos"); + + container.innerHTML = ` +
+ ${renderStudentForm()} + ${renderStudentsTable(data.data || [])} +
+ `; + + setupStudentForm(); + (data.data || []).forEach((alumno) => loadStudentCourses(alumno.id)); + }) + .catch((error) => { + console.error("Error:", error); + container.innerHTML = ` +
+

Error al cargar alumnos

+

${error.message}

+ +
`; + }); +} + + +function renderStudentForm() { + return ` +
+

Gestión de Alumnos

+
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+ +
+ + +
+
+ +
+ + +
+
+
`; +} + +function setupStudentForm() { + const form = document.getElementById("studentForm"); + if (!form) return; + + // Referencias a selects + const tipoCurso = document.getElementById("tipoCurso"); + const curso = document.getElementById("curso"); + + // Cargar cursos dinámicamente + tipoCurso.addEventListener("change", () => { + const tipo = tipoCurso.value; + curso.innerHTML = ''; + fetch(`api/cursos.php?tipo=${tipo}`) + .then((res) => res.json()) + .then((data) => { + if (data.success) { + curso.innerHTML = ''; + data.data.forEach((c) => { + const opt = document.createElement("option"); + opt.value = c.id; + opt.textContent = c.nombre; + curso.appendChild(opt); + }); + } else { + curso.innerHTML = ''; + } + }) + .catch(() => { + curso.innerHTML = ''; + }); + }); + + // Guardar alumno + form.addEventListener("submit", function (e) { + e.preventDefault(); + submitStudentForm(); // ✅ Usa función unificada que detecta si es edición o nuevo + }); + + const searchInput = document.getElementById("studentSearch"); + if (searchInput) { + searchInput.addEventListener("input", function () { + filterStudents(this.value.toLowerCase()); + }); + } +} + +function submitStudentForm() { + const form = document.getElementById("studentForm"); + const submitBtn = form.querySelector('button[type="submit"]'); + const submitText = document.getElementById("submitText"); + const spinner = document.getElementById("submitSpinner"); + + // Mostrar spinner + submitText.textContent = "Procesando..."; + spinner.style.display = "inline-block"; + submitBtn.disabled = true; + + const formData = new FormData(form); + const jsonData = { + nombre: formData.get("nombre"), + email: formData.get("email"), + telefono: formData.get("telefono"), + curso_id: document.getElementById("curso").value, // ✅ Cambio aquí + }; + + const isEdit = form.dataset.editing === "true"; + const studentId = form.dataset.studentId; + const url = "api/alumnos.php"; + const method = isEdit ? "PUT" : "POST"; + + if (isEdit) { + jsonData.id = studentId; + } + + fetch(url, { + method: method, + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(jsonData), + }) + .then((response) => response.json()) + .then((data) => { + if (!data.success) + throw new Error(data.error || "Error al guardar alumno"); + + showToast( + "success", + data.message || (isEdit ? "Alumno actualizado" : "Alumno creado") + ); + resetStudentForm(); + loadStudentsManagement(document.querySelector("#students-content")); + }) + .catch((error) => { + showToast("error", error.message || "Error en el servidor"); + }) + .finally(() => { + submitText.textContent = "Guardar"; + spinner.style.display = "none"; + submitBtn.disabled = false; + }); +} + +window.createStudent = function (data) { + fetch("api/alumnos.php", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(data), + }) + .then((response) => response.json()) + .then((data) => { + if (data.success) { + showSection("students"); + } + }) + .catch((error) => console.error("Error:", error)); +}; + +window.updateStudent = function (id, data) { + data.id = id; + + fetch("api/alumnos.php", { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(data), + }) + .then((response) => response.json()) + .then((data) => { + if (data.success) { + showSection("students"); + } + }) + .catch((error) => console.error("Error:", error)); +}; + +window.editStudent = function (id) { + fetch(`api/alumnos.php`) + .then((response) => response.json()) + .then((data) => { + if (!data.success) + throw new Error(data.error || "Error al obtener alumnos"); + + const alumno = data.data.find((a) => a.id == id); + if (!alumno) throw new Error("Alumno no encontrado"); + + const form = document.getElementById("studentForm"); + form.nombre.value = alumno.nombre; + form.email.value = alumno.email; + form.telefono.value = alumno.telefono || ""; + + form.dataset.editing = "true"; + form.dataset.studentId = id; + + document.getElementById("submitText").textContent = "Actualizar"; + document.getElementById("cancelBtn").style.display = "inline-block"; + + // 👇 Precargar tipo y curso si el alumno tiene asignación + fetch(`api/alumnos-cursos.php?alumno_id=${id}`) + .then((res) => res.json()) + .then((asignaciones) => { + if (asignaciones.success && asignaciones.data.length > 0) { + const curso = asignaciones.data[0]; + const tipoCursoSelect = document.getElementById("tipoCurso"); + const cursoSelect = document.getElementById("curso"); + + tipoCursoSelect.value = curso.tipo; + tipoCursoSelect.dispatchEvent(new Event("change")); + + setTimeout(() => { + cursoSelect.value = curso.id; + }, 300); + } + }); + + form.scrollIntoView({ behavior: "smooth" }); + }) + .catch((error) => { + showToast("error", error.message || "Error al cargar alumno"); + }); +}; + +window.deleteStudent = function (id) { + if (!id) { + showToast("error", "ID de alumno no proporcionado"); + return; + } + + fetch(`api/alumnos.php?id=${id}`, { + method: "DELETE", + }) + .then((response) => response.json()) + .then((data) => { + if (!data.success) + throw new Error(data.error || "Error al eliminar alumno"); + + showToast("success", data.message || "Alumno eliminado"); + closeModal(); + loadStudentsManagement(document.querySelector("#students-content")); + }) + .catch((error) => { + showToast("error", error.message || "Error al eliminar alumno"); + }); +}; + + +window.confirmDeleteStudent = function (id) { + showModal( + "Confirmar eliminación", + "¿Estás seguro de eliminar este alumno? Esta acción no se puede deshacer.", + [ + { + text: "Cancelar", + class: "btn-outline", + handler: "closeModal", + }, + { + text: "Eliminar", + class: "btn-danger", + handler: "deleteStudent(" + id + ")" + }, + ] + ); +}; + +window.resetStudentForm = function () { + const form = document.getElementById("studentForm"); + form.reset(); + form.dataset.editing = "false"; + delete form.dataset.studentId; + + document.getElementById("submitText").textContent = "Guardar"; + document.getElementById("cancelBtn").style.display = "none"; +}; +function filterStudents(searchTerm) { + const rows = document.querySelectorAll(".students-table tbody tr"); + + rows.forEach((row) => { + const nombre = row.cells[0].textContent.toLowerCase(); + const email = row.cells[1].textContent.toLowerCase(); + const telefono = row.cells[2].textContent.toLowerCase(); + + if ( + nombre.includes(searchTerm) || + email.includes(searchTerm) || + telefono.includes(searchTerm) + ) { + row.style.display = ""; + } else { + row.style.display = "none"; + } + }); +} + +//alumnos-cursos + +function renderStudentsTable(alumnos) { + if (alumnos.length === 0) { + return ` +
+
+ + + + + + +

No hay alumnos registrados

+

Comienza agregando tu primer alumno

+
+
`; + } + + return ` +
+
+

Lista de Alumnos

+
+ + +
+
+
+ + + + + + + + + + + + ${alumnos + .map( + (alumno) => ` + + + + + + + + ` + ) + .join("")} + +
NombreEmailTeléfonoCursosAcciones
${alumno.nombre}${alumno.email}${alumno.telefono || "-"} +
+ ${renderCourseBadges(alumno.id)} +
+
+
+ + +
+
+
+
`; +} + +function renderCourseBadges(alumnoId) { + return '
'; // Se cargará dinámicamente +} + +async function loadStudentCourses(alumnoId) { + try { + const response = await fetch( + `api/alumnos-cursos.php?alumno_id=${alumnoId}` + ); + const data = await response.json(); + + if (data.success) { + const container = document.getElementById(`courses-${alumnoId}`); + if (container) { + container.innerHTML = + data.data + .map( + (curso) => ` + + ${curso.nombre} + + + ` + ) + .join("") || 'Sin cursos'; + } + } + } catch (error) { + console.error("Error loading student courses:", error); + } +} + +window.showAssignStudentModal = async function () { + try { + console.log("Mostrando modal de vinculación"); + + const profesorId = getProfesorId(); + if (!profesorId) { + console.error("No se pudo obtener el ID del profesor"); + showToast("error", "No se pudo identificar al profesor"); + return; + } + + // Mostrar loader mientras se cargan los datos + const tempModalContent = `
Cargando datos...
`; + showModal("Vincular Alumnos a Curso", tempModalContent); + + // Cargar cursos y alumnos en paralelo + const [cursosRes, alumnosRes] = await Promise.all([ + fetch(`api/cursos.php?profesor_id=${profesorId}`), + fetch("api/alumnos.php"), + ]); + + const [cursosData, alumnosData] = await Promise.all([ + cursosRes.json(), + alumnosRes.json(), + ]); + + if (!cursosData || !alumnosData || !alumnosData.success) { + closeModal(); + throw new Error("Error al cargar datos necesarios"); + } + + // Crear contenido del modal + const modalHtml = ` +
+ + +
+ +
+ +
+ ${ + alumnosData.data.length > 0 + ? alumnosData.data + .map( + (alumno) => ` + + ` + ) + .join("") + : "

No hay alumnos disponibles

" + } +
+
+ `; + + // Actualizar el contenido del modal + const modalBody = document.querySelector(".modal-body"); + if (modalBody) { + modalBody.innerHTML = modalHtml; + } + + // Crear el footer si no existe + let modalFooter = document.querySelector(".modal-footer"); + if (!modalFooter) { + modalFooter = document.createElement("div"); + modalFooter.className = "modal-footer"; + document.querySelector(".modal").appendChild(modalFooter); + } + + // Actualizar el contenido del footer + modalFooter.innerHTML = ` + + + `; + + // Función para vincular alumnos seleccionados + window.assignStudentsToCourse = async function () { + const cursoId = document.getElementById("selectCurso").value; + const selectedAlumnos = Array.from( + document.querySelectorAll('input[name="alumnos"]:checked') + ).map((input) => input.value); + + if (selectedAlumnos.length === 0) { + showToast("warning", "Selecciona al menos un alumno"); + return; + } + + try { + const response = await fetch("api/alumnos-cursos.php", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + curso_id: cursoId, + alumnos: selectedAlumnos, + }), + }); + + const result = await response.json(); + if (result.success) { + showToast("success", "Alumnos vinculados exitosamente"); + closeModal(); + loadStudentsManagement(document.querySelector("#students-content")); + } else { + showToast("error", result.error || "Error al vincular"); + } + } catch (error) { + console.error("Error al vincular:", error); + showToast("error", "Error al realizar la vinculación"); + } + }; + } catch (error) { + console.error("Error en showAssignStudentModal:", error); + closeModal(); + showToast("error", "Error al cargar datos para vinculación"); + } +}; + +window.unassignStudent = async function (alumnoId, cursoId) { + if (confirm("¿Desvincular este alumno del curso?")) { + try { + const response = await fetch( + `api/alumnos-cursos.php?alumno_id=${alumnoId}&curso_id=${cursoId}`, + { + method: "DELETE", + } + ); + + const data = await response.json(); + + if (data.success) { + showToast("success", data.message); + loadStudentCourses(alumnoId); + } else { + showToast("error", data.error || "Error al desvincular"); + } + } catch (error) { + showToast("error", "Error en la conexión"); + } + } +}; + +// Gestión de diplomas +function loadDiplomasSection(container) { + container.innerHTML = '
Cargando diplomas...
'; + + fetch(`api/diplomas.php?profesor_id=${getProfesorId()}`) + .then((response) => { + if (!response.ok) throw new Error("Error en la respuesta del servidor"); + return response.json(); + }) + .then((data) => { + if (!data.success) + throw new Error(data.error || "Error al obtener diplomas"); + + if (data.data.length === 0) { + container.innerHTML = ` +
+

Diplomas Emitidos

+

No hay diplomas registrados aún

+
`; + return; + } + + container.innerHTML = ` +
+

Diplomas Emitidos

+
+ + + + + + + + + + + + + + ${data.data + .map( + (diploma) => ` + + + + + + + + + + ` + ) + .join("")} + +
AlumnoEmailCursoTipoFechaCódigoAcciones
${diploma.alumno_nombre}${diploma.alumno_email}${diploma.curso_nombre}${diploma.curso_tipo}${diploma.fecha_formateada}${diploma.codigo_unico} + + +
+
+
`; + }) + .catch((error) => { + console.error("Error:", error); + container.innerHTML = ` +
+

Error al cargar diplomas

+

${error.message}

+ +
`; + }); +} + +// Funciones auxiliares +function generateCoursesPreview(courses) { + if (!courses.length) return "

No tienes cursos activos

"; + + return ` +
+ + + + + + + + + + ${courses + .map( + (course) => ` + + + + + + ` + ) + .join("")} + +
NombreTipoEstado
${course.nombre || "Sin nombre"}${ + course.tipo || "N/A" + }${course.estado || "N/A"}
+
`; +} + +function getCourseTypeClass(type) { + const types = { + inyeccion: "type-inyeccion", + pildora: "type-pildora", + tratamiento: "type-tratamiento", + }; + return types[type] || ""; +} + +// Funciones globales para diplomas +window.downloadDiploma = function (codigo) { + window.open(`certificado.php?codigo=${codigo}`, "_blank"); +}; + +window.resendDiploma = function (codigo) { + fetch(`api/diplomas.php?action=resend&codigo=${codigo}`) + .then((response) => response.json()) + .then((data) => { + if (data.success) { + alert("Diploma reenviado exitosamente"); + } else { + alert("Error: " + (data.error || "No se pudo reenviar el diploma")); + } + }) + .catch((error) => { + console.error("Error:", error); + alert("Error al reenviar el diploma"); + }); +}; diff --git a/assets/js/main.js b/assets/js/main.js index e1fd946..ddfb411 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -331,7 +331,10 @@ function renderDashboard(container, data) { function loadProfessorCourses(container) { fetch(`api/cursos.php?profesor_id=${getProfesorId()}`) .then((response) => response.json()) - .then((courses) => { + .then((res) => { + if (!res.success) throw new Error("No se pudieron cargar los cursos"); + const courses = res.data; + container.innerHTML = `

Mis Cursos

@@ -388,12 +391,8 @@ function loadProfessorCourses(container) { (course) => ` ${course.nombre} - ${ - course.descripcion || "-" - } - ${course.tipo} + ${course.descripcion || "-"} + ${formatCourseType(course.tipo)}
- - + +
@@ -425,14 +420,18 @@ function loadProfessorCourses(container) {
`; setupCourseForm(); + }) + .catch((err) => { + console.error("Error al cargar cursos:", err); + container.innerHTML = `
No se pudieron cargar los cursos
`; }); } function formatCourseType(type) { const types = { - 'pildora': 'Píldora', - 'inyeccion': 'Inyección', - 'tratamiento': 'Tratamiento' + pildora: "Píldora", + inyeccion: "Inyección", + tratamiento: "Tratamiento" }; return types[type] || type; } @@ -445,7 +444,7 @@ function setupCourseForm() { : null; if (courseTypeSelect && competenciasInput) { - courseTypeSelect.addEventListener('change', function() { + courseTypeSelect.addEventListener('change', function () { const isTratamiento = this.value === 'tratamiento'; competencesField.classList.toggle('oculto', !isTratamiento); competenciasInput.required = isTratamiento; @@ -458,7 +457,7 @@ function setupCourseForm() { competencesField.classList.toggle('oculto', !isTratamiento); competenciasInput.required = isTratamiento; } - + const form = document.getElementById("courseForm"); if (!form) return; @@ -482,7 +481,7 @@ function setupCourseForm() { descripcion: formData.get("descripcion"), competencias: formData.get("competencias"), tipo: formData.get("tipo"), - estado: formData.get("estado"), + estado: formData.get("estado"), profesor_id: getProfesorId(), }; @@ -532,8 +531,8 @@ window.updateCourse = function (id, data) { window.editCourse = function (id) { fetch(`api/cursos.php?profesor_id=${getProfesorId()}`) .then((response) => response.json()) - .then((courses) => { - const course = courses.find((c) => c.id == id); + .then((res) => { + const course = res.data.find((c) => c.id == id); if (!course) return; const form = document.getElementById("courseForm"); @@ -562,6 +561,7 @@ window.editCourse = function (id) { }); }; + window.deleteCourse = function (id) { if (!confirm("¿Estás seguro de eliminar este curso?")) return; @@ -613,48 +613,104 @@ function loadStudentsManagement(container) { }); } + function renderStudentForm() { return ` -
-

Gestión de Alumnos

-
-
-
- - -
-
- - -
-
- - -
-
-
- - -
-
-
`; +
+
+

Gestión de Alumnos

+ +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+ +
+ + +
+
+ +
+ + +
+
+
`; } + function setupStudentForm() { const form = document.getElementById("studentForm"); if (!form) return; - form.addEventListener("submit", function (e) { - e.preventDefault(); - submitStudentForm(); + // Referencias a selects + const tipoCurso = document.getElementById("tipoCurso"); + const curso = document.getElementById("curso"); + + // Cargar cursos dinámicamente + tipoCurso.addEventListener("change", () => { + const tipo = tipoCurso.value; + curso.innerHTML = ''; + fetch(`api/cursos.php?tipo=${tipo}`) + .then((res) => res.json()) + .then((data) => { + if (data.success) { + curso.innerHTML = ''; + data.data.forEach((c) => { + const opt = document.createElement("option"); + opt.value = c.id; + opt.textContent = c.nombre; + curso.appendChild(opt); + }); + } else { + curso.innerHTML = ''; + } + }) + .catch(() => { + curso.innerHTML = ''; + }); }); - // Configurar búsqueda + // Guardar alumno + form.addEventListener("submit", function (e) { + e.preventDefault(); + submitStudentForm(); // ✅ Usa función unificada que detecta si es edición o nuevo + }); + const searchInput = document.getElementById("studentSearch"); if (searchInput) { searchInput.addEventListener("input", function () { @@ -662,6 +718,7 @@ function setupStudentForm() { }); } } + function submitStudentForm() { const form = document.getElementById("studentForm"); const submitBtn = form.querySelector('button[type="submit"]'); @@ -678,12 +735,12 @@ function submitStudentForm() { nombre: formData.get("nombre"), email: formData.get("email"), telefono: formData.get("telefono"), + curso_id: document.getElementById("curso").value, // ✅ Cambio aquí }; const isEdit = form.dataset.editing === "true"; const studentId = form.dataset.studentId; - - const url = "api/alumnos.php" + (isEdit ? "" : ""); + const url = "api/alumnos.php"; const method = isEdit ? "PUT" : "POST"; if (isEdit) { @@ -772,6 +829,24 @@ window.editStudent = function (id) { document.getElementById("submitText").textContent = "Actualizar"; document.getElementById("cancelBtn").style.display = "inline-block"; + // 👇 Precargar tipo y curso si el alumno tiene asignación + fetch(`api/alumnos-cursos.php?alumno_id=${id}`) + .then((res) => res.json()) + .then((asignaciones) => { + if (asignaciones.success && asignaciones.data.length > 0) { + const curso = asignaciones.data[0]; + const tipoCursoSelect = document.getElementById("tipoCurso"); + const cursoSelect = document.getElementById("curso"); + + tipoCursoSelect.value = curso.tipo; + tipoCursoSelect.dispatchEvent(new Event("change")); + + setTimeout(() => { + cursoSelect.value = curso.id; + }, 300); + } + }); + form.scrollIntoView({ behavior: "smooth" }); }) .catch((error) => { @@ -780,6 +855,11 @@ window.editStudent = function (id) { }; window.deleteStudent = function (id) { + if (!id) { + showToast("error", "ID de alumno no proporcionado"); + return; + } + fetch(`api/alumnos.php?id=${id}`, { method: "DELETE", }) @@ -796,6 +876,8 @@ window.deleteStudent = function (id) { showToast("error", error.message || "Error al eliminar alumno"); }); }; + + window.confirmDeleteStudent = function (id) { showModal( "Confirmar eliminación", @@ -809,11 +891,12 @@ window.confirmDeleteStudent = function (id) { { text: "Eliminar", class: "btn-danger", - handler: () => deleteStudent(id), + handler: "deleteStudent(" + id + ")" }, ] ); }; + window.resetStudentForm = function () { const form = document.getElementById("studentForm"); form.reset(); @@ -870,13 +953,13 @@ function renderStudentsTable(alumnos) { - + +
@@ -1260,4 +1343,51 @@ window.resendDiploma = function (codigo) { console.error("Error:", error); alert("Error al reenviar el diploma"); }); + + window.handleCSVUpload = function (event) { + const file = event.target.files[0]; + if (!file) return; + + const reader = new FileReader(); + reader.onload = function (e) { + const lines = e.target.result.split("\n").map(line => line.trim()).filter(Boolean); + const alumnos = []; + + for (let i = 1; i < lines.length; i++) { + const [nombre, email, telefono, tipoCurso, nombreCurso] = lines[i].split(",").map(s => s.trim()); + + // Validación básica de columnas mínimas + if (!nombre || !email || !tipoCurso || !nombreCurso) continue; + + alumnos.push({ nombre, email, telefono, tipoCurso, nombreCurso }); + } + + fetch("api/importar_csv.php", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ alumnos }), + }) + .then(res => res.json()) + .then(data => { + if (data.success) { + showToast("success", data.message || "Alumnos importados correctamente"); + loadStudentsManagement(document.querySelector("#students-content")); + } else { + // Si vienen errores detallados, los mostramos + if (data.conflicts && data.conflicts.length > 0) { + const list = ``; + showModal("Errores en Importación CSV", `

No se importaron alumnos por los siguientes errores:

${list}`); + } else { + showToast("error", data.error || "Error al importar alumnos"); + } + } + }) + .catch(() => { + showToast("error", "Error al procesar el archivo"); + }); + }; + + reader.readAsText(file); + }; + }; diff --git a/includes/config.php b/includes/config.php index acd4194..ef6467a 100644 --- a/includes/config.php +++ b/includes/config.php @@ -4,7 +4,7 @@ session_start(); $host = 'localhost'; $db = 'diplomaster'; $user = 'root'; -$pass = ''; +$pass = 'root'; $charset = 'utf8mb4'; $dsn = "mysql:host=$host;dbname=$db;charset=$charset";