From 1f82c986465ff0a85dfd9e54b705dcb2a082c201 Mon Sep 17 00:00:00 2001 From: Carsten Graf Date: Thu, 4 Sep 2025 17:27:45 +0200 Subject: [PATCH] Statistik backend and favicon --- public/admin-dashboard.html | 43 ++++++++++++ public/adminlogin.html | 1 + public/css/admin-dashboard.css | 115 +++++++++++++++++++++++++++++++++ public/dashboard.html | 1 + public/generator.html | 1 + public/index.html | 2 + public/js/admin-dashboard.js | 61 +++++++++++++++++ public/js/page-tracking.js | 33 ++++++++++ public/login.html | 1 + public/pictures/favicon.ico | Bin 0 -> 15299 bytes public/reset-password.html | 1 + routes/api.js | 102 +++++++++++++++++++++++++++++ 12 files changed, 361 insertions(+) create mode 100644 public/js/page-tracking.js create mode 100644 public/pictures/favicon.ico diff --git a/public/admin-dashboard.html b/public/admin-dashboard.html index 7278c5a..e38d7d9 100644 --- a/public/admin-dashboard.html +++ b/public/admin-dashboard.html @@ -4,6 +4,7 @@ Admin Dashboard - NinjaCross + @@ -40,6 +41,48 @@ + +
+

🏠 Hauptseiten-Besuche

+
+
+

Heute

+
Lade...
+
+
+

Diese Woche

+
Lade...
+
+
+

Dieser Monat

+
Lade...
+
+
+

Gesamt

