asdadsasd // Variables globales let formEntries = []; let filteredEntries = []; let originalOrder = []; let currentSort = { key: null, asc: true }; let groups = []; let selectedGroup = null; // Funciones de utilidad function showLoading() { document.getElementById('loadingOverlay').style.display = 'flex'; } function hideLoading() { document.getElementById('loadingOverlay').style.display = 'none'; } // Función para traducir el sexo function traducirSexo(sex) { if (!sex || sex === '') return ''; if (sex === 'MAN') return 'Hombre'; if (sex === 'WOMAN') return 'Mujer'; return sex; } // Función para detectar si una entrada es de tipo cabin function isCabinEntry(entry) { // Verificar si el campo accommodation es 'CABIN' return entry.accommodation === 'CABIN'; } // Función para obtener el texto de alojamiento function getAccommodationText(entry) { if (isCabinEntry(entry)) { return 'CABAÑA'; } return entry.accommodation || ''; } // Función para cargar los grupos async function loadGroups() { try { console.log('Loading groups from API...'); const response = await fetch(`${API_ENDPOINT}/groups`); if (!response.ok) { console.error('Error fetching groups:', response.status); return; } groups = await response.json(); console.log('Groups loaded:', groups); // Actualizar el cache if (!window.groupsCache) { window.groupsCache = {}; } groups.forEach(group => { window.groupsCache[group.code] = group.name; }); // Llenar el select de grupos fillGroupFilter(); } catch (error) { console.error('Error loading groups:', error); } } // Función para llenar el filtro de grupos function fillGroupFilter() { const groupFilter = document.getElementById('groupFilter'); if (!groupFilter) return; // Mantener la opción "Todos los grupos" groupFilter.innerHTML = ''; // Agregar la opción "SIN GRUPO" const sinGrupoOption = document.createElement('option'); sinGrupoOption.value = 'SIN_GRUPO'; sinGrupoOption.textContent = 'SIN GRUPO'; groupFilter.appendChild(sinGrupoOption); // Agregar las opciones de grupos groups.forEach(group => { const option = document.createElement('option'); option.value = group.code; option.textContent = group.name; groupFilter.appendChild(option); }); } // Función para mostrar los líderes del grupo seleccionado function showGroupLeaders(groupCode) { const leadersInfo = document.getElementById('leadersInfo'); const leadersList = document.getElementById('leadersList'); if (!leadersInfo || !leadersList) return; if (!groupCode || groupCode === 'SIN_GRUPO') { leadersInfo.classList.remove('show'); return; } const group = groups.find(g => g.code === groupCode); if (!group || !group.leaders || group.leaders.length === 0) { leadersInfo.classList.remove('show'); return; } // Mostrar la información de líderes leadersList.innerHTML = group.leaders.map(leader => `
${leader.name} ${leader.surname}
` ).join(''); leadersInfo.classList.add('show'); } // Función para verificar si un inscrito tiene alojamiento sin pagar function hasUnpaidAccommodation(entry) { console.log('Checking unpaid accommodation for entry:', entry.id); console.log('formEntryProducts:', entry.formEntryProducts); // Excluir entradas de tipo cabin de la detección de deuda if (isCabinEntry(entry)) { console.log('Entry is cabin type, skipping debt detection'); return false; } if (!entry.formEntryProducts || !Array.isArray(entry.formEntryProducts)) { console.log('No formEntryProducts or not an array'); return false; } const hasUnpaid = entry.formEntryProducts.some(product => { console.log('Product:', product); const isAccommodation = product.type === 'ACCOMMODATION'; const isUnpaid = product.paidAmount === 0 || product.paidAmount === null || product.paidAmount === undefined; console.log('Is accommodation:', isAccommodation, 'Is unpaid:', isUnpaid); return isAccommodation && isUnpaid; }); console.log('Has unpaid accommodation:', hasUnpaid); return hasUnpaid; } // Función para obtener el nombre del grupo por código async function getGroupName(groupCode) { console.log('getGroupName called with groupCode:', groupCode); if (!groupCode || groupCode === '') { console.log('Empty groupCode, returning empty string'); return ''; } try { // Cache de grupos para evitar múltiples llamadas if (!window.groupsCache) { window.groupsCache = {}; } // Si ya tenemos el grupo en cache, devolverlo if (window.groupsCache[groupCode]) { console.log('Found in cache:', window.groupsCache[groupCode]); return window.groupsCache[groupCode]; } console.log('Fetching groups from API...'); const response = await fetch(`${API_ENDPOINT}/groups`); if (!response.ok) { console.error('Error fetching groups:', response.status); return ''; } const groups = await response.json(); console.log('Groups received:', groups); // Guardar todos los grupos en cache groups.forEach(group => { window.groupsCache[group.code] = group.name; }); const result = window.groupsCache[groupCode] || ''; console.log('Final result for', groupCode, ':', result); return result; } catch (error) { console.error('Error fetching group name:', error); return ''; } } // Función para formatear fechas function formatDate(dateString) { if (!dateString) return ''; try { return new Date(dateString).toLocaleString('es-ES'); } catch (e) { return dateString; } } // Función para quitar tildes/acentos function quitarTildes(str) { return (str || '').normalize('NFD').replace(/[ \u0301\u0308]/g, '').replace(/[\u00f1\u00d1]/g, 'n').replace(/\u00f1/g, 'n').replace(/\u00d1/g, 'N'); } // Función para cargar los datos async function fetchFormEntries() { console.log('fetchFormEntries() llamado'); if (typeof API_ENDPOINT === 'undefined') { console.error('API_ENDPOINT no está definido'); const container = document.getElementById('tableContainer'); if (container) { container.innerHTML = '
Error: No se pudo cargar la configuración de la API.
'; } return; } // Obtener el formId de los parámetros de la URL const params = new URLSearchParams(window.location.search); const formId = params.get('formId'); if (!formId) { const container = document.getElementById('tableContainer'); if (container) { container.innerHTML = '
Error: No se especificó el ID del formulario.
'; } return; } showLoading(); console.log('Iniciando fetch a la API...'); console.log('URL completa:', `${API_ENDPOINT}/form-entries/all-active?formId=${formId}`); try { const res = await fetch(`${API_ENDPOINT}/form-entries/all-active?formId=${formId}`); console.log('Respuesta recibida, status:', res.status); if (!res.ok) { throw new Error(`HTTP error! status: ${res.status}`); } const data = await res.json(); console.log('Datos procesados, registros:', data.length); console.log('Primeros 3 registros:', data.slice(0, 3)); // Verificar si los datos incluyen formEntryProducts if (data.length > 0) { console.log('Estructura del primer registro:', Object.keys(data[0])); if (data[0].formEntryProducts) { console.log('formEntryProducts del primer registro:', data[0].formEntryProducts); } else { console.log('No se encontró formEntryProducts en los datos'); } } formEntries = data; filteredEntries = data; originalOrder = [...data]; // Cargar grupos después de cargar los datos await loadGroups(); updateStats(); await renderTable(); } catch (error) { console.error('Error en la petición:', error); console.error('Stack trace:', error.stack); const container = document.getElementById('tableContainer'); if (container) { container.innerHTML = `
No se pudieron cargar los datos.
Error: ${error.message}
`; } } finally { hideLoading(); } } // Función para actualizar estadísticas function updateStats() { const count = document.getElementById('count'); const countLabel = document.getElementById('countLabel'); if (count) { count.textContent = filteredEntries.length; } if (countLabel) { // Verificar si hay filtros activos const searchInput = document.getElementById('searchInput'); const groupFilter = document.getElementById('groupFilter'); const hasSearch = searchInput && searchInput.value.trim() !== ''; const hasGroupFilter = groupFilter && groupFilter.value !== ''; if (hasSearch || hasGroupFilter) { countLabel.textContent = 'Filtrados'; } else { countLabel.textContent = 'Total'; } } } // Función para renderizar la tabla async function renderTable() { console.log('renderTable() llamado'); console.log('filteredEntries:', filteredEntries); console.log('filteredEntries.length:', filteredEntries ? filteredEntries.length : 'undefined'); const container = document.getElementById('tableContainer'); if (!filteredEntries.length) { if (container) { container.innerHTML = '
No hay inscripciones.
'; } return; } const columns = [ { key: 'name', label: 'Nombre' }, { key: 'surname', label: 'Apellidos' }, { key: 'age', label: 'Edad' }, { key: 'sex', label: 'Sexo' }, { key: 'city', label: 'Ciudad' }, { key: 'group', label: 'Grupo' }, { key: 'church', label: 'Iglesia' }, { key: 'accommodation', label: 'Alojamiento' }, { key: 'daysEvent', label: 'Días' }, { key: 'busTrip', label: 'Bus' }, { key: 'createdAt', label: 'Fecha' } ]; let thead = '' + columns.map(function(col) { let arrows = `▲▼`; if (currentSort.key === col.key) { arrows = `${currentSort.asc ? '▲' : '▼'}`; } let thStyle = ''; if (col.key === 'name') thStyle = ""; if (col.key === 'surname') thStyle = " style='max-width:140px;min-width:140px;width:140px;'"; if (col.key === 'age') thStyle = " style='max-width:60px;min-width:60px;width:60px;'"; if (col.key === 'sex') thStyle = " style='max-width:80px;min-width:80px;width:80px;'"; if (col.key === 'church') thStyle = " style='max-width:80px;min-width:60px;width:80px;'"; if (col.key === 'city') thStyle = " style='max-width:107px;min-width:107px;width:107px;'"; if (col.key === 'group') thStyle = " style='max-width:120px;min-width:120px;width:120px;'"; if (col.key === 'createdAt') thStyle = " style='max-width:100px;min-width:100px;width:100px;'"; return `${col.label} ${arrows}`; }).join('') + ''; const tbodyRows = await Promise.all(filteredEntries.map(async function(entry) { // Formatear días SOLO para la tabla let diasLabelTabla = ''; if (entry.daysEvent === 'ALL_DAYS') diasLabelTabla = 'Todos los Días'; else if (entry.daysEvent === 'SINGLE_DAYS') diasLabelTabla = 'Días sueltos'; else diasLabelTabla = entry.daysEvent || ''; // Obtener el nombre del grupo console.log('Entry groupname:', entry.groupname, 'groupName:', entry.groupName, 'group_name:', entry.group_name); const groupCode = entry.groupname || entry.groupName || entry.group_name || ''; const groupName = await getGroupName(groupCode); // Verificar si tiene alojamiento sin pagar y si es de tipo cabin const hasUnpaid = hasUnpaidAccommodation(entry); const isCabin = isCabinEntry(entry); let rowClass = ''; if (isCabin) { rowClass = 'cabin-entry'; } else if (hasUnpaid) { rowClass = 'unpaid-accommodation'; } console.log('Entry ID:', entry.id, 'Has unpaid:', hasUnpaid, 'Is cabin:', isCabin, 'Row class:', rowClass); return `
${entry.name||''} ${entry.phone ? ` ${entry.phone} ` : ''}
${entry.surname||''} ${entry.age !== undefined ? entry.age : ''} ${traducirSexo(entry.sex)} ${entry.city||''} ${groupName} ${entry.church === 'OTRA_IGLESIA' ? (entry.otherchurch || entry.otherChurch || '') : (entry.church || '')} ${getAccommodationText(entry)} ${diasLabelTabla} ${entry.busTrip ? 'Sí' : 'No'} ${entry.createdAt ? formatDate(entry.createdAt) : ''} `; })); let tbody = '' + tbodyRows.join('') + ''; if (container) { container.innerHTML = `${thead}${tbody}
`; } } // Función para ordenar la tabla async function sortTable(key) { if (currentSort.key === key) { if (currentSort.asc) { currentSort.asc = false; } else { // Reset: volver al orden original pero manteniendo los filtros currentSort.key = null; currentSort.asc = true; // Aplicar filtros y búsqueda para mantener el filtrado await applyFiltersAndSearch(); return; } } else { currentSort.key = key; currentSort.asc = true; } filteredEntries.sort((a, b) => { let aValue = a[key]; let bValue = b[key]; if (key === 'church') { aValue = a.church === 'OTRA_IGLESIA' ? (a.otherchurch || a.otherChurch || '') : (a.church || ''); bValue = b.church === 'OTRA_IGLESIA' ? (b.otherchurch || b.otherChurch || '') : (b.church || ''); } else if (key === 'group') { // Para grupos, usar el nombre del grupo const groupCodeA = a.groupname || a.groupName || a.group_name || ''; const groupCodeB = b.groupname || b.groupName || b.group_name || ''; aValue = window.groupsCache && window.groupsCache[groupCodeA] ? window.groupsCache[groupCodeA] : groupCodeA; bValue = window.groupsCache && window.groupsCache[groupCodeB] ? window.groupsCache[groupCodeB] : groupCodeB; } else if (key === 'sex') { // Para sexo, usar el valor traducido para ordenación aValue = traducirSexo(a.sex); bValue = traducirSexo(b.sex); } else if (key === 'createdAt') { // Para fechas, convertir a Date para comparación correcta aValue = a.createdAt ? new Date(a.createdAt) : new Date(0); bValue = b.createdAt ? new Date(b.createdAt) : new Date(0); } if (aValue == null) return 1; if (bValue == null) return -1; if (typeof aValue === 'string') { return currentSort.asc ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue); } return currentSort.asc ? aValue - bValue : bValue - aValue; }); await renderTable(); } // Función para aplicar filtros y búsqueda async function applyFiltersAndSearch() { if (!formEntries) { console.log('formEntries aún no está disponible, saltando filtrado'); return; } const searchInput = document.getElementById('searchInput'); const groupFilter = document.getElementById('groupFilter'); const qRaw = searchInput ? searchInput.value : ''; const q = quitarTildes(qRaw).toLowerCase(); const selectedGroupCode = groupFilter ? groupFilter.value : ''; // Actualizar el grupo seleccionado selectedGroup = selectedGroupCode; // Mostrar/ocultar líderes según el grupo seleccionado showGroupLeaders(selectedGroupCode); filteredEntries = formEntries.filter(e => { // Filtrar por grupo si está seleccionado if (selectedGroupCode) { const entryGroupCode = e.groupname || e.groupName || e.group_name || ''; if (selectedGroupCode === 'SIN_GRUPO') { // Para "SIN GRUPO", mostrar entradas con groupName null, vacío o undefined if (entryGroupCode && entryGroupCode.trim() !== '') { return false; } } else { // Para grupos específicos, verificar que coincida if (entryGroupCode !== selectedGroupCode) { return false; } } } // Si no hay término de búsqueda, mostrar todos los del grupo seleccionado if (!q) { return true; } // Buscar por todos los campos editables const fields = [ e.id, e.name, e.surname, e.email, e.dni, e.phone, e.city, e.church, e.otherchurch, e.otherChurch, e.accommodation, e.age, // Buscar por sexo traducirSexo(e.sex), // Buscar por grupo (código y nombre si está en cache) e.groupname || e.groupName || e.group_name || '', // Buscar por nombre del grupo si está en cache (window.groupsCache && (e.groupname || e.groupName || e.group_name)) ? (window.groupsCache[e.groupname || e.groupName || e.group_name] || '') : '', // Buscar por días (permitiendo términos amigables) (e.daysEvent === 'ALL_DAYS' ? 'todos los dias' : e.daysEvent === 'SINGLE_DAYS' ? 'dias sueltos' : e.daysEvent), // Buscar por nombre completo (nombre + apellidos) `${e.name || ''} ${e.surname || ''}`.trim(), // Buscar por apellidos + nombre (orden inverso) `${e.surname || ''} ${e.name || ''}`.trim(), // Buscar por tipo de alojamiento (incluyendo CABAÑA) getAccommodationText(e) ]; const matchSearch = fields.some(f => quitarTildes((f||'').toString()).toLowerCase().includes(q)); return matchSearch; }); // Aplicar ordenación si existe if (currentSort && currentSort.key) { filteredEntries.sort((a, b) => { let aValue = a[currentSort.key]; let bValue = b[currentSort.key]; if (currentSort.key === 'church') { aValue = a.church === 'OTRA_IGLESIA' ? (a.otherchurch || a.otherChurch || '') : (a.church || ''); bValue = b.church === 'OTRA_IGLESIA' ? (b.otherchurch || b.otherChurch || '') : (b.church || ''); } else if (currentSort.key === 'group') { // Para grupos, usar el nombre del grupo const groupCodeA = a.groupname || a.groupName || a.group_name || ''; const groupCodeB = b.groupname || b.groupName || b.group_name || ''; aValue = window.groupsCache && window.groupsCache[groupCodeA] ? window.groupsCache[groupCodeA] : groupCodeA; bValue = window.groupsCache && window.groupsCache[groupCodeB] ? window.groupsCache[groupCodeB] : groupCodeB; } else if (currentSort.key === 'createdAt') { aValue = a.createdAt ? new Date(a.createdAt) : new Date(0); bValue = b.createdAt ? new Date(b.createdAt) : new Date(0); } if (aValue == null) return 1; if (bValue == null) return -1; if (typeof aValue === 'string') { return currentSort.asc ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue); } return currentSort.asc ? aValue - bValue : bValue - aValue; }); } else { // Si no hay ordenación, mantener el orden original de los datos filtrados // Esto es importante para que el reset funcione correctamente const originalOrderIds = originalOrder.map(item => item.id); filteredEntries.sort((a, b) => { const aIndex = originalOrderIds.indexOf(a.id); const bIndex = originalOrderIds.indexOf(b.id); return aIndex - bIndex; }); } updateStats(); await renderTable(); } // Función para refrescar datos function refreshData() { // Limpiar el input de búsqueda const searchInput = document.getElementById('searchInput'); if (searchInput) searchInput.value = ''; // Limpiar el filtro de grupos const groupFilter = document.getElementById('groupFilter'); if (groupFilter) groupFilter.value = ''; // Recargar los datos fetchFormEntries(); // Mostrar notificación de éxito Swal.fire({ icon: 'success', title: 'Datos actualizados', text: 'Los datos han sido recargados correctamente.', timer: 1500, showConfirmButton: false, toast: true, position: 'top-end' }); } // Event listeners document.addEventListener('DOMContentLoaded', function() { console.log('DOM cargado, iniciando aplicación...'); // Configurar event listener para búsqueda const searchInput = document.getElementById('searchInput'); if (searchInput) { searchInput.addEventListener('input', function() { applyFiltersAndSearch(); }); } // Configurar event listener para filtro de grupos const groupFilter = document.getElementById('groupFilter'); if (groupFilter) { groupFilter.addEventListener('change', function() { applyFiltersAndSearch(); }); } // Cargar datos iniciales fetchFormEntries(); }); // Exponer funciones globalmente window.sortTable = sortTable; window.refreshData = refreshData;