let currentUser = null; let currentDataType = null; let currentData = []; // Beim Laden der Seite document.addEventListener('DOMContentLoaded', function() { checkAuth(); loadStatistics(); loadPageStatistics(); setupEventListeners(); }); function setupEventListeners() { // Logout Button document.getElementById('logoutBtn').addEventListener('click', logout); // Generator Button document.getElementById('generatorBtn').addEventListener('click', function() { window.location.href = '/generator'; }); // Modal Close Buttons document.querySelectorAll('.close').forEach(closeBtn => { closeBtn.addEventListener('click', closeModal); }); // Confirm Modal Buttons document.getElementById('confirmNo').addEventListener('click', closeModal); // Search Input document.getElementById('searchInput').addEventListener('input', filterData); // Add Form document.getElementById('addForm').addEventListener('submit', handleAddSubmit); } async function checkAuth() { try { const response = await fetch('/api/check-session'); const result = await response.json(); if (!result.success) { window.location.href = '/adminlogin.html'; return; } currentUser = result.user; document.getElementById('username').textContent = currentUser.username; const accessBadge = document.getElementById('accessBadge'); accessBadge.textContent = `Level ${currentUser.access_level}`; accessBadge.className = `access-badge level-${currentUser.access_level}`; // Generator-Button nur fĂŒr Level 2 if (currentUser.access_level >= 2) { document.getElementById('generatorBtn').style.display = 'inline-block'; } } catch (error) { console.error('Auth check failed:', error); window.location.href = '/adminlogin.html'; } } async function logout() { try { await fetch('/api/logout', { method: 'POST' }); window.location.href = '/adminlogin.html'; } catch (error) { console.error('Logout failed:', error); window.location.href = '/adminlogin.html'; } } async function loadStatistics() { try { const response = await fetch('/api/admin-stats'); const stats = await response.json(); if (stats.success) { document.getElementById('totalPlayers').textContent = stats.data.players || 0; document.getElementById('totalRuns').textContent = stats.data.runs || 0; document.getElementById('totalLocations').textContent = stats.data.locations || 0; document.getElementById('totalAdminUsers').textContent = stats.data.adminUsers || 0; } } catch (error) { console.error('Failed to load statistics:', error); } } async function loadPageStatistics() { try { const response = await fetch('/api/admin-page-stats'); const result = await response.json(); if (result.success) { const data = result.data; // Display page view statistics displayPageStats('todayStats', data.today); displayPageStats('weekStats', data.week); displayPageStats('monthStats', data.month); displayPageStats('totalStats', data.total); // Display link statistics if (data.linkStats) { document.getElementById('totalPlayersCount').textContent = data.linkStats.total_players || 0; document.getElementById('linkedPlayersCount').textContent = data.linkStats.linked_players || 0; document.getElementById('linkPercentage').textContent = `${data.linkStats.link_percentage || 0}%`; } } } catch (error) { console.error('Failed to load page statistics:', error); // Show error in all stat containers ['todayStats', 'weekStats', 'monthStats', 'totalStats'].forEach(id => { document.getElementById(id).innerHTML = '
Fehler beim Laden
'; }); } } function displayPageStats(containerId, stats) { const container = document.getElementById(containerId); if (!stats || stats.length === 0) { container.innerHTML = '
0
'; return; } // Find main page visits const mainPageStat = stats.find(stat => stat.page === 'main_page_visit'); const count = mainPageStat ? mainPageStat.count : 0; container.innerHTML = `
${count}
`; } function getPageDisplayName(page) { const pageNames = { 'main_page_visit': '🏠 Hauptseiten-Besuche', 'home': '🏠 Hauptseite', 'login': '🔐 Login', 'dashboard': '📊 Dashboard', 'admin_login': 'đŸ›Ąïž Admin Login', 'admin_dashboard': 'đŸ›Ąïž Admin Dashboard', 'license_generator': '🔧 Lizenzgenerator', 'reset_password': '🔑 Passwort Reset' }; return pageNames[page] || page; } function showUserManagement() { showDataSection('users', 'Benutzer-Verwaltung'); loadUsers(); } function showPlayerManagement() { showDataSection('players', 'Spieler-Verwaltung'); loadPlayers(); } function showRunManagement() { showDataSection('runs', 'LĂ€ufe-Verwaltung'); loadRuns(); } function showLocationManagement() { showDataSection('locations', 'Standort-Verwaltung'); loadLocations(); } function showAdminUserManagement() { showDataSection('adminusers', 'Admin-Benutzer'); loadAdminUsers(); } function showSystemInfo() { showDataSection('system', 'System-Informationen'); loadSystemInfo(); } function showDataSection(type, title) { currentDataType = type; document.getElementById('dataTitle').textContent = title; document.getElementById('dataSection').style.display = 'block'; document.getElementById('searchInput').value = ''; } async function loadUsers() { // Implementation fĂŒr Supabase-Benutzer document.getElementById('dataContent').innerHTML = '
Supabase-Benutzer werden ĂŒber die Supabase-Console verwaltet
'; } async function loadPlayers() { try { const response = await fetch('/api/admin-players'); const result = await response.json(); if (result.success) { currentData = result.data; displayPlayersTable(result.data); } else { showError('Fehler beim Laden der Spieler'); } } catch (error) { console.error('Failed to load players:', error); showError('Fehler beim Laden der Spieler'); } } async function loadRuns() { try { const response = await fetch('/api/admin-runs'); const result = await response.json(); if (result.success) { currentData = result.data; displayRunsTable(result.data); } else { showError('Fehler beim Laden der LĂ€ufe'); } } catch (error) { console.error('Failed to load runs:', error); showError('Fehler beim Laden der LĂ€ufe'); } } async function loadLocations() { try { const response = await fetch('/api/admin-locations'); const result = await response.json(); if (result.success) { currentData = result.data; displayLocationsTable(result.data); } else { showError('Fehler beim Laden der Standorte'); } } catch (error) { console.error('Failed to load locations:', error); showError('Fehler beim Laden der Standorte'); } } async function loadAdminUsers() { try { const response = await fetch('/api/admin-adminusers'); const result = await response.json(); if (result.success) { currentData = result.data; displayAdminUsersTable(result.data); } else { showError('Fehler beim Laden der Admin-Benutzer'); } } catch (error) { console.error('Failed to load admin users:', error); showError('Fehler beim Laden der Admin-Benutzer'); } } function displayPlayersTable(players) { let html = '
'; html += ''; players.forEach(player => { html += ``; }); html += '
IDNameRFID UIDSupabase UserRegistriertAktionen
${player.id} ${player.full_name || '-'} ${player.rfiduid || '-'} ${player.supabase_user_id ? '✅' : '❌'} ${new Date(player.created_at).toLocaleDateString('de-DE')}
'; document.getElementById('dataContent').innerHTML = html; } function displayRunsTable(runs) { let html = '
'; html += ''; runs.forEach(run => { // Use the time_seconds value from the backend const timeInSeconds = parseFloat(run.time_seconds) || 0; html += ``; }); html += '
IDSpielerStandortZeitDatumAktionen
${run.id} ${run.player_name || `Player ${run.player_id}`} ${run.location_name || `Location ${run.location_id}`} ${timeInSeconds.toFixed(3)}s ${new Date(run.created_at).toLocaleDateString('de-DE')} ${new Date(run.created_at).toLocaleTimeString('de-DE')}
'; document.getElementById('dataContent').innerHTML = html; } function displayLocationsTable(locations) { let html = '
'; html += ''; locations.forEach(location => { html += ``; }); html += '
IDNameLatitudeLongitudeErstelltAktionen
${location.id} ${location.name} ${location.latitude} ${location.longitude} ${new Date(location.created_at).toLocaleDateString('de-DE')}
'; document.getElementById('dataContent').innerHTML = html; } function displayAdminUsersTable(users) { let html = '
'; html += ''; users.forEach(user => { const isCurrentUser = user.id === currentUser.id; html += ``; }); html += '
IDBenutzernameAccess LevelAktivLetzter LoginAktionen
${user.id} ${user.username} ${isCurrentUser ? '(Du)' : ''} Level ${user.access_level} ${user.is_active ? '✅' : '❌'} ${user.last_login ? new Date(user.last_login).toLocaleDateString('de-DE') : 'Nie'} ${!isCurrentUser ? `` : ''}
'; document.getElementById('dataContent').innerHTML = html; } function loadSystemInfo() { document.getElementById('dataContent').innerHTML = `

