556 lines
35 KiB
HTML
556 lines
35 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>SPEEDRUN ARENA - Admin Dashboard</title>
|
|
<link rel="icon" type="image/x-icon" href="/pictures/favicon.ico">
|
|
<link rel="manifest" href="/manifest.json">
|
|
<meta name="mobile-web-app-capable" content="yes">
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="default">
|
|
<meta name="apple-mobile-web-app-title" content="Ninja Cross">
|
|
<link rel="apple-touch-icon" href="/pictures/favicon.ico">
|
|
<script src="https://unpkg.com/@supabase/supabase-js@2"></script>
|
|
<!-- QR Code Scanner Library -->
|
|
<script src="https://unpkg.com/jsqr@1.4.0/dist/jsQR.js"></script>
|
|
<link rel="stylesheet" href="/css/dashboard.css">
|
|
|
|
<!-- Notification Permission Script -->
|
|
<script>
|
|
// Register Service Worker for iPhone Notifications
|
|
if ('serviceWorker' in navigator) {
|
|
navigator.serviceWorker.register('/sw.js')
|
|
.then(function(registration) {
|
|
console.log('✅ Service Worker registered:', registration);
|
|
})
|
|
.catch(function(error) {
|
|
console.log('❌ Service Worker registration failed:', error);
|
|
});
|
|
}
|
|
|
|
// Request notification permission on page load
|
|
if ('Notification' in window) {
|
|
if (Notification.permission === 'default') {
|
|
Notification.requestPermission().then(function(permission) {
|
|
if (permission === 'granted') {
|
|
console.log('✅ Notification permission granted');
|
|
// Subscribe to push notifications
|
|
subscribeToPush();
|
|
} else {
|
|
console.log('❌ Notification permission denied');
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// Subscribe to push notifications
|
|
async function subscribeToPush() {
|
|
try {
|
|
const registration = await navigator.serviceWorker.ready;
|
|
const subscription = await registration.pushManager.subscribe({
|
|
userVisibleOnly: true,
|
|
applicationServerKey: 'BJmNVx0C3XeVxeKGTP9c-Z4HcuZNmdk6QdiLocZgCmb-miCS0ESFO3W2TvJlRhhNAShV63pWA5p36BTVSetyTds'
|
|
});
|
|
|
|
// Send subscription to server
|
|
await fetch('/api/v1/public/subscribe', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(subscription)
|
|
});
|
|
|
|
console.log('✅ Push subscription successful');
|
|
} catch (error) {
|
|
console.error('❌ Push subscription failed:', error);
|
|
}
|
|
}
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<div class="main-container">
|
|
<!-- Language Selector -->
|
|
<div class="language-selector">
|
|
<select id="languageSelect" onchange="changeLanguage()">
|
|
<option value="de" data-flag="🇩🇪">Deutsch</option>
|
|
<option value="en" data-flag="🇺🇸">English</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="nav-buttons">
|
|
<div class="user-info">
|
|
<div class="user-avatar" id="userAvatar">U</div>
|
|
<span id="userEmail">user@example.com</span>
|
|
</div>
|
|
<a href="/" class="btn btn-primary" data-de="Zurück zu Zeiten" data-en="Back to Times">Back to Times</a>
|
|
<button class="btn btn-logout" onclick="logout()" data-de="Logout" data-en="Logout">Logout</button>
|
|
</div>
|
|
|
|
<div class="header-section">
|
|
<h1 class="main-title" data-de="DEIN DASHBOARD" data-en="YOUR DASHBOARD">DEIN DASHBOARD</h1>
|
|
<p class="tagline" data-de="Verwalte deine Läufe in der NINJACROSS ARENA" data-en="Manage your runs in the NINJACROSS ARENA">Verwalte deine Läufe in der NINJACROSS ARENA</p>
|
|
</div>
|
|
<div id="loading" class="loading">
|
|
<div class="spinner"></div>
|
|
<p data-de="Lade dein Dashboard..." data-en="Loading your dashboard...">Lade dein Dashboard...</p>
|
|
</div>
|
|
|
|
<div id="dashboardContent" style="display: none;">
|
|
<div class="welcome-card">
|
|
<h2 data-de="Dein Dashboard 🥷" data-en="Your Dashboard 🥷">Dein Dashboard 🥷</h2>
|
|
<p data-de="Willkommen in Deinem Dashboard-Panel! Deine übersichtliche Übersicht aller deiner Läufe." data-en="Welcome to your Dashboard panel! Your clear overview of all your runs.">Willkommen in Deinem Dashboard-Panel! Deine übersichtliche Übersicht aller deiner Läufe.</p>
|
|
|
|
</div>
|
|
|
|
<div class="dashboard-grid">
|
|
<div class="card" id="analyticsCard" style="cursor: pointer;">
|
|
<h3 data-de="📊 Analytics" data-en="📊 Analytics">📊 Analytics</h3>
|
|
<div id="analyticsPreview" style="display: none;">
|
|
<div class="analytics-stats">
|
|
<div class="mini-stat">
|
|
<div class="mini-stat-number" id="avgTimeThisWeek">--:--</div>
|
|
<div class="mini-stat-label">Durchschnitt diese Woche</div>
|
|
</div>
|
|
<div class="mini-stat">
|
|
<div class="mini-stat-number" id="improvementThisWeek">+0.0%</div>
|
|
<div class="mini-stat-label">Verbesserung</div>
|
|
</div>
|
|
<div class="mini-stat">
|
|
<div class="mini-stat-number" id="runsThisWeek">0</div>
|
|
<div class="mini-stat-label">Läufe diese Woche</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<p data-de="Verfolge deine Leistung und überwache wichtige Metriken." data-en="Track your performance and monitor important metrics.">Verfolge deine Leistung und überwache wichtige Metriken.</p>
|
|
<button class="btn btn-primary" style="margin-top: 1rem;" onclick="event.stopPropagation(); showAnalytics();" data-de="Analytics öffnen" data-en="Open Analytics">Analytics öffnen</button>
|
|
</div>
|
|
|
|
<div class="card" onclick="showSettings()" style="cursor: pointer;">
|
|
<h3 data-de="⚙️ Settings" data-en="⚙️ Settings">⚙️ Settings</h3>
|
|
<p data-de="Verwalte deine Privatsphäre-Einstellungen und andere Optionen." data-en="Manage your privacy settings and other options.">Verwalte deine Privatsphäre-Einstellungen und andere Optionen.</p>
|
|
<button class="btn btn-primary" style="margin-top: 1rem;" onclick="event.stopPropagation(); showSettings();" data-de="Einstellungen öffnen" data-en="Open Settings">Einstellungen öffnen</button>
|
|
</div>
|
|
|
|
<div class="card" onclick="showRFIDSettings()" style="cursor: pointer;">
|
|
<h3 data-de="🏷️ RFID Verknüpfung" data-en="🏷️ RFID Linking">🏷️ RFID Verknüpfung</h3>
|
|
<p data-de="Verknüpfe deine RFID-Karte mit deinem Account, um deine Zeiten automatisch zu tracken." data-en="Link your RFID card with your account to automatically track your times.">Verknüpfe deine RFID-Karte mit deinem Account, um deine Zeiten automatisch zu tracken.</p>
|
|
<button class="btn btn-primary" style="margin-top: 1rem;" onclick="event.stopPropagation(); showRFIDSettings();" data-de="RFID verknüpfen" data-en="Link RFID">RFID verknüpfen</button>
|
|
</div>
|
|
|
|
<div class="card" id="statisticsCard" style="cursor: pointer;">
|
|
<h3 data-de="📊 Statistiken" data-en="📊 Statistics">📊 Statistiken</h3>
|
|
<div id="statisticsPreview" style="display: none;">
|
|
<div class="statistics-stats">
|
|
<div class="mini-stat">
|
|
<div class="mini-stat-number" id="personalBest">--:--</div>
|
|
<div class="mini-stat-label">Persönliche Bestzeit</div>
|
|
</div>
|
|
<div class="mini-stat">
|
|
<div class="mini-stat-number" id="totalRunsCount">0</div>
|
|
<div class="mini-stat-label">Gesamte Läufe</div>
|
|
</div>
|
|
<div class="mini-stat">
|
|
<div class="mini-stat-number" id="rankPosition">-</div>
|
|
<div class="mini-stat-label">Ranglisten-Position</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<p data-de="Detaillierte Statistiken zu deinen Läufen - beste Zeiten, Verbesserungen und Vergleiche." data-en="Detailed statistics about your runs - best times, improvements and comparisons.">Detaillierte Statistiken zu deinen Läufen - beste Zeiten, Verbesserungen und Vergleiche.</p>
|
|
<button class="btn btn-primary" style="margin-top: 1rem;" onclick="event.stopPropagation(); showStatistics();" data-de="Statistiken öffnen" data-en="Open Statistics">Statistiken öffnen</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- User Times Section -->
|
|
<div class="times-section">
|
|
<div class="times-header">
|
|
<h2 data-de="🏃♂️ Meine Zeiten" data-en="🏃♂️ My Times">🏃♂️ Meine Zeiten</h2>
|
|
<p data-de="Deine persönlichen Bestzeiten an allen Standorten" data-en="Your personal best times at all locations">Deine persönlichen Bestzeiten an allen Standorten</p>
|
|
</div>
|
|
|
|
<!-- Loading State -->
|
|
<div id="timesLoading" class="times-loading" style="display: none;">
|
|
<div class="spinner"></div>
|
|
<p data-de="Lade deine Zeiten..." data-en="Loading your times...">Lade deine Zeiten...</p>
|
|
</div>
|
|
|
|
<!-- Not Linked State -->
|
|
<div id="timesNotLinked" class="times-not-linked">
|
|
<div class="not-linked-content">
|
|
<div class="not-linked-icon">🔗</div>
|
|
<h3 data-de="RFID noch nicht verknüpft" data-en="RFID not linked yet">RFID noch nicht verknüpft</h3>
|
|
<p data-de="Um deine persönlichen Zeiten zu sehen, musst du zuerst deine RFID-Karte mit deinem Account verknüpfen." data-en="To see your personal times, you must first link your RFID card with your account.">Um deine persönlichen Zeiten zu sehen, musst du zuerst deine RFID-Karte mit deinem Account verknüpfen.</p>
|
|
<button class="btn btn-primary" onclick="showRFIDSettings()" data-de="🏷️ RFID jetzt verknüpfen" data-en="🏷️ Link RFID now">
|
|
🏷️ RFID jetzt verknüpfen
|
|
</button>
|
|
<div class="link-info">
|
|
<h4 data-de="So funktioniert's:" data-en="How it works:">So funktioniert's:</h4>
|
|
<ol>
|
|
<li data-de="Klicke auf \"RFID jetzt verknüpfen\"" data-en="Click on \"Link RFID now\"">Klicke auf "RFID jetzt verknüpfen"</li>
|
|
<li data-de="Scanne den QR-Code auf deiner RFID-Karte" data-en="Scan the QR code on your RFID card">Scanne den QR-Code auf deiner RFID-Karte</li>
|
|
<li data-de="Fertig! Deine Zeiten werden automatisch hier angezeigt" data-en="Done! Your times will be displayed here automatically">Fertig! Deine Zeiten werden automatisch hier angezeigt</li>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Times Display -->
|
|
<div id="timesDisplay" style="display: none;">
|
|
<div class="times-stats">
|
|
<div class="stat-card">
|
|
<div class="stat-number" id="totalRuns">0</div>
|
|
<div class="stat-label" data-de="Gesamte Läufe" data-en="Total Runs">Gesamte Läufe</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-number" id="bestTime">--:--</div>
|
|
<div class="stat-label" data-de="Beste Zeit" data-en="Best Time">Beste Zeit</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-number" id="locationsCount">0</div>
|
|
<div class="stat-label" data-de="Standorte" data-en="Locations">Standorte</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-number" id="linkedPlayer">--</div>
|
|
<div class="stat-label" data-de="Verknüpfter Spieler" data-en="Linked Player">Verknüpfter Spieler</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="times-content">
|
|
<div class="times-grid" id="userTimesGrid">
|
|
<!-- Times will be populated here -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Analytics Section -->
|
|
<div id="analyticsSection" class="analytics-section" style="display: none;">
|
|
<div class="section-header">
|
|
<h2 data-de="📊 Analytics" data-en="📊 Analytics">📊 Analytics</h2>
|
|
<p data-de="Detaillierte Analyse deiner Performance und Trends" data-en="Detailed analysis of your performance and trends">Detaillierte Analyse deiner Performance und Trends</p>
|
|
</div>
|
|
|
|
<!-- Performance Overview -->
|
|
<div class="analytics-grid">
|
|
<div class="analytics-card">
|
|
<h3>📈 Performance-Trends</h3>
|
|
<div class="trend-stats">
|
|
<div class="trend-item">
|
|
<span class="trend-label">Diese Woche:</span>
|
|
<span class="trend-value" id="avgTimeThisWeekDetail">--:--</span>
|
|
</div>
|
|
<div class="trend-item">
|
|
<span class="trend-label">Letzte Woche:</span>
|
|
<span class="trend-value" id="avgTimeLastWeek">--:--</span>
|
|
</div>
|
|
<div class="trend-item">
|
|
<span class="trend-label">Verbesserung:</span>
|
|
<span class="trend-value" id="improvementDetail">+0.0%</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="analytics-card">
|
|
<h3>🏃♂️ Aktivitäts-Heatmap</h3>
|
|
<div class="activity-stats">
|
|
<div class="activity-item">
|
|
<span class="activity-label">Heute:</span>
|
|
<span class="activity-value" id="runsToday">0 Läufe</span>
|
|
</div>
|
|
<div class="activity-item">
|
|
<span class="activity-label">Diese Woche:</span>
|
|
<span class="activity-value" id="runsThisWeekDetail">0 Läufe</span>
|
|
</div>
|
|
<div class="activity-item">
|
|
<span class="activity-label">Durchschnitt/Tag:</span>
|
|
<span class="activity-value" id="avgRunsPerDay">0.0</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="analytics-card">
|
|
<h3>🏆 Standort-Performance</h3>
|
|
<div class="location-stats" id="locationPerformance">
|
|
<p data-de="Lade Standort-Daten..." data-en="Loading location data...">Lade Standort-Daten...</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="analytics-card">
|
|
<h3>📅 Monatlicher Fortschritt</h3>
|
|
<div class="monthly-stats">
|
|
<div class="monthly-item">
|
|
<span class="monthly-label">Dieser Monat:</span>
|
|
<span class="monthly-value" id="runsThisMonth">0 Läufe</span>
|
|
</div>
|
|
<div class="monthly-item">
|
|
<span class="monthly-label">Letzter Monat:</span>
|
|
<span class="monthly-value" id="runsLastMonth">0 Läufe</span>
|
|
</div>
|
|
<div class="monthly-item">
|
|
<span class="monthly-label">Beste Zeit:</span>
|
|
<span class="monthly-value" id="bestTimeThisMonth">--:--</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Statistics Section -->
|
|
<div id="statisticsSection" class="statistics-section" style="display: none;">
|
|
<div class="section-header">
|
|
<h2 data-de="📊 Statistiken" data-en="📊 Statistics">📊 Statistiken</h2>
|
|
<p data-de="Detaillierte Statistiken zu deinen Läufen und Vergleiche" data-en="Detailed statistics about your runs and comparisons">Detaillierte Statistiken zu deinen Läufen und Vergleiche</p>
|
|
</div>
|
|
|
|
<!-- Personal Records -->
|
|
<div class="statistics-grid">
|
|
<div class="statistics-card">
|
|
<h3>🏆 Persönliche Bestzeiten</h3>
|
|
<div class="personal-records" id="personalRecords">
|
|
<p data-de="Lade Bestzeiten..." data-en="Loading best times...">Lade Bestzeiten...</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="statistics-card">
|
|
<h3>📊 Konsistenz-Metriken</h3>
|
|
<div class="consistency-stats">
|
|
<div class="consistency-item">
|
|
<span class="consistency-label">Durchschnittszeit:</span>
|
|
<span class="consistency-value" id="averageTime">--:--</span>
|
|
</div>
|
|
<div class="consistency-item">
|
|
<span class="consistency-label">Standardabweichung:</span>
|
|
<span class="consistency-value" id="timeDeviation">--:--</span>
|
|
</div>
|
|
<div class="consistency-item">
|
|
<span class="consistency-label">Konsistenz-Score:</span>
|
|
<span class="consistency-value" id="consistencyScore">0%</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="statistics-card">
|
|
<h3>🏅 Ranglisten-Positionen</h3>
|
|
<div class="ranking-stats" id="rankingStats">
|
|
<p data-de="Lade Ranglisten..." data-en="Loading rankings...">Lade Ranglisten...</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="statistics-card">
|
|
<h3>📈 Fortschritt-Übersicht</h3>
|
|
<div class="progress-stats">
|
|
<div class="progress-item">
|
|
<span class="progress-label">Gesamte Läufe:</span>
|
|
<span class="progress-value" id="totalRunsStats">0</span>
|
|
</div>
|
|
<div class="progress-item">
|
|
<span class="progress-label">Aktive Tage:</span>
|
|
<span class="progress-value" id="activeDays">0</span>
|
|
</div>
|
|
<div class="progress-item">
|
|
<span class="progress-label">Standorte besucht:</span>
|
|
<span class="progress-value" id="locationsVisited">0</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Achievements Section -->
|
|
<div class="achievements-section">
|
|
<div class="achievements-header">
|
|
<h2 data-de="🏆 Meine Achievements" data-en="🏆 My Achievements">🏆 Meine Achievements</h2>
|
|
<p data-de="Sammele Punkte und erreiche neue Meilensteine!" data-en="Collect points and reach new milestones!">Sammele Punkte und erreiche neue Meilensteine!</p>
|
|
</div>
|
|
|
|
<!-- Achievement Stats -->
|
|
<div class="achievement-stats" id="achievementStats" style="display: none;">
|
|
<div class="stat-card achievement-stat">
|
|
<div class="stat-number" id="totalPoints">0</div>
|
|
<div class="stat-label" data-de="Gesamtpunkte" data-en="Total Points">Gesamtpunkte</div>
|
|
</div>
|
|
<div class="stat-card achievement-stat">
|
|
<div class="stat-number" id="completedAchievements">0</div>
|
|
<div class="stat-label" data-de="Abgeschlossen" data-en="Completed">Abgeschlossen</div>
|
|
</div>
|
|
<div class="stat-card achievement-stat">
|
|
<div class="stat-number" id="achievementsToday">0</div>
|
|
<div class="stat-label" data-de="Heute erreicht" data-en="Achieved Today">Heute erreicht</div>
|
|
</div>
|
|
<div class="stat-card achievement-stat">
|
|
<div class="stat-number" id="completionPercentage">0%</div>
|
|
<div class="stat-label" data-de="Fortschritt" data-en="Progress">Fortschritt</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Achievement Categories -->
|
|
<div class="achievement-categories" id="achievementCategories" style="display: none;">
|
|
<div class="category-tabs">
|
|
<button class="category-tab active" onclick="showAchievementCategory('all')" data-category="all" data-de="Alle" data-en="All">Alle</button>
|
|
<button class="category-tab" onclick="showAchievementCategory('consistency')" data-category="consistency" data-de="Konsistenz" data-en="Consistency">Konsistenz</button>
|
|
<button class="category-tab" onclick="showAchievementCategory('improvement')" data-category="improvement" data-de="Verbesserung" data-en="Improvement">Verbesserung</button>
|
|
<button class="category-tab" onclick="showAchievementCategory('seasonal')" data-category="seasonal" data-de="Saisonal" data-en="Seasonal">Saisonal</button>
|
|
<button class="category-tab" onclick="showAchievementCategory('monthly')" data-category="monthly" data-de="Monatlich" data-en="Monthly">Monatlich</button>
|
|
</div>
|
|
|
|
<div class="achievements-grid" id="achievementsGrid">
|
|
<!-- Achievements will be populated here -->
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Achievement Loading State -->
|
|
<div id="achievementsLoading" class="achievements-loading" style="display: none;">
|
|
<div class="spinner"></div>
|
|
<p data-de="Lade deine Achievements..." data-en="Loading your achievements...">Lade deine Achievements...</p>
|
|
</div>
|
|
|
|
<!-- Achievement Not Available State -->
|
|
<div id="achievementsNotAvailable" class="achievements-not-available" style="display: none;">
|
|
<div class="not-available-content">
|
|
<div class="not-available-icon">🏆</div>
|
|
<h3 data-de="Achievements noch nicht verfügbar" data-en="Achievements not available yet">Achievements noch nicht verfügbar</h3>
|
|
<p data-de="Um Achievements zu sammeln, musst du zuerst deine RFID-Karte mit deinem Account verknüpfen und einige Läufe absolvieren." data-en="To collect achievements, you must first link your RFID card with your account and complete some runs.">Um Achievements zu sammeln, musst du zuerst deine RFID-Karte mit deinem Account verknüpfen und einige Läufe absolvieren.</p>
|
|
<button class="btn btn-primary" onclick="showRFIDSettings()" data-de="🏷️ RFID jetzt verknüpfen" data-en="🏷️ Link RFID now">
|
|
🏷️ RFID jetzt verknüpfen
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- RFID Settings Modal -->
|
|
<div id="rfidModal" class="modal">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h2 class="modal-title" data-de="📱 RFID QR-Code Scanner" data-en="📱 RFID QR Code Scanner">📱 RFID QR-Code Scanner</h2>
|
|
<span class="close" onclick="closeModal('rfidModal')">×</span>
|
|
</div>
|
|
<div id="rfidMessage"></div>
|
|
|
|
<!-- QR Scanner Step -->
|
|
<div id="qrScannerStep">
|
|
<p style="color: #8892b0; margin-bottom: 1.5rem; text-align: center;" data-de="Scanne den QR-Code auf deiner RFID-Karte, um sie mit deinem Account zu verknüpfen." data-en="Scan the QR code on your RFID card to link it with your account.">
|
|
Scanne den QR-Code auf deiner RFID-Karte, um sie mit deinem Account zu verknüpfen.
|
|
</p>
|
|
|
|
<!-- Camera Preview -->
|
|
<div id="cameraContainer" style="display: none;">
|
|
<video id="qrVideo" style="width: 100%; max-width: 400px; border-radius: 0.75rem; margin: 0 auto; display: block;"></video>
|
|
<canvas id="qrCanvas" style="display: none;"></canvas>
|
|
</div>
|
|
|
|
<!-- Scanner Controls -->
|
|
<div style="text-align: center; margin: 1.5rem 0;">
|
|
<button class="btn btn-primary" onclick="startQRScanner()" id="startScanBtn" data-de="📷 Kamera starten" data-en="📷 Start Camera">
|
|
📷 Kamera starten
|
|
</button>
|
|
<button class="btn btn-secondary" onclick="stopQRScanner()" id="stopScanBtn" style="display: none;" data-de="🛑 Scanner stoppen" data-en="🛑 Stop Scanner">
|
|
🛑 Scanner stoppen
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Manual Input Fallback -->
|
|
<div style="border-top: 1px solid #334155; padding-top: 1.5rem; margin-top: 1.5rem;">
|
|
<p style="color: #8892b0; text-align: center; margin-bottom: 1rem; font-size: 0.9rem;" data-de="Kamera funktioniert nicht? RFID UID manuell eingeben:" data-en="Camera not working? Enter RFID UID manually:">
|
|
Kamera funktioniert nicht? RFID UID manuell eingeben:
|
|
</p>
|
|
<div class="form-group">
|
|
<input type="text" id="manualRfidInput" class="form-input" placeholder="z.B. aaaaaa, FFFFFF oder FF:FF:FF:FF" style="text-align: center; font-family: monospace;" data-de="z.B. aaaaaa, FFFFFF oder FF:FF:FF:FF" data-en="e.g. aaaaaa, FFFFFF or FF:FF:FF:FF">
|
|
</div>
|
|
<button class="btn btn-secondary" onclick="linkManualRfid()" style="width: 100%;" data-de="Manuell verknüpfen" data-en="Link Manually">
|
|
Manuell verknüpfen
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Create New Player Section -->
|
|
<div id="createPlayerSection" style="border-top: 1px solid #334155; padding-top: 1.5rem; margin-top: 1.5rem;">
|
|
<p style="color: #8892b0; text-align: center; margin-bottom: 1rem; font-size: 0.9rem;" data-de="Neuen Spieler mit RFID erstellen:" data-en="Create new player with RFID:">
|
|
Neuen Spieler mit RFID erstellen:
|
|
</p>
|
|
|
|
<div class="form-group">
|
|
<label for="playerFirstname" style="color: #8892b0; font-size: 0.9rem; margin-bottom: 0.5rem; display: block;" data-de="Vorname:" data-en="First Name:">Vorname:</label>
|
|
<input type="text" id="playerFirstname" class="form-input" placeholder="Max" style="text-align: center;">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="playerLastname" style="color: #8892b0; font-size: 0.9rem; margin-bottom: 0.5rem; display: block;" data-de="Nachname:" data-en="Last Name:">Nachname:</label>
|
|
<input type="text" id="playerLastname" class="form-input" placeholder="Mustermann" style="text-align: center;">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="playerBirthdate" style="color: #8892b0; font-size: 0.9rem; margin-bottom: 0.5rem; display: block;" data-de="Geburtsdatum:" data-en="Birth Date:">Geburtsdatum:</label>
|
|
<input type="date" id="playerBirthdate" class="form-input" style="text-align: center;">
|
|
</div>
|
|
|
|
<button class="btn btn-primary" onclick="createRfidPlayerRecord()" style="width: 100%;" data-de="Spieler erstellen" data-en="Create Player">
|
|
Spieler erstellen
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Scanning Status -->
|
|
<div id="scanningStatus" style="display: none; text-align: center; color: #00d4ff; margin-top: 1rem;">
|
|
<div class="spinner" style="width: 20px; height: 20px; margin: 0 auto 0.5rem;"></div>
|
|
<span data-de="Suche nach QR-Code..." data-en="Searching for QR code...">Suche nach QR-Code...</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Settings Modal -->
|
|
<div id="settingsModal" class="modal">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h2 class="modal-title" data-de="⚙️ Einstellungen" data-en="⚙️ Settings">⚙️ Einstellungen</h2>
|
|
<span class="close" onclick="closeModal('settingsModal')">×</span>
|
|
</div>
|
|
|
|
<div class="settings-content">
|
|
<div class="setting-item">
|
|
<div class="setting-info">
|
|
<h3 data-de="🏆 Leaderboard Sichtbarkeit" data-en="🏆 Leaderboard Visibility">🏆 Leaderboard Sichtbarkeit</h3>
|
|
<p data-de="Bestimme, ob deine Zeiten im globalen Leaderboard angezeigt werden sollen." data-en="Determine whether your times should be displayed in the global leaderboard.">Bestimme, ob deine Zeiten im globalen Leaderboard angezeigt werden sollen.</p>
|
|
</div>
|
|
<div class="setting-control">
|
|
<label class="toggle-switch">
|
|
<input type="checkbox" id="showInLeaderboard" onchange="updateLeaderboardSetting()">
|
|
<span class="toggle-slider"></span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="setting-description">
|
|
<p style="color: #8892b0; font-size: 0.9rem; margin-top: 1rem; padding: 1rem; background: #1e293b; border-radius: 0.5rem;" data-de="<strong>Hinweis:</strong> Wenn diese Option deaktiviert ist, werden deine Zeiten nur in deinem persönlichen Dashboard angezeigt, aber nicht im öffentlichen Leaderboard. Du kannst diese Einstellung jederzeit ändern." data-en="<strong>Note:</strong> If this option is disabled, your times will only be displayed in your personal dashboard, but not in the public leaderboard. You can change this setting at any time.">
|
|
<strong>Hinweis:</strong> Wenn diese Option deaktiviert ist, werden deine Zeiten nur in deinem persönlichen Dashboard angezeigt, aber nicht im öffentlichen Leaderboard. Du kannst diese Einstellung jederzeit ändern.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="settings-actions">
|
|
<button class="btn btn-primary" onclick="saveSettings()" data-de="Einstellungen speichern" data-en="Save Settings">Einstellungen speichern</button>
|
|
<button class="btn btn-secondary" onclick="closeModal('settingsModal')" data-de="Abbrechen" data-en="Cancel">Abbrechen</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<footer class="footer">
|
|
<div class="footer-content">
|
|
<div class="footer-links">
|
|
<a href="/impressum.html" class="footer-link" data-de="Impressum" data-en="Imprint">Impressum</a>
|
|
<a href="/datenschutz.html" class="footer-link" data-de="Datenschutz" data-en="Privacy">Datenschutz</a>
|
|
<button id="cookie-settings-footer" class="footer-link cookie-settings-btn" data-de="Cookie-Einstellungen" data-en="Cookie Settings">Cookie-Einstellungen</button>
|
|
</div>
|
|
<div class="footer-text">
|
|
<p data-de="© 2024 NinjaCross. Alle Rechte vorbehalten." data-en="© 2024 NinjaCross. All rights reserved.">© 2024 NinjaCross. Alle Rechte vorbehalten.</p>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
|
|
<script src="/js/cookie-consent.js"></script>
|
|
<script src="/js/dashboard.js?v=1.1"></script>
|
|
</body>
|
|
</html>
|