const API_URL = "https://creditos-api.adrian-camelot32.workers.dev"; // Variables globales para la matriz let globalEstudiantes = []; let globalActividades = []; // Elementos UI const loginForm = document.getElementById('login-form'); const loginSection = document.getElementById('login-section'); const dashboardSection = document.getElementById('dashboard-section'); const loginError = document.getElementById('login-error'); const welcomeMsg = document.getElementById('welcome-msg'); const logoutBtn = document.getElementById('logout-btn'); const adminPanel = document.getElementById('admin-panel'); const tutorPanel = document.getElementById('tutor-panel'); const studentPanel = document.getElementById('student-panel'); const changePasswordPanel = document.getElementById('change-password-panel'); // Elementos Admin & Estudiante const createUserForm = document.getElementById('create-user-form'); const createUserMsg = document.getElementById('create-user-msg'); const adminResetForm = document.getElementById('admin-reset-form'); const userChangePasswordForm = document.getElementById('user-change-password-form'); const creditosObtenidosEl = document.getElementById('creditos-obtenidos'); const creditosMetaEl = document.getElementById('creditos-meta'); // Elementos Tutor const createActivityForm = document.getElementById('create-activity-form'); const setGoalForm = document.getElementById('set-goal-form'); const assignForm = document.getElementById('assign-activity-form'); const gruposBotones = document.getElementById('grupos-botones'); const matrizContainer = document.getElementById('matriz-container'); const matrizHeader = document.getElementById('matriz-header'); const matrizBody = document.getElementById('matriz-body'); const matrizTitulo = document.getElementById('matriz-titulo'); const btnGuardarMatriz = document.getElementById('btn-guardar-matriz'); const matrizMsg = document.getElementById('matriz-msg'); document.addEventListener("DOMContentLoaded", () => { const token = localStorage.getItem('token'); const user = JSON.parse(localStorage.getItem('user')); if (token && user) showDashboard(user); }); document.getElementById('new-role').addEventListener('change', (e) => { const s = document.getElementById('new-grupo'); s.innerHTML = ''; if (e.target.value === 'tutor') s.innerHTML = ``; else if (e.target.value === 'student') s.innerHTML = ``; }); async function loadTutorData(grado) { let grupos = []; if(grado === '4') grupos = ['4A','4B','4C']; if(grado === '5') grupos = ['5A','5B','5C']; if(grado === '6') grupos = ['6A','6B','6C','6D']; document.getElementById('goal-grupo').innerHTML = ''; grupos.forEach(g => document.getElementById('goal-grupo').innerHTML += ``); // Botones de Grupos para la Matriz gruposBotones.innerHTML = ''; grupos.forEach(g => { const btn = document.createElement('button'); btn.textContent = `Lista ${g}`; btn.type = "button"; btn.style.padding = "0.6rem"; btn.style.background = "#17a2b8"; btn.onclick = () => renderMatriz(g); gruposBotones.appendChild(btn); }); try { const resEst = await fetch(`${API_URL}/api/usuarios?grado=${grado}`); globalEstudiantes = await resEst.json(); const estSelect = document.getElementById('assign-student'); estSelect.innerHTML = ''; globalEstudiantes.forEach(est => estSelect.innerHTML += ``); const resAct = await fetch(`${API_URL}/api/actividades`); globalActividades = await resAct.json(); const actSelect = document.getElementById('assign-activity'); actSelect.innerHTML = ''; globalActividades.forEach(act => actSelect.innerHTML += ``); // Si la matriz está abierta, refrescarla if (!matrizContainer.classList.contains('hidden')) { const grupoActual = matrizTitulo.textContent.split(': ')[1]; if(grupoActual) renderMatriz(grupoActual); } } catch(e) { console.error(e); } } // ---------------- LÓGICA DE LA MATRIZ MASIVA ---------------- function renderMatriz(grupo) { matrizContainer.classList.remove('hidden'); matrizTitulo.textContent = `Alumnos del Grupo: ${grupo}`; // Generar Cabeceras (Las Actividades + Checkbox "Seleccionar Todo") matrizHeader.innerHTML = 'Alumno'; globalActividades.forEach(act => { matrizHeader.innerHTML += ` `; }); // Generar Filas (Los Alumnos) matrizBody.innerHTML = ''; const alumnosGrupo = globalEstudiantes.filter(e => e.grupo === grupo); if(alumnosGrupo.length === 0) { matrizBody.innerHTML = `No hay alumnos.`; return; } alumnosGrupo.forEach((alum, index) => { const bg = index % 2 === 0 ? '#fff' : '#f9f9f9'; let tr = ` ${alum.username}`; globalActividades.forEach(act => { tr += ` `; }); tr += ``; matrizBody.innerHTML += tr; }); } // Función mágica para seleccionar/deseleccionar toda una columna window.toggleColumna = function(checkboxCentral, actId) { const checkboxesAlumnos = document.querySelectorAll(`.act-${actId}`); checkboxesAlumnos.forEach(c => c.checked = checkboxCentral.checked); }; // Guardar lo que esté chequeado en la Matriz btnGuardarMatriz.addEventListener('click', async () => { const checked = document.querySelectorAll('.chk-matriz:checked'); if (checked.length === 0) { matrizMsg.textContent = "No has seleccionado ninguna casilla."; matrizMsg.className = "msg error"; return; } matrizMsg.textContent = "Enviando lote de asignaciones..."; matrizMsg.className = "msg"; const asignaciones = Array.from(checked).map(c => ({ student_id: parseInt(c.getAttribute('data-student')), activity_id: parseInt(c.getAttribute('data-activity')) })); try { const res = await fetch(`${API_URL}/api/asignaciones`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ asignaciones }) }); const data = await res.json(); if (!res.ok) throw new Error(data.error || "Error al asignar"); matrizMsg.textContent = `¡Excelente! ${asignaciones.length} créditos asignados a los alumnos.`; matrizMsg.classList.add('success'); // Limpiar todas las casillas tras guardar document.querySelectorAll('input[type="checkbox"]').forEach(c => c.checked = false); setTimeout(() => { matrizMsg.textContent = ""; }, 4000); } catch (error) { matrizMsg.textContent = error.message; matrizMsg.classList.add('error'); } }); // ------------------------------------------------------------- // FORMULARIOS CLÁSICOS RESTANTES loginForm.addEventListener('submit', async (e) => { e.preventDefault(); loginError.textContent = "Conectando..."; try { const res = await fetch(`${API_URL}/api/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: document.getElementById('username').value.trim(), password: document.getElementById('password').value }) }); const data = await res.json(); if (!res.ok) throw new Error(data.error || "Error"); localStorage.setItem('token', data.token); localStorage.setItem('user', JSON.stringify(data.usuario)); showDashboard(data.usuario); loginForm.reset(); loginError.textContent = ""; } catch (error) { loginError.textContent = error.message; } }); createActivityForm.addEventListener('submit', async (e) => { e.preventDefault(); const user = JSON.parse(localStorage.getItem('user')); try { await fetch(`${API_URL}/api/actividades`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ nombre_actividad: document.getElementById('actividad-nombre').value.trim(), creditos: parseInt(document.getElementById('actividad-creditos').value), created_by: user.id }) }); createActivityForm.reset(); loadTutorData(user.grupo); document.getElementById('create-activity-msg').textContent = "¡Actividad registrada!"; setTimeout(() => { document.getElementById('create-activity-msg').textContent = ""; }, 3000); } catch (error) {} }); setGoalForm.addEventListener('submit', async (e) => { e.preventDefault(); const user = JSON.parse(localStorage.getItem('user')); try { await fetch(`${API_URL}/api/metas`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ grupo: document.getElementById('goal-grupo').value, creditos_objetivo: parseInt(document.getElementById('goal-creditos').value), set_by: user.id }) }); setGoalForm.reset(); document.getElementById('set-goal-msg').textContent = "¡Meta fijada!"; setTimeout(() => { document.getElementById('set-goal-msg').textContent = ""; }, 3000); } catch (error) {} }); assignForm.addEventListener('submit', async (e) => { e.preventDefault(); try { await fetch(`${API_URL}/api/asignaciones`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ student_id: document.getElementById('assign-student').value, activity_id: document.getElementById('assign-activity').value }) }); assignForm.reset(); document.getElementById('assign-msg').textContent = "¡Créditos asignados!"; setTimeout(() => { document.getElementById('assign-msg').textContent = ""; }, 3000); } catch (error) {} }); logoutBtn.addEventListener('click', () => { localStorage.clear(); window.location.reload(); }); async function loadStudentData(user) { document.getElementById('student-grupo-info').textContent = `Grupo: ${user.grupo}`; try { const data = await (await fetch(`${API_URL}/api/progreso?student_id=${user.id}&grupo=${user.grupo}`)).json(); creditosObtenidosEl.textContent = data.obtenidos; creditosMetaEl.textContent = data.meta; document.getElementById('progress-bar').style.width = `${Math.min(data.meta > 0 ? (data.obtenidos / data.meta) * 100 : 0, 100)}%`; const list = document.getElementById('historial-lista'); list.innerHTML = ''; if(data.historial.length === 0) list.innerHTML = '
  • No hay actividades registradas.
  • '; else data.historial.forEach(i => list.innerHTML += `
  • ${i.nombre_actividad}+${i.creditos} pts
  • `); } catch(e) {} } function showDashboard(user) { loginSection.classList.add('hidden'); dashboardSection.classList.remove('hidden'); welcomeMsg.textContent = `¡Hola, ${user.username}!`; [adminPanel, tutorPanel, studentPanel, changePasswordPanel].forEach(p => p.classList.add('hidden')); if (user.requires_password_change) changePasswordPanel.classList.remove('hidden'); if (user.role === 'admin') adminPanel.classList.remove('hidden'); else if (user.role === 'tutor') { tutorPanel.classList.remove('hidden'); document.getElementById('tutor-info').textContent = `Titular del Grado ${user.grupo}`; loadTutorData(user.grupo); } else { studentPanel.classList.remove('hidden'); loadStudentData(user); } }