Server-Informationen

Node.js Version: ${navigator.userAgent}

Aktuelle Zeit: ${new Date().toLocaleString('de-DE')}

Angemeldeter Benutzer: ${currentUser.username} (Level ${currentUser.access_level})

`; } function filterData() { const searchTerm = document.getElementById('searchInput').value.toLowerCase(); if (!currentData) return; let filteredData = currentData.filter(item => { return Object.values(item).some(value => value && value.toString().toLowerCase().includes(searchTerm) ); }); switch(currentDataType) { case 'players': displayPlayersTable(filteredData); break; case 'runs': displayRunsTable(filteredData); break; case 'locations': displayLocationsTable(filteredData); break; case 'adminusers': displayAdminUsersTable(filteredData); break; } } function refreshData() { switch(currentDataType) { case 'players': loadPlayers(); break; case 'runs': loadRuns(); break; case 'locations': loadLocations(); break; case 'adminusers': loadAdminUsers(); break; case 'system': loadSystemInfo(); break; } } function showAddModal() { const modal = document.getElementById('addModal'); const modalTitle = document.getElementById('modalTitle'); const formFields = document.getElementById('formFields'); // Modal-Titel basierend auf aktuellem Datentyp setzen switch(currentDataType) { case 'players': modalTitle.textContent = 'Neuen Spieler hinzufĂŒgen'; formFields.innerHTML = `
`; break; case 'locations': modalTitle.textContent = 'Neuen Standort hinzufĂŒgen'; formFields.innerHTML = `
`; break; case 'adminusers': modalTitle.textContent = 'Neuen Admin-Benutzer hinzufĂŒgen'; formFields.innerHTML = `
`; break; case 'runs': modalTitle.textContent = 'Neuen Lauf hinzufĂŒgen'; formFields.innerHTML = `
`; break; default: modalTitle.textContent = 'Element hinzufĂŒgen'; formFields.innerHTML = '

Keine Felder fĂŒr diesen Datentyp verfĂŒgbar.

'; } modal.style.display = 'block'; } function closeModal() { document.querySelectorAll('.modal').forEach(modal => { modal.style.display = 'none'; }); // Formular zurĂŒcksetzen document.getElementById('addForm').reset(); document.getElementById('modalMessage').style.display = 'none'; } async function handleAddSubmit(e) { e.preventDefault(); const formData = new FormData(e.target); const data = Object.fromEntries(formData.entries()); // PrĂŒfen ob es sich um eine Edit-Operation handelt const isEdit = data.edit_id; const editId = data.edit_id; delete data.edit_id; // edit_id aus den Daten entfernen try { let endpoint = ''; let successMessage = ''; let method = 'POST'; switch(currentDataType) { case 'players': endpoint = isEdit ? `/api/admin-players/${editId}` : '/api/admin-players'; successMessage = isEdit ? 'Spieler erfolgreich aktualisiert' : 'Spieler erfolgreich hinzugefĂŒgt'; method = isEdit ? 'PUT' : 'POST'; break; case 'locations': endpoint = isEdit ? `/api/admin-locations/${editId}` : '/api/admin-locations'; successMessage = isEdit ? 'Standort erfolgreich aktualisiert' : 'Standort erfolgreich hinzugefĂŒgt'; method = isEdit ? 'PUT' : 'POST'; break; case 'adminusers': endpoint = isEdit ? `/api/admin-adminusers/${editId}` : '/api/admin-adminusers'; successMessage = isEdit ? 'Admin-Benutzer erfolgreich aktualisiert' : 'Admin-Benutzer erfolgreich hinzugefĂŒgt'; method = isEdit ? 'PUT' : 'POST'; break; case 'runs': endpoint = isEdit ? `/api/admin-runs/${editId}` : '/api/admin-runs'; successMessage = isEdit ? 'Lauf erfolgreich aktualisiert' : 'Lauf erfolgreich hinzugefĂŒgt'; method = isEdit ? 'PUT' : 'POST'; break; default: showError('Unbekannter Datentyp'); return; } const response = await fetch(endpoint, { method: method, headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(data) }); const result = await response.json(); if (result.success) { showSuccess(successMessage); closeModal(); refreshData(); // Daten neu laden } else { showError(result.message || `Fehler beim ${isEdit ? 'Aktualisieren' : 'HinzufĂŒgen'}`); } } catch (error) { console.error('Submit failed:', error); showError(`Fehler beim ${isEdit ? 'Aktualisieren' : 'HinzufĂŒgen'}`); } } // Edit-Funktionen async function editPlayer(id) { const player = currentData.find(p => p.id == id); if (!player) return; const modal = document.getElementById('addModal'); const modalTitle = document.getElementById('modalTitle'); const formFields = document.getElementById('formFields'); modalTitle.textContent = 'Spieler bearbeiten'; formFields.innerHTML = `
`; modal.style.display = 'block'; } async function editLocation(id) { const location = currentData.find(l => l.id == id); if (!location) return; const modal = document.getElementById('addModal'); const modalTitle = document.getElementById('modalTitle'); const formFields = document.getElementById('formFields'); modalTitle.textContent = 'Standort bearbeiten'; formFields.innerHTML = `
`; modal.style.display = 'block'; } async function editRun(id) { try { // Lade die spezifischen Lauf-Daten direkt von der API const response = await fetch(`/api/admin-runs/${id}`); const result = await response.json(); if (!result.success) { showError('Fehler beim Laden der Lauf-Daten: ' + (result.message || 'Unbekannter Fehler')); return; } const run = result.data; if (!run) { showError('Lauf nicht gefunden'); return; } console.log('Editing run:', run); // Debug log const modal = document.getElementById('addModal'); const modalTitle = document.getElementById('modalTitle'); const formFields = document.getElementById('formFields'); modalTitle.textContent = 'Lauf bearbeiten'; formFields.innerHTML = `
`; modal.style.display = 'block'; } catch (error) { console.error('Error loading run data:', error); showError('Fehler beim Laden der Lauf-Daten'); } } async function deletePlayer(id) { if (await confirmDelete(`Spieler mit ID ${id} löschen?`)) { try { const response = await fetch(`/api/admin-players/${id}`, { method: 'DELETE' }); const result = await response.json(); if (result.success) { showSuccess('Spieler erfolgreich gelöscht'); loadPlayers(); } else { showError('Fehler beim Löschen des Spielers'); } } catch (error) { console.error('Delete failed:', error); showError('Fehler beim Löschen des Spielers'); } } } async function deleteRun(id) { if (await confirmDelete(`Lauf mit ID ${id} löschen?`)) { try { const response = await fetch(`/api/admin-runs/${id}`, { method: 'DELETE' }); const result = await response.json(); if (result.success) { showSuccess('Lauf erfolgreich gelöscht'); loadRuns(); } else { showError('Fehler beim Löschen des Laufs'); } } catch (error) { console.error('Delete failed:', error); showError('Fehler beim Löschen des Laufs'); } } } async function deleteLocation(id) { if (await confirmDelete(`Standort mit ID ${id} löschen?`)) { try { const response = await fetch(`/api/admin-locations/${id}`, { method: 'DELETE' }); const result = await response.json(); if (result.success) { showSuccess('Standort erfolgreich gelöscht'); loadLocations(); } else { showError('Fehler beim Löschen des Standorts'); } } catch (error) { console.error('Delete failed:', error); showError('Fehler beim Löschen des Standorts'); } } } async function deleteAdminUser(id) { if (await confirmDelete(`Admin-Benutzer mit ID ${id} löschen?`)) { try { const response = await fetch(`/api/admin-adminusers/${id}`, { method: 'DELETE' }); const result = await response.json(); if (result.success) { showSuccess('Admin-Benutzer erfolgreich gelöscht'); loadAdminUsers(); } else { showError('Fehler beim Löschen des Admin-Benutzers'); } } catch (error) { console.error('Delete failed:', error); showError('Fehler beim Löschen des Admin-Benutzers'); } } } function confirmDelete(message) { return new Promise((resolve) => { document.getElementById('confirmMessage').textContent = message; document.getElementById('confirmModal').style.display = 'block'; document.getElementById('confirmYes').onclick = () => { closeModal(); resolve(true); }; document.getElementById('confirmNo').onclick = () => { closeModal(); resolve(false); }; }); } function showSuccess(message) { const messageDiv = document.getElementById('modalMessage'); messageDiv.textContent = message; messageDiv.className = 'message success'; messageDiv.style.display = 'block'; setTimeout(() => { messageDiv.style.display = 'none'; }, 3000); } function showError(message) { const messageDiv = document.getElementById('modalMessage'); messageDiv.textContent = message; messageDiv.className = 'message error'; messageDiv.style.display = 'block'; setTimeout(() => { messageDiv.style.display = 'none'; }, 3000); }