const express = require('express'); const router = express.Router(); const { requireAuth } = require('../middlewares/authMiddleware'); router.use(requireAuth); router.get('/', async (req, res) => { const actual_role = (req.user?.role || 'admin').toLowerCase(); const roleParam = (req.query.role || req.query.view_as || '').toLowerCase().trim(); const role = (['admin', 'bedelia', 'docente', 'alumno'].includes(roleParam) ? roleParam : actual_role) || 'admin'; let apiData = {}; let backendStats = {}; let audit_logs = []; let monthly_data = []; try { const response = await req.apiClient.get('/dashboard/stats'); apiData = response.data || {}; backendStats = apiData.stats || {}; audit_logs = apiData.audit_logs || []; monthly_data = apiData.monthly_data || []; } catch (error) { console.warn('Dashboard stats API notice:', error.message); } if (!monthly_data || monthly_data.length === 0) { monthly_data = [ { month: 'Ene', reservations: 120 }, { month: 'Feb', reservations: 180 }, { month: 'Mar', reservations: 250 }, { month: 'Abr', reservations: 220 }, { month: 'May', reservations: 300 }, { month: 'Jun', reservations: 310 }, { month: 'Jul', reservations: 200 }, { month: 'Ago', reservations: 350 }, { month: 'Sep', reservations: 420 }, { month: 'Oct', reservations: 480 }, { month: 'Nov', reservations: 520 }, { month: 'Dic', reservations: 210 } ]; } const total_classrooms = backendStats.total_classrooms ?? 31; const total_subjects = backendStats.active_subjects ?? backendStats.total_subjects ?? 12; const total_users = backendStats.total_active_users ?? backendStats.total_users ?? 8; const today_reservations = backendStats.today_reservations ?? 19; const pending_count = backendStats.pending_count ?? 3; const physical_classrooms = backendStats.physical_classrooms ?? Math.max(1, total_classrooms - 4); const virtual_classrooms_count = backendStats.virtual_classrooms ?? 4; const occupancy_rate = backendStats.occupancy_rate ?? 68; const assigned_classrooms = backendStats.assigned_classrooms ?? 26; const assigned_classrooms_pct = backendStats.assigned_classrooms_pct ?? 96.3; const unassigned_classrooms = backendStats.unassigned_classrooms ?? 1; const unassigned_classrooms_pct = backendStats.unassigned_classrooms_pct ?? 3.7; const assigned_today_classrooms = backendStats.assigned_today_classrooms ?? 0; const assigned_today_pct = backendStats.assigned_today_pct ?? 0; const unassigned_today_classrooms = backendStats.unassigned_today_classrooms ?? physical_classrooms; const unassigned_today_pct = backendStats.unassigned_today_pct ?? 100; const apiPending = Array.isArray(apiData.pending_reservations) && apiData.pending_reservations.length > 0 ? apiData.pending_reservations : null; const apiTodaySchedule = Array.isArray(apiData.today_schedule_list) && apiData.today_schedule_list.length > 0 ? apiData.today_schedule_list : null; const apiUpcoming = Array.isArray(apiData.upcoming_reservations) && apiData.upcoming_reservations.length > 0 ? apiData.upcoming_reservations : null; const apiMilestones = Array.isArray(apiData.milestones) && apiData.milestones.length > 0 ? apiData.milestones : null; // Consolidated and role-specific stats const stats = { total_classrooms, total_subjects, total_users, today_reservations, pending_count: apiPending ? apiPending.length : pending_count, physical_classrooms, virtual_classrooms: virtual_classrooms_count, occupancy_rate, assigned_classrooms, assigned_classrooms_pct, unassigned_classrooms, unassigned_classrooms_pct, assigned_today_classrooms, assigned_today_pct, unassigned_today_classrooms, unassigned_today_pct, my_today_count: apiTodaySchedule ? Math.min(3, apiTodaySchedule.length) : 2, my_total_reservations: 8, virtual_rooms_count: virtual_classrooms_count, today_classes_count: apiTodaySchedule ? Math.min(4, apiTodaySchedule.length) : 2, milestones_count: apiMilestones ? apiMilestones.length : 3 }; let role_data = {}; if (role === 'admin') { role_data = { recent_audits: audit_logs.length > 0 ? audit_logs : [ { created_at: '2026-09-18 21:15', action_type: 'UPDATE_PERMISSION', user_email: 'admin@edu-space.com', ip_address: '127.0.0.1' }, { created_at: '2026-09-18 20:30', action_type: 'CREATE_COMMISSION', user_email: 'admin@edu-space.com', ip_address: '127.0.0.1' }, { created_at: '2026-09-18 19:45', action_type: 'LOGIN_SUCCESS', user_email: 'admin@edu-space.com', ip_address: '127.0.0.1' } ] }; } else if (role === 'bedelia') { role_data = { pending_reservations: apiPending || [ { id: 101, start_time: '08:00', end_time: '12:00', classroom: { code: 'Aula 101' }, subject_name: 'Arquitectura de Computadoras', user: { name: 'Prof. Gabriel Martínez' } }, { id: 102, start_time: '14:00', end_time: '18:00', classroom: { code: 'Lab Informática 2' }, subject_name: 'Bases de Datos II', user: { name: 'Dra. Laura Blanco' } }, { id: 103, start_time: '18:30', end_time: '22:00', classroom: { code: 'Aula Magna' }, subject_name: 'Seminario de Ciberseguridad', user: { name: 'Lic. Fernando Gómez' } } ], today_schedule_list: apiTodaySchedule || [ { start_time: '08:00', end_time: '12:00', classroom: { code: 'Aula 102' }, subject_name: 'Algoritmos y Estructuras de Datos', user: { name: 'Prof. Ana Vega' } }, { start_time: '08:30', end_time: '12:30', classroom: { code: 'Aula 204' }, subject_name: 'Matemática Discreta', user: { name: 'Prof. Carlos López' } }, { start_time: '14:00', end_time: '18:00', classroom: { code: 'Lab Redes' }, subject_name: 'Redes y Telecomunicaciones', user: { name: 'Ing. Marcos Ruiz' } } ] }; } else if (role === 'docente') { const myClasses = apiTodaySchedule ? apiTodaySchedule.slice(0, 3) : null; role_data = { my_today_classes: myClasses || [ { id: 201, start_time: '08:30', end_time: '12:00', subject_name: 'Algoritmos y Estructuras de Datos', subject_code: 'AED-102', commission: { code: 'COM-A' }, classroom: { is_virtual: false, location_display: 'Piso 1 · Aula 104' }, virtual_link: '' }, { id: 202, start_time: '18:30', end_time: '22:00', subject_name: 'Programación Concurrente y Distribuida', subject_code: 'PCD-301', commission: { code: 'COM-D' }, classroom: { is_virtual: true, location_display: 'Campus Virtual' }, virtual_link: 'https://meet.google.com/edu-space-pcd' } ], virtual_classrooms: [ { code: 'Sala Virtual 1', link: 'https://meet.google.com/edu-space-v1' }, { code: 'Sala Virtual 2', link: 'https://meet.google.com/edu-space-v2' } ] }; } else if (role === 'alumno') { const studentClasses = apiTodaySchedule ? apiTodaySchedule.slice(0, 4) : null; role_data = { today_classes: studentClasses || [ { start_time: '08:00', end_time: '12:00', subject_name: 'Bases de Datos Relacionales', subject_code: 'BDR-201', commission: { code: 'COM-1' }, classroom: { is_virtual: false, location_display: 'Piso 2 · Laboratorio 3' }, virtual_link: '' }, { start_time: '18:30', end_time: '22:30', subject_name: 'Redes y Telecomunicaciones', subject_code: 'RYT-302', commission: { code: 'COM-2' }, classroom: { is_virtual: true, location_display: 'Campus Virtual (Google Meet)' }, virtual_link: 'https://meet.google.com/edu-space-demo' } ], upcoming_milestones: apiMilestones ? apiMilestones.map(m => ({ ...m, milestone_type: m.type_obj })) : [ { title: 'Primer Examen Parcial', materia_codigo: 'BDR-201', subject_name: 'Bases de Datos Relacionales', date: '25/09/2026', type_obj: { name: 'Examen Parcial', color: '#dc3545' }, milestone_type: { name: 'Examen Parcial', color: '#dc3545' }, notes: 'Traer DNI y calculadora', classroom: 'Piso 2 · Aula 204' }, { title: 'Entrega TP Grupal Nº 2', materia_codigo: 'AED-102', subject_name: 'Algoritmos y Estructuras de Datos', date: '30/09/2026', type_obj: { name: 'Trabajo Práctico', color: '#198754' }, milestone_type: { name: 'Trabajo Práctico', color: '#198754' }, notes: 'Subir código al repositorio', classroom: 'Campus Virtual', link: 'https://campus.edu-space.com/tps' }, { title: 'Recuperatorio Parcial 1', materia_codigo: 'RYT-302', subject_name: 'Redes y Telecomunicaciones', date: '08/10/2026', type_obj: { name: 'Recuperatorio', color: '#fd7e14' }, milestone_type: { name: 'Recuperatorio', color: '#fd7e14' }, notes: 'Piso 2 · Aula 204', classroom: 'Piso 2 · Aula 204' } ] }; } const upcoming_reservations = apiUpcoming || [ { start_time: '08:00', end_time: '12:00', date_display: '22/09', subject_name: 'Matemática Discreta', subject_code: 'MAT-101', shift: 'Mañana', commission: { code: 'COM-1' }, status: 'CONFIRMED', classroom: { code: 'Aula 101' }, user: { name: 'Prof. Carlos López' } }, { start_time: '14:00', end_time: '18:00', date_display: '23/09', subject_name: 'Sistemas Operativos', subject_code: 'SO-202', shift: 'Tarde', commission: { code: 'COM-2' }, status: 'CONFIRMED', classroom: { code: 'Lab 2' }, user: { name: 'Dra. Ana Vega' } }, { start_time: '18:30', end_time: '22:30', date_display: '24/09', subject_name: 'Ingeniería de Software', subject_code: 'IS-301', shift: 'Noche', commission: { code: 'COM-3' }, status: 'PENDING', classroom: { code: 'Aula Magna' }, user: { name: 'Ing. Marcos Ruiz' } } ]; res.render('dashboard', { title: role === 'bedelia' ? 'Panel Operativo de Bedelía - Edu-Space Admin' : role === 'docente' ? 'Panel Docente - Edu-Space Admin' : role === 'alumno' ? 'Mi Portal de Cursada - Edu-Space Admin' : 'Panel de Administración - Edu-Space Admin', user: req.user, role, actual_role, stats, role_data, monthly_data, audit_logs, upcoming_reservations }); }); module.exports = router;