From 0174ac83e9b499efef08332077314cc21b0e5173 Mon Sep 17 00:00:00 2001 From: cialloo Date: Sat, 4 Oct 2025 16:50:23 +0800 Subject: [PATCH] Implement API integration for statistics, recent chat messages, and top players; remove mock data --- src/App.tsx | 220 +++++++++++++++++++++++++++------------------------- 1 file changed, 115 insertions(+), 105 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 35ff03f..f55d4c9 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,47 +1,126 @@ import { useTranslation } from 'react-i18next' import { Link } from 'react-router-dom' +import { useState, useEffect } from 'react' import Layout from './components/Layout' import './App.css' +interface ChatMessage { + steamID64: string + userName: string + message: string + timeStamp: number +} + +interface TopPlayer { + steamID64: string + userName: string + playTime: number +} + +interface Stats { + totalPlayers: number + totalConnects: number + totalPlayTime: number + totalKills: number +} + function App() { const { t } = useTranslation() - // Mock data - in real app, this would come from API - // API endpoints: /api/server/statistics/* - // To integrate real API, replace mock data with: - // - // const [stats, setStats] = useState({ totalPlayers: 0, totalConnects: 0, totalPlayTime: 0, totalKills: 0 }) - // - // useEffect(() => { - // const timeRangeEnd = Date.now() - // const timeRangeStart = 0 // or specific start time - // const requestBody = { timeRangeStart, timeRangeEnd, playerFilter: [] } - // - // Promise.all([ - // fetch('/api/server/statistics/total-player-count', { method: 'POST', body: JSON.stringify(requestBody) }), - // fetch('/api/server/statistics/total-connect-count', { method: 'POST', body: JSON.stringify(requestBody) }), - // fetch('/api/server/statistics/total-play-time', { method: 'POST', body: JSON.stringify(requestBody) }), - // fetch('/api/server/statistics/total-kill-count', { - // method: 'POST', - // body: JSON.stringify({ ...requestBody, headshotOnly: false, weaponFilter: [] }) - // }) - // ]).then(responses => Promise.all(responses.map(r => r.json()))) - // .then(([players, connects, playTime, kills]) => { - // setStats({ - // totalPlayers: players.count, - // totalConnects: connects.totalConnectCount, - // totalPlayTime: playTime.totalPlayTime, - // totalKills: kills.totalKillCount - // }) - // }) - // }, []) - - const stats = { - totalPlayers: 1247, // from /api/server/statistics/total-player-count - totalConnects: 3456, // from /api/server/statistics/total-connect-count - totalPlayTime: 8640000, // from /api/server/statistics/total-play-time (in seconds) - totalKills: 15420 // from /api/server/statistics/total-kill-count - } + const [stats, setStats] = useState({ + totalPlayers: 0, + totalConnects: 0, + totalPlayTime: 0, + totalKills: 0 + }) + const [recentChats, setRecentChats] = useState([]) + const [topPlayers, setTopPlayers] = useState([]) + + // Fetch statistics data from API + useEffect(() => { + const timeRangeEnd = Date.now() + const timeRangeStart = 0 // all time + const requestBody = { timeRangeStart, timeRangeEnd } + + Promise.all([ + fetch('/api/server/statistics/total-player-count', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(requestBody) + }), + fetch('/api/server/statistics/total-connect-count', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(requestBody) + }), + fetch('/api/server/statistics/total-play-time', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(requestBody) + }), + fetch('/api/server/statistics/total-kill-count', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + ...requestBody, + headshotOnly: false, + weaponFilter: [], + playerFilter: [] + }) + }) + ]) + .then(responses => Promise.all(responses.map(r => r.json()))) + .then(([players, connects, playTime, kills]) => { + setStats({ + totalPlayers: players.count || 0, + totalConnects: connects.totalConnectCount || 0, + totalPlayTime: playTime.totalPlayTime || 0, + totalKills: kills.totalKillCount || 0 + }) + }) + .catch(error => console.error('Error fetching stats:', error)) + }, []) + + // Fetch recent chat messages (limit to top 5) + useEffect(() => { + fetch('/api/server/statistics/recent-chat-message', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + timeRangeStart: Date.now() - 3600000, // last hour + timeRangeEnd: Date.now() + }) + }) + .then(r => r.json()) + .then(data => { + // Limit to top 5 most recent messages + const messages = data.messages || [] + const top5 = messages + .sort((a: ChatMessage, b: ChatMessage) => b.timeStamp - a.timeStamp) + .slice(0, 5) + setRecentChats(top5) + }) + .catch(error => console.error('Error fetching chat messages:', error)) + }, []) + + // Fetch top players by playtime + useEffect(() => { + fetch('/api/server/statistics/top-play-time', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + timeRangeStart: 0, // all time + timeRangeEnd: Date.now() + }) + }) + .then(r => r.json()) + .then(data => { + // Get top 3 players + const players = data.players || [] + setTopPlayers(players.slice(0, 3)) + }) + .catch(error => console.error('Error fetching top players:', error)) + }, []) // Format playtime from seconds to hours const formatPlayTime = (seconds: number) => { @@ -54,75 +133,6 @@ function App() { return hours.toLocaleString() } - // Mock recent chat messages - from /api/server/statistics/recent-chat-message - // Response format: { messages: [{ steamID64, userName, message, timeStamp }] } - // To integrate real API: - // const [recentChats, setRecentChats] = useState([]) - // useEffect(() => { - // fetch('/api/server/statistics/recent-chat-message', { - // method: 'POST', - // headers: { 'Content-Type': 'application/json' }, - // body: JSON.stringify({ - // timeRangeStart: Date.now() - 3600000, // last hour - // timeRangeEnd: Date.now() - // }) - // }).then(r => r.json()) - // .then(data => setRecentChats(data.messages)) - // }, []) - const recentChats = [ - { - steamID64: '76561198281616762', - userName: 'ProGamer99', - message: 'GG everyone! Great match!', - timeStamp: Date.now() - 120000 // 2 minutes ago - }, - { - steamID64: '76561198281616763', - userName: 'SniperElite', - message: 'Anyone up for a quick match?', - timeStamp: Date.now() - 300000 // 5 minutes ago - }, - { - steamID64: '76561198281616764', - userName: 'HeadshotKing', - message: 'New server just went live!', - timeStamp: Date.now() - 480000 // 8 minutes ago - }, - { - steamID64: '76561198281616765', - userName: 'TacticalNuke', - message: 'Looking for team players', - timeStamp: Date.now() - 720000 // 12 minutes ago - }, - { - steamID64: '76561198281616766', - userName: 'FragMaster', - message: 'Server maintenance complete', - timeStamp: Date.now() - 900000 // 15 minutes ago - } - ] - - // Mock top players - from /api/server/statistics/top-play-time - // Response format: { players: [{ steamID64, userName, playTime }] } - // To integrate real API: - // const [topPlayers, setTopPlayers] = useState([]) - // useEffect(() => { - // fetch('/api/server/statistics/top-play-time', { - // method: 'POST', - // headers: { 'Content-Type': 'application/json' }, - // body: JSON.stringify({ - // timeRangeStart: 0, // all time - // timeRangeEnd: Date.now() - // }) - // }).then(r => r.json()) - // .then(data => setTopPlayers(data.players.slice(0, 3))) // top 3 - // }, []) - const topPlayers = [ - { steamID64: '76561198281616762', userName: 'ProGamer99', playTime: 882000 }, // 245 hours - { steamID64: '76561198281616763', userName: 'SniperElite', playTime: 784800 }, // 218 hours - { steamID64: '76561198281616764', userName: 'HeadshotKing', playTime: 702000 } // 195 hours - ] - // Format time ago from timestamp const formatTimeAgo = (timestamp: number) => { const seconds = Math.floor((Date.now() - timestamp) / 1000)