809 lines
30 KiB
JavaScript
809 lines
30 KiB
JavaScript
let currentUser = null;
|
|
let currentDataType = null;
|
|
let currentData = [];
|
|
|
|
// Beim Laden der Seite
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
checkAuth();
|
|
loadStatistics();
|
|
|
|
// Add cookie settings button functionality
|
|
const cookieSettingsBtn = document.getElementById('cookie-settings-footer');
|
|
if (cookieSettingsBtn) {
|
|
cookieSettingsBtn.addEventListener('click', function() {
|
|
if (window.cookieConsent) {
|
|
window.cookieConsent.resetConsent();
|
|
}
|
|
});
|
|
}
|
|
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/v1/web/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/v1/public/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/v1/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/v1/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 = '<div style="color: #dc3545;">Fehler beim Laden</div>';
|
|
});
|
|
}
|
|
}
|
|
|
|
function displayPageStats(containerId, stats) {
|
|
const container = document.getElementById(containerId);
|
|
|
|
if (!stats || stats.length === 0) {
|
|
container.innerHTML = '<div style="color: #6c757d;">0</div>';
|
|
return;
|
|
}
|
|
|
|
// Find main page visits
|
|
const mainPageStat = stats.find(stat => stat.page === 'main_page_visit');
|
|
const count = mainPageStat ? mainPageStat.count : 0;
|
|
|
|
container.innerHTML = `<div style="font-size: 1.5em; font-weight: bold; color: #1e3c72;">${count}</div>`;
|
|
}
|
|
|
|
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 = '<div class="no-data">Supabase-Benutzer werden über die Supabase-Console verwaltet</div>';
|
|
}
|
|
|
|
async function loadPlayers() {
|
|
try {
|
|
const response = await fetch('/api/v1/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/v1/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/v1/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/v1/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 = '<div class="table-container"><table class="data-table">';
|
|
html += '<thead><tr><th>ID</th><th>Name</th><th>RFID UID</th><th>Supabase User</th><th>Registriert</th><th>Aktionen</th></tr></thead><tbody>';
|
|
|
|
players.forEach(player => {
|
|
html += `<tr>
|
|
<td>${player.id}</td>
|
|
<td>${player.full_name || '-'}</td>
|
|
<td>${player.rfiduid || '-'}</td>
|
|
<td>${player.supabase_user_id ? '✅' : '❌'}</td>
|
|
<td>${new Date(player.created_at).toLocaleDateString('de-DE')}</td>
|
|
<td class="action-buttons">
|
|
<button class="btn btn-small btn-warning" onclick="editPlayer('${player.id}')">Bearbeiten</button>
|
|
<button class="btn btn-small btn-danger" onclick="deletePlayer('${player.id}')">Löschen</button>
|
|
</td>
|
|
</tr>`;
|
|
});
|
|
|
|
html += '</tbody></table></div>';
|
|
document.getElementById('dataContent').innerHTML = html;
|
|
}
|
|
|
|
function displayRunsTable(runs) {
|
|
let html = '<div class="table-container"><table class="data-table">';
|
|
html += '<thead><tr><th>ID</th><th>Spieler</th><th>Standort</th><th>Zeit</th><th>Datum</th><th>Aktionen</th></tr></thead><tbody>';
|
|
|
|
runs.forEach(run => {
|
|
// Use the time_seconds value from the backend
|
|
const timeInSeconds = parseFloat(run.time_seconds) || 0;
|
|
|
|
html += `<tr>
|
|
<td>${run.id}</td>
|
|
<td>${run.player_name || `Player ${run.player_id}`}</td>
|
|
<td>${run.location_name || `Location ${run.location_id}`}</td>
|
|
<td>${timeInSeconds.toFixed(3)}s</td>
|
|
<td>${new Date(run.created_at).toLocaleDateString('de-DE')} ${new Date(run.created_at).toLocaleTimeString('de-DE')}</td>
|
|
<td class="action-buttons">
|
|
<button class="btn btn-small btn-warning" onclick="editRun('${run.id}')">Bearbeiten</button>
|
|
<button class="btn btn-small btn-danger" onclick="deleteRun('${run.id}')">Löschen</button>
|
|
</td>
|
|
</tr>`;
|
|
});
|
|
|
|
html += '</tbody></table></div>';
|
|
document.getElementById('dataContent').innerHTML = html;
|
|
}
|
|
|
|
function displayLocationsTable(locations) {
|
|
let html = '<div class="table-container"><table class="data-table">';
|
|
html += '<thead><tr><th>ID</th><th>Name</th><th>Latitude</th><th>Longitude</th><th>Erstellt</th><th>Aktionen</th></tr></thead><tbody>';
|
|
|
|
locations.forEach(location => {
|
|
html += `<tr>
|
|
<td>${location.id}</td>
|
|
<td>${location.name}</td>
|
|
<td>${location.latitude}</td>
|
|
<td>${location.longitude}</td>
|
|
<td>${new Date(location.created_at).toLocaleDateString('de-DE')}</td>
|
|
<td class="action-buttons">
|
|
<button class="btn btn-small btn-warning" onclick="editLocation('${location.id}')">Bearbeiten</button>
|
|
<button class="btn btn-small btn-danger" onclick="deleteLocation('${location.id}')">Löschen</button>
|
|
</td>
|
|
</tr>`;
|
|
});
|
|
|
|
html += '</tbody></table></div>';
|
|
document.getElementById('dataContent').innerHTML = html;
|
|
}
|
|
|
|
function displayAdminUsersTable(users) {
|
|
let html = '<div class="table-container"><table class="data-table">';
|
|
html += '<thead><tr><th>ID</th><th>Benutzername</th><th>Access Level</th><th>Aktiv</th><th>Letzter Login</th><th>Aktionen</th></tr></thead><tbody>';
|
|
|
|
users.forEach(user => {
|
|
const isCurrentUser = user.id === currentUser.id;
|
|
html += `<tr>
|
|
<td>${user.id}</td>
|
|
<td>${user.username} ${isCurrentUser ? '(Du)' : ''}</td>
|
|
<td>Level ${user.access_level}</td>
|
|
<td>${user.is_active ? '✅' : '❌'}</td>
|
|
<td>${user.last_login ? new Date(user.last_login).toLocaleDateString('de-DE') : 'Nie'}</td>
|
|
<td class="action-buttons">
|
|
${!isCurrentUser ? `<button class="btn btn-small btn-danger" onclick="deleteAdminUser(${user.id})">Löschen</button>` : ''}
|
|
</td>
|
|
</tr>`;
|
|
});
|
|
|
|
html += '</tbody></table></div>';
|
|
document.getElementById('dataContent').innerHTML = html;
|
|
}
|
|
|
|
function loadSystemInfo() {
|
|
document.getElementById('dataContent').innerHTML = `
|
|
<div style="padding: 20px;">
|
|
<h4>Server-Informationen</h4>
|
|
<p><strong>Node.js Version:</strong> ${navigator.userAgent}</p>
|
|
<p><strong>Aktuelle Zeit:</strong> ${new Date().toLocaleString('de-DE')}</p>
|
|
<p><strong>Angemeldeter Benutzer:</strong> ${currentUser.username} (Level ${currentUser.access_level})</p>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
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 = `
|
|
<div class="form-group">
|
|
<label for="playerName">Vollständiger Name:</label>
|
|
<input type="text" id="playerName" name="full_name" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="playerRfid">RFID UID:</label>
|
|
<input type="text" id="playerRfid" name="rfiduid" placeholder="z.B. 1234567890">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="playerSupabaseId">Supabase User ID (optional):</label>
|
|
<input type="text" id="playerSupabaseId" name="supabase_user_id" placeholder="UUID">
|
|
</div>
|
|
`;
|
|
break;
|
|
|
|
case 'locations':
|
|
modalTitle.textContent = 'Neuen Standort hinzufügen';
|
|
formFields.innerHTML = `
|
|
<div class="form-group">
|
|
<label for="locationName">Standort-Name:</label>
|
|
<input type="text" id="locationName" name="name" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="locationLat">Breitengrad (Latitude):</label>
|
|
<input type="number" id="locationLat" name="latitude" step="any" required placeholder="z.B. 48.385337">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="locationLng">Längengrad (Longitude):</label>
|
|
<input type="number" id="locationLng" name="longitude" step="any" required placeholder="z.B. 9.986960">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="locationThreshold">Zeit-Schwellenwert (optional):</label>
|
|
<input type="number" id="locationThreshold" name="time_threshold" step="0.001" placeholder="z.B. 60.000">
|
|
</div>
|
|
`;
|
|
break;
|
|
|
|
case 'adminusers':
|
|
modalTitle.textContent = 'Neuen Admin-Benutzer hinzufügen';
|
|
formFields.innerHTML = `
|
|
<div class="form-group">
|
|
<label for="adminUsername">Benutzername:</label>
|
|
<input type="text" id="adminUsername" name="username" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="adminPassword">Passwort:</label>
|
|
<input type="password" id="adminPassword" name="password" required minlength="6">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="adminAccessLevel">Zugriffslevel:</label>
|
|
<select id="adminAccessLevel" name="access_level" required>
|
|
<option value="1">Level 1 - Basis-Admin</option>
|
|
<option value="2">Level 2 - Vollzugriff</option>
|
|
</select>
|
|
</div>
|
|
`;
|
|
break;
|
|
|
|
case 'runs':
|
|
modalTitle.textContent = 'Neuen Lauf hinzufügen';
|
|
formFields.innerHTML = `
|
|
<div class="form-group">
|
|
<label for="runPlayerId">Spieler ID:</label>
|
|
<input type="number" id="runPlayerId" name="player_id" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="runLocationId">Standort ID:</label>
|
|
<input type="number" id="runLocationId" name="location_id" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="runTime">Zeit (Sekunden):</label>
|
|
<input type="number" id="runTime" name="time_seconds" step="0.001" required placeholder="z.B. 60.123">
|
|
</div>
|
|
`;
|
|
break;
|
|
|
|
default:
|
|
modalTitle.textContent = 'Element hinzufügen';
|
|
formFields.innerHTML = '<p>Keine Felder für diesen Datentyp verfügbar.</p>';
|
|
}
|
|
|
|
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/v1/admin/players/${editId}` : '/api/v1/admin/players';
|
|
successMessage = isEdit ? 'Spieler erfolgreich aktualisiert' : 'Spieler erfolgreich hinzugefügt';
|
|
method = isEdit ? 'PUT' : 'POST';
|
|
break;
|
|
case 'locations':
|
|
endpoint = isEdit ? `/api/v1/admin/locations/${editId}` : '/api/v1/admin/locations';
|
|
successMessage = isEdit ? 'Standort erfolgreich aktualisiert' : 'Standort erfolgreich hinzugefügt';
|
|
method = isEdit ? 'PUT' : 'POST';
|
|
break;
|
|
case 'adminusers':
|
|
endpoint = isEdit ? `/api/v1/admin/adminusers/${editId}` : '/api/v1/admin/adminusers';
|
|
successMessage = isEdit ? 'Admin-Benutzer erfolgreich aktualisiert' : 'Admin-Benutzer erfolgreich hinzugefügt';
|
|
method = isEdit ? 'PUT' : 'POST';
|
|
break;
|
|
case 'runs':
|
|
endpoint = isEdit ? `/api/v1/admin/runs/${editId}` : '/api/v1/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 = `
|
|
<div class="form-group">
|
|
<label for="playerName">Vollständiger Name:</label>
|
|
<input type="text" id="playerName" name="full_name" value="${player.full_name || ''}" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="playerRfid">RFID UID:</label>
|
|
<input type="text" id="playerRfid" name="rfiduid" value="${player.rfiduid || ''}" placeholder="z.B. 1234567890">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="playerSupabaseId">Supabase User ID (optional):</label>
|
|
<input type="text" id="playerSupabaseId" name="supabase_user_id" value="${player.supabase_user_id || ''}" placeholder="UUID">
|
|
</div>
|
|
<input type="hidden" name="edit_id" value="${player.id}">
|
|
`;
|
|
|
|
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 = `
|
|
<div class="form-group">
|
|
<label for="locationName">Standort-Name:</label>
|
|
<input type="text" id="locationName" name="name" value="${location.name}" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="locationLat">Breitengrad (Latitude):</label>
|
|
<input type="number" id="locationLat" name="latitude" step="any" value="${location.latitude}" required placeholder="z.B. 48.385337">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="locationLng">Längengrad (Longitude):</label>
|
|
<input type="number" id="locationLng" name="longitude" step="any" value="${location.longitude}" required placeholder="z.B. 9.986960">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="locationThreshold">Zeit-Schwellenwert (optional):</label>
|
|
<input type="number" id="locationThreshold" name="time_threshold" step="0.001" value="${location.time_threshold || ''}" placeholder="z.B. 60.000">
|
|
</div>
|
|
<input type="hidden" name="edit_id" value="${location.id}">
|
|
`;
|
|
|
|
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 = `
|
|
<div class="form-group">
|
|
<label for="runPlayerId">Spieler ID:</label>
|
|
<input type="text" id="runPlayerId" name="player_id" value="${run.player_id || ''}" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="runLocationId">Standort ID:</label>
|
|
<input type="text" id="runLocationId" name="location_id" value="${run.location_id || ''}" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="runTime">Zeit (Sekunden):</label>
|
|
<input type="number" id="runTime" name="time_seconds" step="0.001" value="${parseFloat(run.time_seconds || 0)}" required placeholder="z.B. 60.123">
|
|
</div>
|
|
<input type="hidden" name="edit_id" value="${run.id}">
|
|
`;
|
|
|
|
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/v1/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/v1/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/v1/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/v1/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);
|
|
}
|