diff --git a/api/alumnos.php b/api/alumnos.php new file mode 100644 index 0000000..fe00c0d --- /dev/null +++ b/api/alumnos.php @@ -0,0 +1,64 @@ + 'No autenticado']); + exit; +} + +$method = $_SERVER['REQUEST_METHOD']; + +switch ($method) { + case 'GET': + try { + $stmt = $pdo->query(" + SELECT a.*, + GROUP_CONCAT(ac.curso_id) AS cursos + FROM alumnos a + LEFT JOIN alumnos_cursos ac ON a.id = ac.alumno_id + GROUP BY a.id + "); + + $alumnos = $stmt->fetchAll(); + + // Convertir cursos a array + foreach ($alumnos as &$alumno) { + $alumno['cursos'] = $alumno['cursos'] ? explode(',', $alumno['cursos']) : []; + } + + echo json_encode($alumnos); + + } catch (PDOException $e) { + http_response_code(500); + echo json_encode(['error' => 'Error al cargar alumnos']); + } + break; + + case 'POST': + $data = json_decode(file_get_contents('php://input'), true); + + try { + $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()]); + } catch (PDOException $e) { + http_response_code(500); + echo json_encode(['error' => 'Error al crear alumno: ' . $e->getMessage()]); + } + break; + + default: + http_response_code(405); + echo json_encode(['error' => 'Método no permitido']); +} +?> \ No newline at end of file diff --git a/api/cursos.php b/api/cursos.php index 9d7ce17..83de32e 100644 --- a/api/cursos.php +++ b/api/cursos.php @@ -9,44 +9,91 @@ if (!is_logged_in()) { } $method = $_SERVER['REQUEST_METHOD']; -$user = $_SESSION['user']; +$profesorId = $_SESSION['profesor']['id'] ?? null; switch ($method) { case 'GET': - if ($user['rol'] === 'admin') { - $stmt = $pdo->query("SELECT * FROM cursos"); - } else { - $stmt = $pdo->prepare(" - SELECT c.*, uc.estado, uc.fecha_inicio, uc.fecha_fin, uc.profesor - FROM usuario_cursos uc - JOIN cursos c ON uc.curso_id = c.id - WHERE uc.usuario_id = ? - "); - $stmt->execute([$user['id']]); + try { + $query = " + SELECT + c.*, + COUNT(ac.id) AS alumnos_count, + u.nombre AS profesor_nombre + FROM cursos c + LEFT JOIN alumnos_cursos ac ON c.id = ac.curso_id + LEFT JOIN usuarios u ON c.profesor_id = u.id + "; + + $params = []; + + if (isset($_GET['profesor_id'])) { + $query .= " WHERE c.profesor_id = ?"; + $params[] = $_GET['profesor_id']; + } + + $query .= " GROUP BY c.id ORDER BY c.estado, c.nombre"; + + $stmt = $pdo->prepare($query); + $stmt->execute($params); + + echo json_encode($stmt->fetchAll()); + + } catch (PDOException $e) { + http_response_code(500); + echo json_encode(['error' => 'Error al cargar cursos: ' . $e->getMessage()]); } - echo json_encode($stmt->fetchAll()); break; case 'POST': - if ($user['rol'] !== 'admin') { - http_response_code(403); - echo json_encode(['error' => 'Acceso no autorizado']); + $data = json_decode(file_get_contents('php://input'), true); + + try { + $stmt = $pdo->prepare(" + INSERT INTO cursos (nombre, descripcion, tipo, estado, profesor_id) + VALUES (?, ?, ?, 'activo', ?) + "); + $stmt->execute([ + $data['nombre'], + $data['descripcion'] ?? null, + $data['tipo'], + $profesorId + ]); + + echo json_encode(['success' => true, 'id' => $pdo->lastInsertId()]); + } catch (PDOException $e) { + http_response_code(500); + echo json_encode(['error' => 'Error al crear curso: ' . $e->getMessage()]); + } + break; + + case 'DELETE': + $id = $_GET['id'] ?? null; + if (!$id) { + http_response_code(400); + echo json_encode(['error' => 'ID de curso no proporcionado']); exit; } - $data = json_decode(file_get_contents('php://input'), true); - - $stmt = $pdo->prepare(" - INSERT INTO cursos (nombre, tipo, competencias) - VALUES (?, ?, ?) - "); - $stmt->execute([ - $data['nombre'], - $data['tipo'], - $data['competencias'] ?? null - ]); - - echo json_encode(['success' => true, 'id' => $pdo->lastInsertId()]); + try { + // Verificar que el curso pertenece al profesor + if ($profesorId) { + $stmt = $pdo->prepare("SELECT id FROM cursos WHERE id = ? AND profesor_id = ?"); + $stmt->execute([$id, $profesorId]); + if (!$stmt->fetch()) { + http_response_code(403); + echo json_encode(['error' => 'No autorizado']); + exit; + } + } + + $stmt = $pdo->prepare("DELETE FROM cursos WHERE id = ?"); + $stmt->execute([$id]); + + echo json_encode(['success' => true]); + } catch (PDOException $e) { + http_response_code(500); + echo json_encode(['error' => 'Error al eliminar curso: ' . $e->getMessage()]); + } break; default: diff --git a/api/diploma.php b/api/diploma.php new file mode 100644 index 0000000..5450f13 --- /dev/null +++ b/api/diploma.php @@ -0,0 +1,78 @@ + 'No autenticado']); + exit; +} + +try { + $profesorId = $_SESSION['profesor']['id'] ?? null; + $action = $_GET['action'] ?? null; + + if ($action === 'resend') { + // Lógica para reenviar diploma + $codigo = $_GET['codigo'] ?? null; + if (!$codigo) { + throw new Exception('Código de diploma no proporcionado'); + } + + // Aquí iría la lógica para reenviar el diploma por email + echo json_encode(['success' => true, 'message' => 'Diploma reenviado']); + exit; + } + + $query = " + SELECT + d.id, + d.codigo_unico, + d.fecha_emision, + a.nombre AS alumno_nombre, + a.email AS alumno_email, + c.nombre AS curso_nombre, + c.tipo AS curso_tipo, + c.id AS curso_id, + DATE_FORMAT(d.fecha_emision, '%d/%m/%Y') AS fecha_formateada + FROM diplomas d + JOIN alumnos_cursos ac ON d.alumno_curso_id = ac.id + JOIN alumnos a ON ac.alumno_id = a.id + JOIN cursos c ON ac.curso_id = c.id + "; + + $params = []; + + if ($profesorId) { + $query .= " WHERE c.profesor_id = ?"; + $params[] = $profesorId; + } + + $query .= " ORDER BY d.fecha_emision DESC"; + + $stmt = $pdo->prepare($query); + $stmt->execute($params); + + $diplomas = $stmt->fetchAll(); + + // Asegurar que todos los diplomas tengan código único + foreach ($diplomas as &$diploma) { + if (empty($diploma['codigo_unico'])) { + $diploma['codigo_unico'] = 'DIPL-' . str_pad($diploma['id'], 6, '0', STR_PAD_LEFT); + } + } + + echo json_encode([ + 'success' => true, + 'data' => $diplomas, + 'count' => count($diplomas) + ]); + +} catch (Exception $e) { + http_response_code(500); + echo json_encode([ + 'success' => false, + 'error' => $e->getMessage() + ]); +} +?> \ No newline at end of file diff --git a/api/login.php b/api/login.php index b62b8f4..9906b9c 100644 --- a/api/login.php +++ b/api/login.php @@ -2,80 +2,57 @@ header('Content-Type: application/json'); require '../includes/config.php'; -// Habilitar reporte de errores para depuración (quitar en producción) error_reporting(E_ALL); ini_set('display_errors', 1); -// Verificar si la solicitud es POST if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); echo json_encode(['success' => false, 'message' => 'Método no permitido']); exit; } -// Obtener datos del formulario -$username = trim($_POST['username'] ?? ''); +$email = trim($_POST['email'] ?? ''); $password = $_POST['password'] ?? ''; -// Validaciones básicas -if (empty($username) || empty($password)) { - echo json_encode(['success' => false, 'message' => 'Usuario y contraseña son requeridos']); +if (empty($email) || empty($password)) { + echo json_encode(['success' => false, 'message' => 'Email y contraseña son requeridos']); exit; } try { - // Buscar usuario en la base de datos - $stmt = $pdo->prepare("SELECT * FROM usuarios WHERE username = ?"); - $stmt->execute([$username]); - $user = $stmt->fetch(); + // Buscar profesor en la base de datos + $stmt = $pdo->prepare("SELECT * FROM usuarios WHERE email = ? AND aprobado = 1"); + $stmt->execute([$email]); + $profesor = $stmt->fetch(); - if (!$user) { - echo json_encode(['success' => false, 'message' => 'Usuario no encontrado']); + if (!$profesor) { + echo json_encode(['success' => false, 'message' => 'Profesor no encontrado o no aprobado']); exit; } - // Verificar contraseña - if (!password_verify($password, $user['password'])) { + if (!password_verify($password, $profesor['password'])) { echo json_encode(['success' => false, 'message' => 'Contraseña incorrecta']); exit; } - // Obtener cursos del usuario - $stmt = $pdo->prepare(" - SELECT c.*, uc.estado, uc.fecha_inicio, uc.fecha_fin, uc.profesor - FROM usuario_cursos uc - JOIN cursos c ON uc.curso_id = c.id - WHERE uc.usuario_id = ? - "); - $stmt->execute([$user['id']]); - $cursos = $stmt->fetchAll(); - - // Configurar sesión de usuario - $_SESSION['user'] = [ - 'id' => $user['id'], - 'username' => $user['username'], - 'nombre' => $user['nombre'], - 'email' => $user['email'], - 'rol' => $user['rol'], - 'cursos' => $cursos + // Configurar sesión de profesor + $_SESSION['profesor'] = [ + 'id' => $profesor['id'], + 'nombre' => $profesor['nombre'], + 'email' => $profesor['email'] ]; - // Respuesta exitosa echo json_encode([ 'success' => true, 'redirect' => 'dashboard.php', - 'user' => [ - 'id' => $user['id'], - 'nombre' => $user['nombre'], - 'rol' => $user['rol'] + 'profesor' => [ + 'id' => $profesor['id'], + 'nombre' => $profesor['nombre'] ] ]); } catch (PDOException $e) { - // Registrar error en archivo de log error_log('Error en login.php: ' . $e->getMessage()); - - // Respuesta de error genérico (no mostrar detalles internos al usuario) echo json_encode([ 'success' => false, 'message' => 'Error en el servidor. Por favor, intente más tarde.' diff --git a/assets/css/styles.css b/assets/css/styles.css index d106f83..2daf94d 100644 --- a/assets/css/styles.css +++ b/assets/css/styles.css @@ -566,3 +566,36 @@ header h1 { background-color: #a0aec0; cursor: not-allowed; } +/* Badges para tipos de curso */ +.badge { + padding: 4px 8px; + border-radius: 12px; + font-size: 0.8em; + font-weight: 600; + text-transform: capitalize; +} + +.badge.active { + background-color: #4CAF50; + color: white; +} + +.badge.inactive { + background-color: #f44336; + color: white; +} + +.badge.type-inyeccion { + background-color: #2196F3; + color: white; +} + +.badge.type-pildora { + background-color: #FF9800; + color: white; +} + +.badge.type-tratamiento { + background-color: #9C27B0; + color: white; +} diff --git a/assets/js/main.js b/assets/js/main.js index 6b93519..38b160d 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -6,7 +6,7 @@ document.addEventListener('DOMContentLoaded', function() { } // Configuración inicial del dashboard - if (document.body.classList.contains('admin') || document.body.classList.contains('user')) { + if (document.body.classList.contains('admin')) { initializeDashboard(); } }); @@ -47,126 +47,126 @@ function initializeDashboard() { function setupSidebarNavigation() { document.querySelectorAll('.sidebar-menu li').forEach(item => { - item.addEventListener('click', function() { - const section = this.getAttribute('data-section'); - showSection(section); - }); + if (item.getAttribute('data-section')) { + item.addEventListener('click', function() { + const section = this.getAttribute('data-section'); + showSection(section); + }); + } }); } function loadInitialData() { - fetch('api/cursos.php') - .then(response => response.json()) - .then(data => { - if (document.body.classList.contains('admin')) { - updateAdminStats(data); - } else { - updateUserStats(data); - } - }) - .catch(error => console.error('Error:', error)); + // Verificar si es admin o profesor + const isAdmin = document.body.classList.contains('admin'); + + // Hacer todas las peticiones en paralelo + Promise.all([ + fetch('api/cursos.php').then(res => res.json()), + fetch('api/alumnos.php').then(res => res.json()), + fetch('api/diplomas.php').then(res => res.json()) + ]) + .then(([courses, students, diplomas]) => { + if (isAdmin) { + updateAdminStats(courses, students, diplomas); + } else { + updateProfessorStats(courses, students, diplomas); + } + }) + .catch(error => { + console.error('Error loading initial data:', error); + showErrorNotification('Error al cargar datos iniciales'); + }); } -function updateAdminStats(courses) { - document.getElementById('active-courses-count').textContent = courses.length; - // Aquí puedes agregar más llamadas para estudiantes y diplomas - // fetch('api/estudiantes.php')... - // fetch('api/diplomas.php')... +function updateAdminStats(courses, students, diplomas) { + // Filtrar cursos activos + const activeCourses = courses.filter(c => c.estado === 'activo'); + + // Actualizar estadísticas + document.getElementById('active-courses-count').textContent = activeCourses.length; + document.getElementById('students-count').textContent = students.length; + document.getElementById('diplomas-count').textContent = diplomas.length; + + // Actualizar gráficos o tablas adicionales si existen + updateCoursesTable(activeCourses.slice(0, 5)); + updateRecentDiplomas(diplomas.slice(0, 5)); } -function updateUserStats(courses) { - document.getElementById('user-courses-count').textContent = courses.length; - const approvedCourses = courses.filter(c => c.estado === 'Aprobado'); - document.getElementById('user-diplomas-count').textContent = approvedCourses.length; - window.userCourses = courses; +function updateProfessorStats(courses, students, diplomas) { + const profesorId = getProfesorId(); - // Mostrar los primeros 5 cursos en el dashboard - renderDashboardCourses(courses.slice(0, 5)); - setupDashboardPagination(courses); - setupDashboardSearch(); + // Filtrar datos del profesor actual + const profesorCourses = courses.filter(c => c.profesor_id == profesorId); + const activeProfesorCourses = profesorCourses.filter(c => c.estado === 'activo'); + + // Obtener alumnos del profesor + const profesorStudents = students.filter(s => + profesorCourses.some(c => s.cursos.includes(c.id)) + ); + + // Obtener diplomas del profesor + const profesorDiplomas = diplomas.filter(d => + profesorCourses.some(c => d.curso_id === c.id) + ); + + // Actualizar estadísticas + document.getElementById('active-courses-count').textContent = activeProfesorCourses.length; + document.getElementById('students-count').textContent = profesorStudents.length; + document.getElementById('diplomas-count').textContent = profesorDiplomas.length; + + // Actualizar tablas específicas del profesor + updateProfessorCoursesTable(activeProfesorCourses); + updateProfessorStudentsTable(profesorStudents.slice(0, 5)); } -function renderDashboardCourses(courses) { - const tbody = document.getElementById('dashboard-courses-body'); - if (!tbody) return; + +function updateRecentDiplomas(diplomas) { + const tableBody = document.getElementById('diplomas-table-body'); + if (!tableBody) return; - tbody.innerHTML = courses.map(course => ` + tableBody.innerHTML = diplomas.map(diploma => ` - ${course.nombre} - ${course.fecha_inicio || '-'} - ${course.fecha_fin || '-'} + ${diploma.alumno_nombre} + ${diploma.curso_nombre} + ${new Date(diploma.fecha_emision).toLocaleDateString()} - ${course.estado === 'Aprobado' ? - `` : - 'No disponible'} + `).join(''); +} +function updateCoursesTable(courses) { + const tableBody = document.getElementById('courses-table-body'); + if (!tableBody) return; - // Configurar eventos de descarga - document.querySelectorAll('.download-btn').forEach(btn => { - btn.addEventListener('click', function() { - const courseId = this.getAttribute('data-course-id'); - window.open(`certificado.php?course_id=${courseId}`, '_blank'); - }); - }); + tableBody.innerHTML = courses.map(course => ` + + ${course.nombre} + ${course.tipo} + ${course.alumnos_count || 0} + ${course.estado} + + `).join(''); } -function setupDashboardPagination(allCourses) { - let currentPage = 1; - const perPage = 5; - const totalPages = Math.ceil(allCourses.length / perPage); +function updateDashboardStats(courses, students, diplomas) { + const activeCourses = courses.filter(c => c.estado === 'activo'); - function updatePagination() { - const start = (currentPage - 1) * perPage; - const end = start + perPage; - renderDashboardCourses(allCourses.slice(start, end)); - - document.getElementById('page-info').textContent = `Página ${currentPage} de ${totalPages}`; - document.getElementById('prev-page').disabled = currentPage === 1; - document.getElementById('next-page').disabled = currentPage === totalPages || totalPages === 0; + if (document.getElementById('active-courses-count')) { + document.getElementById('active-courses-count').textContent = activeCourses.length; } - document.getElementById('prev-page')?.addEventListener('click', () => { - if (currentPage > 1) { - currentPage--; - updatePagination(); - } - }); + if (document.getElementById('students-count')) { + document.getElementById('students-count').textContent = students.length; + } - document.getElementById('next-page')?.addEventListener('click', () => { - if (currentPage < totalPages) { - currentPage++; - updatePagination(); - } - }); - - updatePagination(); -} - -function setupDashboardSearch() { - const searchBtn = document.getElementById('dashboard-search-btn'); - const searchInput = document.getElementById('dashboard-course-search'); - - if (searchBtn && searchInput) { - searchBtn.addEventListener('click', () => { - const term = searchInput.value.toLowerCase(); - const filtered = window.userCourses.filter(course => - course.nombre.toLowerCase().includes(term) || - course.tipo.toLowerCase().includes(term) || - course.estado.toLowerCase().includes(term) - ); - - setupDashboardPagination(filtered); - }); - - // Permitir búsqueda al presionar Enter - searchInput.addEventListener('keypress', (e) => { - if (e.key === 'Enter') { - searchBtn.click(); - } - }); + if (document.getElementById('diplomas-count')) { + document.getElementById('diplomas-count').textContent = diplomas.length; } } + function showSection(sectionId, isInitialLoad = false) { // Actualizar menú activo updateActiveMenu(sectionId); @@ -176,7 +176,7 @@ function showSection(sectionId, isInitialLoad = false) { if (sectionElement) { toggleSections(sectionElement); - // Solo cargar contenido dinámico si no es la carga inicial del dashboard + // Solo cargar contenido dinámico si no es la carga inicial del dashboard if (!(isInitialLoad && sectionId === 'dashboard')) { if (sectionId === 'dashboard') { // Recargar los datos del dashboard @@ -184,21 +184,22 @@ function showSection(sectionId, isInitialLoad = false) { } else { loadDynamicContent(sectionId, sectionElement); } - } } } +} function updateActiveMenu(sectionId) { document.querySelectorAll('.sidebar-menu li').forEach(li => { li.classList.remove('active'); }); - document.querySelector(`.sidebar-menu li[data-section="${sectionId}"]`).classList.add('active'); + + const activeItem = document.querySelector(`.sidebar-menu li[data-section="${sectionId}"]`); + if (activeItem) { + activeItem.classList.add('active'); + } } function getSectionElement(sectionId) { - if (sectionId === 'dashboard') { - return document.getElementById('dashboard-content'); - } return document.getElementById(`${sectionId}-content`); } @@ -210,66 +211,133 @@ function toggleSections(activeSection) { } function loadDynamicContent(sectionId, container) { - // Mostrar loader mientras se carga container.innerHTML = '
Cargando...
'; switch(sectionId) { + case 'dashboard': + loadDashboardContent(container); + break; case 'courses': - loadAdminCourses(container); + loadProfessorCourses(container); break; case 'students': - loadAdminStudents(container); - break; - case 'my-courses': - loadUserCourses(container); + loadStudentsManagement(container); break; case 'diplomas': - loadUserDiplomas(container); - break; - case 'profile': - loadProfileSection(container); + loadDiplomasSection(container); break; default: container.innerHTML = '

Sección no implementada

'; } } +async function loadDashboardContent(container) { + try { + container.innerHTML = '
Cargando datos...
'; + + // Obtener datos del profesor + const profesorId = getProfesorId(); + if (!profesorId) throw new Error('No se pudo obtener ID de profesor'); + + // Hacer peticiones en paralelo + const responses = await Promise.all([ + fetch(`api/cursos.php?profesor_id=${profesorId}`), + fetch('api/alumnos.php'), + fetch(`api/diplomas.php?profesor_id=${profesorId}`) + ]); + + // Verificar respuestas + for (const response of responses) { + if (!response.ok) throw new Error(`Error HTTP: ${response.status}`); + } + + // Parsear JSON + const [courses, students, diplomas] = await Promise.all( + responses.map(r => r.json()) + ); + + // Filtrar cursos activos + const activeCourses = Array.isArray(courses) ? + courses.filter(c => c.estado === 'activo') : []; + + // Generar HTML + container.innerHTML = ` +
+

Resumen General

+
+

Resumen:

+

${activeCourses.length} cursos activos

+

${students.length || 0} alumnos registrados

+

${diplomas.length || 0} diplomas emitidos

+
+
+
+

Mis Cursos Activos

+ ${generateCoursesPreview(activeCourses.slice(0, 5))} +
`; + + } catch (error) { + console.error('Error loading dashboard:', error); + container.innerHTML = ` +
+

Error al cargar datos

+

${error.message}

+ +
`; + } +} + // Funciones para cargar contenido específico -function loadAdminCourses(container) { - fetch('api/cursos.php') +function loadProfessorCourses(container) { + fetch(`api/cursos.php?profesor_id=${getProfesorId()}`) .then(response => response.json()) .then(courses => { container.innerHTML = `
-

Gestión de Cursos

+

Mis Cursos

+ + + - - + -
- - -
- - +

Lista de Cursos

-
- ${generateCoursesList(courses)} +
+ + +
+
+ + + + + + + + + + + ${generateCoursesTableRows(courses)} + +
NombreTipoEstadoAcciones
`; setupCourseForm(); + setupCourseSearch(); }) .catch(error => { container.innerHTML = '

Error al cargar los cursos

'; @@ -277,96 +345,241 @@ function loadAdminCourses(container) { }); } -function loadUserCourses(container) { - const courses = window.userCourses || []; - +function loadStudentsManagement(container) { container.innerHTML = `
-

Mis Cursos

-
- - -
-
- ${courses.length > 0 ? - courses.map(course => generateCourseCard(course)).join('') : - '

No tienes cursos registrados.

'} -
-
`; - - setupCourseSearch(); -} - -function loadUserDiplomas(container) { - const courses = (window.userCourses || []).filter(c => c.estado === 'Aprobado'); - - container.innerHTML = ` -
-

Mis Diplomas

- ${courses.length > 0 ? - courses.map(course => generateDiplomaCard(course)).join('') : - '

No tienes diplomas disponibles todavía.

'} -
`; - - setupDiplomaDownloads(); -} - -// Funciones auxiliares -function generateCoursesList(courses) { - return courses.map(course => ` -
-

${course.nombre}

-

Tipo: ${course.tipo}

-

ID: ${course.id}

+

Gestión de Alumnos

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

Lista de Alumnos

+
+ + +
+
+ + + + + + + + + + + + +
NombreEmailTeléfonoAcciones
+
+
`; + + fetch('api/alumnos.php') + .then(response => response.json()) + .then(students => { + renderStudentsTable(students); + }) + .catch(error => { + console.error('Error:', error); + }); + + setupStudentForm(); + setupStudentSearch(); +} + +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} + + +
+
+
+ Mostrando ${data.data.length} diplomas +
+
`; + }) + .catch(error => { + console.error('Error:', error); + container.innerHTML = ` +
+

Error al cargar diplomas

+

${error.message}

+ +
`; + }); +} + +// Función para generar nuevo diploma +function generateNewDiploma() { + // Implementar lógica para seleccionar alumno y curso + alert('Implementar diálogo para seleccionar alumno y curso'); +} + +// Funciones auxiliares para generar contenido +function generateCoursesTableRows(courses) { + return courses.map(course => ` + + ${course.nombre} + ${course.tipo} + ${course.estado} + + + + + `).join(''); } -function generateCourseCard(course) { - return ` -
-

${course.nombre}

-

Tipo: ${course.tipo}

-

Estado: ${course.estado}

- ${course.competencias ? `

Competencias: ${course.competencias}

` : ''} -

Profesor: ${course.profesor || 'No asignado'}

-

Fecha: ${course.fecha_inicio} a ${course.fecha_fin}

-
`; +function generateStudentsTableRows(students) { + return students.map(student => ` + + ${student.nombre} + ${student.email} + ${student.telefono || '-'} + + + + + + `).join(''); } -function generateDiplomaCard(course) { - return ` -
-

Diploma de ${course.nombre}

-

Fecha: ${course.fecha_fin || 'Completado'}

-

Profesor: ${course.profesor || 'No especificado'}

- -
`; +function generateDiplomasTableRows(diplomas) { + return diplomas.map(diploma => ` + + ${diploma.alumno_nombre} + ${diploma.curso_nombre} + ${new Date(diploma.fecha_emision).toLocaleDateString()} + + + + + + `).join(''); } - -// Configuración de eventos dinámicos -function setupCourseForm() { - const courseTypeSelect = document.getElementById('courseType'); - if (courseTypeSelect) { - courseTypeSelect.addEventListener('change', function() { - const competencesField = document.getElementById('competencesField'); - if (competencesField) { - competencesField.classList.toggle('oculto', this.value !== 'tratamiento'); - } - }); - } +function generateDashboardCoursesRows(courses) { + return courses.map(course => ` + + ${course.nombre} + ${course.tipo} + ${course.alumnos_count || 0} + ${course.estado} + + `).join(''); +} +function generateCoursesPreview(courses) { + if (!courses.length) return '

No tienes cursos activos

'; + return ` +
+ + + + + + + + + + + ${courses.map(course => ` + + + + + + + `).join('')} + +
NombreTipoAlumnosEstado
${course.nombre || 'Sin nombre'}${course.tipo || 'N/A'}${course.alumnos_count || 0}${course.estado || 'N/A'}
+
`; +} +// Configuración de formularios y eventos +function setupCourseForm() { const courseForm = document.getElementById('courseForm'); if (courseForm) { courseForm.addEventListener('submit', function(e) { e.preventDefault(); const formData = new FormData(this); - const jsonData = {}; - formData.forEach((value, key) => jsonData[key] = value); + const jsonData = { + nombre: formData.get('nombre'), + descripcion: formData.get('descripcion'), + tipo: formData.get('tipo'), + profesor_id: getProfesorId() + }; fetch('api/cursos.php', { method: 'POST', @@ -377,7 +590,7 @@ function setupCourseForm() { .then(data => { if (data.success) { alert('Curso creado exitosamente'); - showSection('courses'); + showSection('courses'); // Recargar la sección } else { alert('Error al crear el curso'); } @@ -387,54 +600,209 @@ function setupCourseForm() { } } -function setupCourseSearch() { - const searchButton = document.getElementById('searchButton'); - if (searchButton) { - searchButton.addEventListener('click', function() { - const searchTerm = document.getElementById('courseSearch').value.toLowerCase(); - const courses = window.userCourses || []; - const filteredCourses = courses.filter(course => - course.nombre.toLowerCase().includes(searchTerm) || - (course.profesor && course.profesor.toLowerCase().includes(searchTerm)) - ); +function setupStudentForm() { + const studentForm = document.getElementById('studentForm'); + if (studentForm) { + studentForm.addEventListener('submit', function(e) { + e.preventDefault(); + const formData = new FormData(this); + const jsonData = { + nombre: formData.get('nombre'), + email: formData.get('email'), + telefono: formData.get('telefono') + }; - const courseList = document.querySelector('.course-list'); - if (courseList) { - courseList.innerHTML = filteredCourses.length > 0 ? - filteredCourses.map(course => generateCourseCard(course)).join('') : - '

No se encontraron cursos que coincidan con la búsqueda.

'; - } + fetch('api/alumnos.php', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(jsonData) + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + alert('Alumno registrado exitosamente'); + showSection('students'); // Recargar la sección + } else { + alert('Error al registrar al alumno'); + } + }) + .catch(error => console.error('Error:', error)); }); } } -function setupDiplomaDownloads() { - document.querySelectorAll('.download-btn').forEach(btn => { - btn.addEventListener('click', function() { - - - // Mostrar mensaje de carga - const originalText = this.innerHTML; - this.innerHTML = 'Generando diploma...'; - this.disabled = true; - - // Abrir en nueva pestaña en lugar de usar fetch - window.open(`certificado.php`, '_blank'); - - // Restaurar botón después de un breve retraso - setTimeout(() => { - this.innerHTML = originalText; - this.disabled = false; - }, 2000); +function setupCourseSearch() { + const searchBtn = document.getElementById('searchCourseBtn'); + const searchInput = document.getElementById('courseSearch'); + + if (searchBtn && searchInput) { + searchBtn.addEventListener('click', searchCourses); + searchInput.addEventListener('keypress', function(e) { + if (e.key === 'Enter') searchCourses(); }); - }); + } } -// Funciones de secciones no implementadas (para completar) -function loadAdminStudents(container) { - container.innerHTML = '

Gestión de Estudiantes

Sección en desarrollo

'; +function setupStudentSearch() { + const searchBtn = document.getElementById('searchStudentBtn'); + const searchInput = document.getElementById('studentSearch'); + + if (searchBtn && searchInput) { + searchBtn.addEventListener('click', searchStudents); + searchInput.addEventListener('keypress', function(e) { + if (e.key === 'Enter') searchStudents(); + }); + } } -function loadProfileSection(container) { - container.innerHTML = '

Perfil de Usuario

Sección en desarrollo

'; +function searchCourses() { + const term = document.getElementById('courseSearch').value.toLowerCase(); + + fetch(`api/cursos.php?profesor_id=${getProfesorId()}`) + .then(response => response.json()) + .then(courses => { + const filtered = courses.filter(course => + course.nombre.toLowerCase().includes(term) || + course.tipo.toLowerCase().includes(term) || + course.estado.toLowerCase().includes(term) + ); + + document.getElementById('coursesTableBody').innerHTML = generateCoursesTableRows(filtered); + }) + .catch(error => console.error('Error:', error)); +} + +function searchStudents() { + const term = document.getElementById('studentSearch').value.toLowerCase(); + + fetch('api/alumnos.php') + .then(response => response.json()) + .then(students => { + const filtered = students.filter(student => + student.nombre.toLowerCase().includes(term) || + student.email.toLowerCase().includes(term) || + (student.telefono && student.telefono.toLowerCase().includes(term)) + ); + + document.getElementById('studentsTableBody').innerHTML = generateStudentsTableRows(filtered); + }) + .catch(error => console.error('Error:', error)); +} + +function renderStudentsTable(students) { + const tbody = document.getElementById('studentsTableBody'); + if (tbody) { + tbody.innerHTML = generateStudentsTableRows(students); + } +} + +function setupDiplomaActions() { + // Los eventos se manejan directamente con onclick en los botones +} + +// Funciones de acciones +function editCourse(courseId) { + // Implementar lógica de edición + alert(`Editar curso con ID: ${courseId}`); +} + +function deleteCourse(courseId) { + if (confirm('¿Estás seguro de eliminar este curso?')) { + fetch(`api/cursos.php?id=${courseId}`, { + method: 'DELETE' + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + showSection('courses'); // Recargar la sección + } else { + alert('Error al eliminar el curso'); + } + }) + .catch(error => console.error('Error:', error)); + } +} + +function editStudent(studentId) { + // Implementar lógica de edición + alert(`Editar alumno con ID: ${studentId}`); +} + +function deleteStudent(studentId) { + if (confirm('¿Estás seguro de eliminar este alumno?')) { + fetch(`api/alumnos.php?id=${studentId}`, { + method: 'DELETE' + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + showSection('students'); // Recargar la sección + } else { + alert('Error al eliminar el alumno'); + } + }) + .catch(error => console.error('Error:', error)); + } +} + +function resendDiploma(diplomaId) { + fetch(`api/diplomas.php?action=resend&id=${diplomaId}`) + .then(response => response.json()) + .then(data => { + if (data.success) { + alert('Diploma reenviado exitosamente'); + } else { + alert('Error al reenviar el diploma'); + } + }) + .catch(error => console.error('Error:', error)); +} + +function downloadDiploma(diplomaId) { + window.open(`certificado.php?diploma_id=${diplomaId}`, '_blank'); +} + +// Función para obtener el ID del profesor desde la sesión +function getProfesorId() { + // En una implementación real, esto debería venir de la sesión + // Esto es solo un ejemplo temporal + return 1; +} +function getCourseTypeClass(type) { + const types = { + 'inyeccion': 'type-inyeccion', + 'pildora': 'type-pildora', + 'tratamiento': 'type-tratamiento' + }; + return types[type] || ''; +} + +// Funciones globales para usar en onclick +window.editCourse = editCourse; +window.deleteCourse = deleteCourse; +window.editStudent = editStudent; +window.deleteStudent = deleteStudent; +window.resendDiploma = resendDiploma; +window.downloadDiploma = downloadDiploma; + +//Diplomas +function downloadDiploma(codigo) { + window.open(`certificado.php?codigo=${codigo}`, '_blank'); +} + +// Función para reenviar diploma +function resendDiploma(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'); + }); } \ No newline at end of file diff --git a/dashboard.php b/dashboard.php index 6121c78..414e581 100644 --- a/dashboard.php +++ b/dashboard.php @@ -2,7 +2,7 @@ include 'includes/config.php'; redirect_if_not_logged_in(); -$user = $_SESSION['user']; +$profesor = $_SESSION['profesor']; ?> @@ -13,108 +13,49 @@ $user = $_SESSION['user']; - +

DiploMaster

-
- +
+
- - -
-
-

Panel de Administración

-

Bienvenido al sistema de gestión de DiploMaster

-
-

Estadísticas:

-

0 cursos activos

-

0 estudiantes registrados

-

0 diplomas emitidos

-
+
+
+

Bienvenido

+

Este es tu panel de gestión de DiploMaster

+
+

Resumen:

+

0 cursos activos

+

0 alumnos registrados

+

0 diplomas emitidos

- -
- -
- -
- -
- - -
-
-

Bienvenido

-

Este es tu panel de control en DiploMaster

-
-

Resumen:

-

0 cursos registrados

-

0 diplomas disponibles

-
-
- -
-

Mis Cursos Recientes

-
- - -
-
- - - - - - - - - - - - -
NombreFecha InicioFecha FinAcciones
- -
-
-
- -
- -
- -
- -
- +
- -
+
+ +
+ +
+ +
+ +
diff --git a/includes/config.php b/includes/config.php index 930bb62..0ab85c9 100644 --- a/includes/config.php +++ b/includes/config.php @@ -21,7 +21,7 @@ try { } function is_logged_in() { - return isset($_SESSION['user']); + return isset($_SESSION['profesor']); } function redirect_if_not_logged_in() { diff --git a/index.php b/index.php index 73ec632..cda4885 100644 --- a/index.php +++ b/index.php @@ -17,14 +17,14 @@

DiploMaster

-

Bienvenido al sistema de diplomas

+

Sistema de gestión de diplomas para profesores

- +
@@ -40,11 +40,6 @@ - -
diff --git a/sql/diplomaster (1).sql b/sql/diplomaster (1).sql index 89c3975..a1a759c 100644 --- a/sql/diplomaster (1).sql +++ b/sql/diplomaster (1).sql @@ -1,157 +1,57 @@ --- phpMyAdmin SQL Dump --- version 5.2.1 --- https://www.phpmyadmin.net/ --- --- Servidor: 127.0.0.1 --- Tiempo de generación: 05-05-2025 a las 04:15:28 --- Versión del servidor: 10.4.32-MariaDB --- Versión de PHP: 8.2.12 - -SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; -START TRANSACTION; -SET time_zone = "+00:00"; - - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8mb4 */; - --- --- Base de datos: `diplomaster` --- - --- -------------------------------------------------------- - --- --- Estructura de tabla para la tabla `cursos` --- - -CREATE TABLE `cursos` ( - `id` int(11) NOT NULL, - `nombre` varchar(100) NOT NULL, - `tipo` enum('pildora','inyeccion','tratamiento') NOT NULL, - `competencias` text DEFAULT NULL, - `fecha_creacion` timestamp NOT NULL DEFAULT current_timestamp() -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; - --- --- Volcado de datos para la tabla `cursos` --- - -INSERT INTO `cursos` (`id`, `nombre`, `tipo`, `competencias`, `fecha_creacion`) VALUES -(1, 'Seguridad Informática', 'tratamiento', 'Análisis de datos, Comunicación efectiva', '2025-05-05 01:27:58'), -(2, 'Introducción a Python', 'pildora', NULL, '2025-05-05 01:27:58'), -(3, 'Machine Learning Avanzado', 'tratamiento', 'Modelado predictivo, Python', '2025-05-05 01:27:58'); - --- -------------------------------------------------------- - --- --- Estructura de tabla para la tabla `usuarios` --- +-- Crear la base de datos +CREATE DATABASE IF NOT EXISTS diplomaster; +USE diplomaster; +-- Tabla de usuarios (profesores) CREATE TABLE `usuarios` ( - `id` int(11) NOT NULL, - `username` varchar(50) NOT NULL, - `password` varchar(255) NOT NULL, - `nombre` varchar(100) NOT NULL, - `email` varchar(100) NOT NULL, - `rol` enum('admin','user') NOT NULL DEFAULT 'user', - `fecha_registro` timestamp NOT NULL DEFAULT current_timestamp() + `id` INT(11) NOT NULL AUTO_INCREMENT, + `nombre` VARCHAR(100) NOT NULL, + `email` VARCHAR(100) UNIQUE NOT NULL, + `password` VARCHAR(255) NOT NULL, + `aprobado` BOOLEAN NOT NULL DEFAULT 0, + PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; --- --- Volcado de datos para la tabla `usuarios` --- - -INSERT INTO `usuarios` (`id`, `username`, `password`, `nombre`, `email`, `rol`, `fecha_registro`) VALUES -(1, 'admin', '$2y$10$H3tCRUt444g0jo996uiKXenINy2d84FfuwQhoDBfa3tNblZLtNZpK', 'Administrador', 'admin@diplomaster.com', 'admin', '2025-05-05 01:27:58'), -(2, 'usuario1', '$2y$10$SjyU29E200ax73/m0NTjqe0sMLmpsPBThlIUucGKyxvqh/znHiwh.', 'Juan Pérez', 'juan@example.com', 'user', '2025-05-05 01:27:58'); - --- -------------------------------------------------------- - --- --- Estructura de tabla para la tabla `usuario_cursos` --- - -CREATE TABLE `usuario_cursos` ( - `id` int(11) NOT NULL, - `usuario_id` int(11) NOT NULL, - `curso_id` int(11) NOT NULL, - `estado` enum('En progreso','Aprobado','Completado') NOT NULL DEFAULT 'En progreso', - `fecha_inicio` date DEFAULT NULL, - `fecha_fin` date DEFAULT NULL, - `profesor` varchar(100) DEFAULT NULL +-- Tabla de cursos (cada profesor crea sus cursos) +CREATE TABLE `cursos` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `nombre` VARCHAR(100) NOT NULL, + `descripcion` VARCHAR(250) DEFAULT NULL, + `estado` ENUM('activo', 'completado', 'archivado') NOT NULL DEFAULT 'activo', + `tipo` ENUM('inyeccion', 'pildora', 'tratamiento') NOT NULL, + `profesor_id` INT(11) NOT NULL, + FOREIGN KEY (`profesor_id`) REFERENCES `usuarios`(`id`) ON DELETE CASCADE, + PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; --- --- Volcado de datos para la tabla `usuario_cursos` --- +-- Tabla de alumnos +CREATE TABLE `alumnos` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `nombre` VARCHAR(100) NOT NULL, + `email` VARCHAR(100) UNIQUE NOT NULL, + `telefono` VARCHAR(15) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; -INSERT INTO `usuario_cursos` (`id`, `usuario_id`, `curso_id`, `estado`, `fecha_inicio`, `fecha_fin`, `profesor`) VALUES -(1, 2, 1, 'Aprobado', '2023-01-15', '2023-04-20', 'Dra. Ana López'), -(2, 2, 2, 'En progreso', '2023-05-10', NULL, 'Prof. Carlos Ruiz'); +-- Tabla para vincular alumnos con cursos +CREATE TABLE `alumnos_cursos` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `alumno_id` INT(11) NOT NULL, + `curso_id` INT(11) NOT NULL, + `estado` ENUM('cursando', 'aprobado', 'reprobado') NOT NULL DEFAULT 'cursando', + `competencias` TEXT DEFAULT NULL, -- Solo para tratamiento + FOREIGN KEY (`alumno_id`) REFERENCES `alumnos`(`id`) ON DELETE CASCADE, + FOREIGN KEY (`curso_id`) REFERENCES `cursos`(`id`) ON DELETE CASCADE, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; --- --- Índices para tablas volcadas --- +-- Tabla de diplomas +CREATE TABLE `diplomas` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `alumno_curso_id` INT(11) NOT NULL, + `fecha_emision` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `competencias` TEXT DEFAULT NULL, + FOREIGN KEY (`alumno_curso_id`) REFERENCES `alumnos_cursos`(`id`) ON DELETE CASCADE, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; --- --- Indices de la tabla `cursos` --- -ALTER TABLE `cursos` - ADD PRIMARY KEY (`id`); - --- --- Indices de la tabla `usuarios` --- -ALTER TABLE `usuarios` - ADD PRIMARY KEY (`id`), - ADD UNIQUE KEY `username` (`username`), - ADD UNIQUE KEY `email` (`email`); - --- --- Indices de la tabla `usuario_cursos` --- -ALTER TABLE `usuario_cursos` - ADD PRIMARY KEY (`id`), - ADD KEY `usuario_id` (`usuario_id`), - ADD KEY `curso_id` (`curso_id`); - --- --- AUTO_INCREMENT de las tablas volcadas --- - --- --- AUTO_INCREMENT de la tabla `cursos` --- -ALTER TABLE `cursos` - MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4; - --- --- AUTO_INCREMENT de la tabla `usuarios` --- -ALTER TABLE `usuarios` - MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3; - --- --- AUTO_INCREMENT de la tabla `usuario_cursos` --- -ALTER TABLE `usuario_cursos` - MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3; - --- --- Restricciones para tablas volcadas --- - --- --- Filtros para la tabla `usuario_cursos` --- -ALTER TABLE `usuario_cursos` - ADD CONSTRAINT `usuario_cursos_ibfk_1` FOREIGN KEY (`usuario_id`) REFERENCES `usuarios` (`id`), - ADD CONSTRAINT `usuario_cursos_ibfk_2` FOREIGN KEY (`curso_id`) REFERENCES `cursos` (`id`); -COMMIT; - -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;