-
-
Welcome to Ninja Server! π₯·
-View the latest times and performance data from our ninja training sessions.
+
+
- SPEEDRUN ARENA
+Die ultimative Timer-Rangliste
-
β±οΈ Latest Times
-
-
-
Loading times...
+
+
+
-
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/routes/public.js b/routes/public.js
index 41dfe14..179daf1 100644
--- a/routes/public.js
+++ b/routes/public.js
@@ -72,5 +72,109 @@ router.get('/times', async (req, res) => {
}
});
+// Public route to get all times with player and location details for leaderboard
+router.get('/times-with-details', async (req, res) => {
+ try {
+ const { location, period } = req.query;
+
+ // Build WHERE clause for location filter
+ let locationFilter = '';
+ if (location && location !== 'all') {
+ locationFilter = `AND l.name ILIKE '%${location}%'`;
+ }
+
+ // Build WHERE clause for date filter
+ let dateFilter = '';
+ const now = new Date();
+ if (period === 'today') {
+ const today = now.toISOString().split('T')[0];
+ dateFilter = `AND DATE(t.created_at) = '${today}'`;
+ } else if (period === 'week') {
+ const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
+ dateFilter = `AND DATE(t.created_at) >= '${weekAgo}'`;
+ } else if (period === 'month') {
+ const monthAgo = new Date(now.getFullYear(), now.getMonth(), 1).toISOString().split('T')[0];
+ dateFilter = `AND DATE(t.created_at) >= '${monthAgo}'`;
+ }
+
+ // Get all times with player and location details, ordered by time (fastest first)
+ const result = await pool.query(`
+ SELECT
+ t.id,
+ EXTRACT(EPOCH FROM t.recorded_time) as recorded_time_seconds,
+ t.created_at,
+ json_build_object(
+ 'id', p.id,
+ 'firstname', p.firstname,
+ 'lastname', p.lastname,
+ 'rfiduid', p.rfiduid
+ ) as player,
+ json_build_object(
+ 'id', l.id,
+ 'name', l.name,
+ 'latitude', l.latitude,
+ 'longitude', l.longitude
+ ) as location
+ FROM times t
+ LEFT JOIN players p ON t.player_id = p.id
+ LEFT JOIN locations l ON t.location_id = l.id
+ WHERE 1=1 ${locationFilter} ${dateFilter}
+ ORDER BY t.recorded_time ASC
+ LIMIT 50
+ `);
+
+ // Convert seconds to minutes:seconds.milliseconds format
+ const formattedResults = result.rows.map(row => {
+ const totalSeconds = parseFloat(row.recorded_time_seconds);
+ const minutes = Math.floor(totalSeconds / 60);
+ const seconds = Math.floor(totalSeconds % 60);
+ const milliseconds = Math.floor((totalSeconds % 1) * 1000);
+
+ return {
+ ...row,
+ recorded_time: {
+ minutes: minutes,
+ seconds: seconds,
+ milliseconds: milliseconds
+ }
+ };
+ });
+
+ res.json(formattedResults);
+
+ } catch (error) {
+ console.error('β Fehler beim Abrufen der Zeiten mit Details:', error);
+ res.status(500).json({
+ success: false,
+ message: 'Fehler beim Abrufen der Zeiten mit Details',
+ error: error.message
+ });
+ }
+});
+
+// Public route to get all locations for filter dropdown
+router.get('/locations', async (req, res) => {
+ try {
+ const result = await pool.query(`
+ SELECT id, name, latitude, longitude
+ FROM locations
+ ORDER BY name ASC
+ `);
+
+ res.json({
+ success: true,
+ data: result.rows
+ });
+
+ } catch (error) {
+ console.error('β Fehler beim Abrufen der Standorte:', error);
+ res.status(500).json({
+ success: false,
+ message: 'Fehler beim Abrufen der Standorte',
+ error: error.message
+ });
+ }
+});
+
module.exports = router;
+
-
+
+
+ 0
+ Teilnehmer
+
+
+ --:--
+ Rekordzeit
+
+
0
+ LΓ€ufe
+
- No times available yet. Check back later!
+
+
+
+
+
+
+
+ π Alle Standorte β’ π
Heute
+
+
+ Letzter Sync: Loading...
+
+
+