+
Lade...
+
+
+ + + +
+
diff --git a/public/adminlogin.html b/public/adminlogin.html index 87412a1..3742489 100644 --- a/public/adminlogin.html +++ b/public/adminlogin.html @@ -4,6 +4,7 @@ Login - Lizenzgenerator + diff --git a/public/css/admin-dashboard.css b/public/css/admin-dashboard.css index 5903be4..6b89da1 100644 --- a/public/css/admin-dashboard.css +++ b/public/css/admin-dashboard.css @@ -326,6 +326,121 @@ body { margin: 5% auto; width: 95%; } + + .page-stats-grid { + grid-template-columns: 1fr; + } + + .link-stats-grid { + grid-template-columns: repeat(2, 1fr); + } +} + +/* Page Statistics Styles */ +.page-stats-section { + background: white; + border-radius: 10px; + padding: 25px; + margin: 20px 0; + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); +} + +.page-stats-section h2 { + color: #1e3c72; + margin-bottom: 20px; + font-size: 1.5em; +} + +.page-stats-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 20px; + margin-bottom: 30px; +} + +.page-stat-card { + background: #f8f9fa; + border-radius: 8px; + padding: 20px; + border-left: 4px solid #1e3c72; +} + +.page-stat-card h3 { + color: #1e3c72; + margin-bottom: 15px; + font-size: 1.2em; +} + +.page-stats-content { + font-size: 0.9em; + line-height: 1.6; +} + +.page-stats-content .page-item { + display: flex; + justify-content: space-between; + align-items: center; + padding: 8px 0; + border-bottom: 1px solid #e9ecef; +} + +.page-stats-content .page-item:last-child { + border-bottom: none; +} + +.page-stats-content .page-name { + font-weight: 500; + color: #495057; +} + +.page-stats-content .page-count { + background: #1e3c72; + color: white; + padding: 4px 8px; + border-radius: 12px; + font-size: 0.8em; + font-weight: bold; +} + +/* Link Statistics Styles */ +.link-stats-section { + background: #f8f9fa; + border-radius: 8px; + padding: 20px; + margin-top: 20px; +} + +.link-stats-section h3 { + color: #1e3c72; + margin-bottom: 15px; + font-size: 1.3em; +} + +.link-stats-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + gap: 20px; +} + +.link-stat-card { + text-align: center; + background: white; + border-radius: 8px; + padding: 20px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); +} + +.link-stat-number { + font-size: 2em; + font-weight: bold; + color: #1e3c72; + margin-bottom: 8px; +} + +.link-stat-label { + color: #6c757d; + font-size: 0.9em; + font-weight: 500; } @media (max-width: 480px) { diff --git a/public/dashboard.html b/public/dashboard.html index 37e9010..eeb58cc 100644 --- a/public/dashboard.html +++ b/public/dashboard.html @@ -4,6 +4,7 @@ SPEEDRUN ARENA - Admin Dashboard + diff --git a/public/generator.html b/public/generator.html index 216097c..737eb7f 100644 --- a/public/generator.html +++ b/public/generator.html @@ -4,6 +4,7 @@ Lizenzgenerator + diff --git a/public/index.html b/public/index.html index 37a522b..dd4c32e 100644 --- a/public/index.html +++ b/public/index.html @@ -4,6 +4,8 @@ Timer Leaderboard + + diff --git a/public/js/admin-dashboard.js b/public/js/admin-dashboard.js index 0cea831..95bb68f 100644 --- a/public/js/admin-dashboard.js +++ b/public/js/admin-dashboard.js @@ -6,6 +6,7 @@ let currentData = []; document.addEventListener('DOMContentLoaded', function() { checkAuth(); loadStatistics(); + loadPageStatistics(); setupEventListeners(); }); @@ -87,6 +88,66 @@ async function loadStatistics() { } } +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(); diff --git a/public/js/page-tracking.js b/public/js/page-tracking.js new file mode 100644 index 0000000..327d95a --- /dev/null +++ b/public/js/page-tracking.js @@ -0,0 +1,33 @@ +// Page tracking functionality +function trackPageView(pageName) { + // Get user information + const userAgent = navigator.userAgent; + const referer = document.referrer || ''; + + // Send tracking data to server + fetch('/api/track-page-view', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + page: pageName, + userAgent: userAgent, + ipAddress: null, // Will be determined by server + referer: referer + }) + }).catch(error => { + console.log('Page tracking failed:', error); + // Silently fail - don't interrupt user experience + }); +} + +// Auto-track page on load - only track main page visits +document.addEventListener('DOMContentLoaded', function() { + // Only track the main page (index.html or root path) + const path = window.location.pathname; + + if (path === '/' || path === '/index.html') { + trackPageView('main_page_visit'); + } +}); diff --git a/public/login.html b/public/login.html index 97d50b0..7aff8cf 100644 --- a/public/login.html +++ b/public/login.html @@ -4,6 +4,7 @@ Ninja Server - Admin Login + diff --git a/public/pictures/favicon.ico b/public/pictures/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..5f2904b6066949fff4ce6195d013e8a4b74f7fde GIT binary patch literal 15299 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 Df8F^b literal 0 HcmV?d00001 diff --git a/public/reset-password.html b/public/reset-password.html index 0699a8c..993c114 100644 --- a/public/reset-password.html +++ b/public/reset-password.html @@ -4,6 +4,7 @@ Passwort zurücksetzen - NinjaCross + diff --git a/routes/api.js b/routes/api.js index 4cfa411..625d694 100644 --- a/routes/api.js +++ b/routes/api.js @@ -1622,6 +1622,108 @@ router.delete('/admin-adminusers/:id', requireAdminAuth, async (req, res) => { } }); +// ============================================================================ +// PAGE VIEWS TRACKING +// ============================================================================ + +// Track page view +router.post('/track-page-view', async (req, res) => { + try { + const { page, userAgent, ipAddress, referer } = req.body; + + await pool.query(` + INSERT INTO page_views (page, user_agent, ip_address, referer) + VALUES ($1, $2, $3, $4) + `, [page, userAgent, ipAddress, referer]); + + res.json({ success: true }); + } catch (error) { + console.error('Error tracking page view:', error); + res.status(500).json({ + success: false, + message: 'Fehler beim Tracking der Seitenaufrufe' + }); + } +}); + +// Get page statistics +router.get('/admin-page-stats', requireAdminAuth, async (req, res) => { + try { + // Page views for today, this week, this month + const today = new Date(); + const startOfDay = new Date(today.getFullYear(), today.getMonth(), today.getDate()); + const startOfWeek = new Date(today); + startOfWeek.setDate(today.getDate() - today.getDay()); + startOfWeek.setHours(0, 0, 0, 0); + const startOfMonth = new Date(today.getFullYear(), today.getMonth(), 1); + + // Today's page views + const todayViews = await pool.query(` + SELECT page, COUNT(*) as count + FROM page_views + WHERE created_at >= $1 + GROUP BY page + ORDER BY count DESC + `, [startOfDay]); + + // This week's page views + const weekViews = await pool.query(` + SELECT page, COUNT(*) as count + FROM page_views + WHERE created_at >= $1 + GROUP BY page + ORDER BY count DESC + `, [startOfWeek]); + + // This month's page views + const monthViews = await pool.query(` + SELECT page, COUNT(*) as count + FROM page_views + WHERE created_at >= $1 + GROUP BY page + ORDER BY count DESC + `, [startOfMonth]); + + // Total page views + const totalViews = await pool.query(` + SELECT page, COUNT(*) as count + FROM page_views + GROUP BY page + ORDER BY count DESC + `); + + // Player/Supabase link statistics + const linkStats = await pool.query(` + SELECT + COUNT(*) as total_players, + COUNT(CASE WHEN supabase_user_id IS NOT NULL THEN 1 END) as linked_players, + CAST( + ROUND( + (COUNT(CASE WHEN supabase_user_id IS NOT NULL THEN 1 END)::numeric / COUNT(*)) * 100, 2 + ) AS DECIMAL(5,2) + ) as link_percentage + FROM players + `); + + res.json({ + success: true, + data: { + today: todayViews.rows, + week: weekViews.rows, + month: monthViews.rows, + total: totalViews.rows, + linkStats: linkStats.rows[0] + } + }); + } catch (error) { + console.error('Error loading page statistics:', error); + res.status(500).json({ + success: false, + message: 'Fehler beim Laden der Seitenstatistiken' + }); + } +}); + // ============================================================================ // POST/PUT ROUTES FÜR CRUD-OPERATIONEN // ============================================================================