DiploMaster/assets/js/main.js

808 lines
25 KiB
JavaScript

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();
}
});
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));
}
function initializeDashboard() {
// Configurar eventos del menú lateral
setupSidebarNavigation();
// Cargar datos iniciales
loadInitialData();
// Mostrar la sección activa inicial
const activeSection = document.querySelector('.sidebar-menu li.active');
if (activeSection) {
const sectionId = activeSection.getAttribute('data-section');
showSection(sectionId, true); // true indica que es la carga inicial
}
}
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);
});
}
});
}
function loadInitialData() {
// 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, 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 updateProfessorStats(courses, students, diplomas) {
const profesorId = getProfesorId();
// 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 updateRecentDiplomas(diplomas) {
const tableBody = document.getElementById('diplomas-table-body');
if (!tableBody) return;
tableBody.innerHTML = diplomas.map(diploma => `
<tr>
<td>${diploma.alumno_nombre}</td>
<td>${diploma.curso_nombre}</td>
<td>${new Date(diploma.fecha_emision).toLocaleDateString()}</td>
<td>
<button class="btn btn-sm" onclick="downloadDiploma('${diploma.codigo_unico}')">
Descargar
</button>
</td>
</tr>
`).join('');
}
function updateCoursesTable(courses) {
const tableBody = document.getElementById('courses-table-body');
if (!tableBody) return;
tableBody.innerHTML = courses.map(course => `
<tr>
<td>${course.nombre}</td>
<td><span class="badge ${getCourseTypeClass(course.tipo)}">${course.tipo}</span></td>
<td>${course.alumnos_count || 0}</td>
<td><span class="badge ${course.estado === 'activo' ? 'active' : 'inactive'}">${course.estado}</span></td>
</tr>
`).join('');
}
function updateDashboardStats(courses, students, diplomas) {
const activeCourses = courses.filter(c => c.estado === 'activo');
if (document.getElementById('active-courses-count')) {
document.getElementById('active-courses-count').textContent = activeCourses.length;
}
if (document.getElementById('students-count')) {
document.getElementById('students-count').textContent = students.length;
}
if (document.getElementById('diplomas-count')) {
document.getElementById('diplomas-count').textContent = diplomas.length;
}
}
function showSection(sectionId, isInitialLoad = false) {
// Actualizar menú activo
updateActiveMenu(sectionId);
// Mostrar la sección correspondiente
const sectionElement = getSectionElement(sectionId);
if (sectionElement) {
toggleSections(sectionElement);
// 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
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');
}
}
function getSectionElement(sectionId) {
return document.getElementById(`${sectionId}-content`);
}
function toggleSections(activeSection) {
document.querySelectorAll('.content-section').forEach(section => {
section.classList.remove('active');
});
activeSection.classList.add('active');
}
function loadDynamicContent(sectionId, container) {
container.innerHTML = '<div class="loader">Cargando...</div>';
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 = '<div class="card"><h2>Sección no implementada</h2></div>';
}
}
async function loadDashboardContent(container) {
try {
container.innerHTML = '<div class="loader">Cargando datos...</div>';
// 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 = `
<div class="card">
<h2>Resumen General</h2>
<div class="stats">
<p><strong>Resumen:</strong></p>
<p>• <span class="stat-number">${activeCourses.length}</span> cursos activos</p>
<p>• <span class="stat-number">${students.length || 0}</span> alumnos registrados</p>
<p>• <span class="stat-number">${diplomas.length || 0}</span> diplomas emitidos</p>
</div>
</div>
<div class="card">
<h2>Mis Cursos Activos</h2>
${generateCoursesPreview(activeCourses.slice(0, 5))}
</div>`;
} catch (error) {
console.error('Error loading dashboard:', error);
container.innerHTML = `
<div class="card error-card">
<h2>Error al cargar datos</h2>
<p>${error.message}</p>
<button class="btn" onclick="showSection('dashboard')">Reintentar</button>
</div>`;
}
}
// Funciones para cargar contenido específico
function loadProfessorCourses(container) {
fetch(`api/cursos.php?profesor_id=${getProfesorId()}`)
.then(response => response.json())
.then(courses => {
container.innerHTML = `
<div class="card">
<h2>Mis Cursos</h2>
<form id="courseForm">
<label>Nombre del Curso</label>
<input type="text" name="nombre" placeholder="Ej. Seguridad Informática" required>
<label>Descripción</label>
<textarea name="descripcion" placeholder="Descripción del curso"></textarea>
<label>Tipo de Curso</label>
<select name="tipo" required>
<option value="">Seleccionar</option>
<option value="inyeccion">Inyección</option>
<option value="pildora">Píldora</option>
<option value="tratamiento">Tratamiento</option>
</select>
<button class="btn" type="submit">Crear Curso</button>
</form>
</div>
<div class="card">
<h2>Lista de Cursos</h2>
<div class="search-container">
<input type="text" id="courseSearch" placeholder="Buscar cursos..." class="search-input">
<button class="btn" id="searchCourseBtn">Buscar</button>
</div>
<div class="table-container">
<table class="courses-table">
<thead>
<tr>
<th>Nombre</th>
<th>Tipo</th>
<th>Estado</th>
<th>Acciones</th>
</tr>
</thead>
<tbody id="coursesTableBody">
${generateCoursesTableRows(courses)}
</tbody>
</table>
</div>
</div>`;
setupCourseForm();
setupCourseSearch();
})
.catch(error => {
container.innerHTML = '<div class="card"><h2>Error al cargar los cursos</h2></div>';
console.error('Error:', error);
});
}
function loadStudentsManagement(container) {
container.innerHTML = `
<div class="card">
<h2>Gestión de Alumnos</h2>
<form id="studentForm">
<label>Nombre del Alumno</label>
<input type="text" name="nombre" required>
<label>Email</label>
<input type="email" name="email" required>
<label>Teléfono</label>
<input type="tel" name="telefono">
<button class="btn" type="submit">Registrar Alumno</button>
</form>
</div>
<div class="card">
<h2>Lista de Alumnos</h2>
<div class="search-container">
<input type="text" id="studentSearch" placeholder="Buscar alumnos..." class="search-input">
<button class="btn" id="searchStudentBtn">Buscar</button>
</div>
<div class="table-container">
<table class="students-table">
<thead>
<tr>
<th>Nombre</th>
<th>Email</th>
<th>Teléfono</th>
<th>Acciones</th>
</tr>
</thead>
<tbody id="studentsTableBody">
<!-- Se llenará dinámicamente -->
</tbody>
</table>
</div>
</div>`;
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 = '<div class="loader">Cargando diplomas...</div>';
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 = `
<div class="card">
<h2>Diplomas Emitidos</h2>
<p>No hay diplomas registrados aún</p>
<button class="btn" onclick="generateNewDiploma()">Generar Primer Diploma</button>
</div>`;
return;
}
container.innerHTML = `
<div class="card">
<h2>Diplomas Emitidos</h2>
<div class="controls">
<button class="btn" onclick="generateNewDiploma()">Generar Nuevo Diploma</button>
<div class="search-container">
<input type="text" id="diplomaSearch" placeholder="Buscar por alumno o curso...">
<button class="btn" onclick="searchDiplomas()">Buscar</button>
</div>
</div>
<div class="table-container">
<table class="diplomas-table">
<thead>
<tr>
<th>Alumno</th>
<th>Email</th>
<th>Curso</th>
<th>Tipo</th>
<th>Fecha</th>
<th>Código</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
${data.data.map(diploma => `
<tr>
<td>${diploma.alumno_nombre}</td>
<td>${diploma.alumno_email}</td>
<td>${diploma.curso_nombre}</td>
<td><span class="badge ${getCourseTypeClass(diploma.curso_tipo)}">${diploma.curso_tipo}</span></td>
<td>${diploma.fecha_formateada}</td>
<td class="code">${diploma.codigo_unico}</td>
<td>
<button class="btn" onclick="downloadDiploma('${diploma.codigo_unico}')">
<i class="icon-download"></i> Descargar
</button>
<button class="btn" onclick="resendDiploma('${diploma.codigo_unico}', '${diploma.alumno_email}')">
<i class="icon-send"></i> Reenviar
</button>
</td>
</tr>
`).join('')}
</tbody>
</table>
</div>
<div class="pagination-info">
Mostrando ${data.data.length} diplomas
</div>
</div>`;
})
.catch(error => {
console.error('Error:', error);
container.innerHTML = `
<div class="card error-card">
<h2>Error al cargar diplomas</h2>
<p>${error.message}</p>
<button class="btn" onclick="loadDiplomasSection(this.parentElement)">
Reintentar
</button>
</div>`;
});
}
// 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 => `
<tr>
<td>${course.nombre}</td>
<td>${course.tipo}</td>
<td>${course.estado}</td>
<td>
<button class="btn" onclick="editCourse(${course.id})">Editar</button>
<button class="btn btn-danger" onclick="deleteCourse(${course.id})">Eliminar</button>
</td>
</tr>
`).join('');
}
function generateStudentsTableRows(students) {
return students.map(student => `
<tr>
<td>${student.nombre}</td>
<td>${student.email}</td>
<td>${student.telefono || '-'}</td>
<td>
<button class="btn" onclick="editStudent(${student.id})">Editar</button>
<button class="btn btn-danger" onclick="deleteStudent(${student.id})">Eliminar</button>
</td>
</tr>
`).join('');
}
function generateDiplomasTableRows(diplomas) {
return diplomas.map(diploma => `
<tr>
<td>${diploma.alumno_nombre}</td>
<td>${diploma.curso_nombre}</td>
<td>${new Date(diploma.fecha_emision).toLocaleDateString()}</td>
<td>
<button class="btn" onclick="resendDiploma(${diploma.id})">Reenviar</button>
<button class="btn" onclick="downloadDiploma(${diploma.id})">Descargar</button>
</td>
</tr>
`).join('');
}
function generateDashboardCoursesRows(courses) {
return courses.map(course => `
<tr>
<td>${course.nombre}</td>
<td><span class="badge ${getCourseTypeClass(course.tipo)}">${course.tipo}</span></td>
<td>${course.alumnos_count || 0}</td>
<td><span class="badge ${course.estado === 'activo' ? 'active' : 'inactive'}">${course.estado}</span></td>
</tr>
`).join('');
}
function generateCoursesPreview(courses) {
if (!courses.length) return '<p>No tienes cursos activos</p>';
return `
<div class="table-container">
<table class="preview-table">
<thead>
<tr>
<th>Nombre</th>
<th>Tipo</th>
<th>Alumnos</th>
<th>Estado</th>
</tr>
</thead>
<tbody>
${courses.map(course => `
<tr>
<td>${course.nombre || 'Sin nombre'}</td>
<td><span class="badge ${getCourseTypeClass(course.tipo)}">${course.tipo || 'N/A'}</span></td>
<td>${course.alumnos_count || 0}</td>
<td><span class="badge ${course.estado === 'activo' ? 'active' : 'inactive'}">${course.estado || 'N/A'}</span></td>
</tr>
`).join('')}
</tbody>
</table>
</div>`;
}
// 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 = {
nombre: formData.get('nombre'),
descripcion: formData.get('descripcion'),
tipo: formData.get('tipo'),
profesor_id: getProfesorId()
};
fetch('api/cursos.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(jsonData)
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert('Curso creado exitosamente');
showSection('courses'); // Recargar la sección
} else {
alert('Error al crear el curso');
}
})
.catch(error => console.error('Error:', error));
});
}
}
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')
};
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 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();
});
}
}
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 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');
});
}