Refactor App component to integrate mock statistics and recent chat messages; update localization for stats and activity sections
This commit is contained in:
174
src/App.tsx
174
src/App.tsx
@@ -7,21 +7,139 @@ 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 = {
|
||||
onlinePlayers: 1247,
|
||||
totalServers: 89,
|
||||
totalPlayTime: '2.4M',
|
||||
activeGames: 23
|
||||
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
|
||||
}
|
||||
|
||||
// Format playtime from seconds to hours
|
||||
const formatPlayTime = (seconds: number) => {
|
||||
const hours = Math.floor(seconds / 3600)
|
||||
if (hours >= 1000000) {
|
||||
return `${(hours / 1000000).toFixed(1)}M`
|
||||
} else if (hours >= 1000) {
|
||||
return `${(hours / 1000).toFixed(1)}K`
|
||||
}
|
||||
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 = [
|
||||
{ user: 'ProGamer99', message: 'GG everyone! Great match!', time: '2m ago' },
|
||||
{ user: 'SniperElite', message: 'Anyone up for a quick match?', time: '5m ago' },
|
||||
{ user: 'HeadshotKing', message: 'New server just went live!', time: '8m ago' },
|
||||
{ user: 'TacticalNuke', message: 'Looking for team players', time: '12m ago' },
|
||||
{ user: 'FragMaster', message: 'Server maintenance complete', time: '15m ago' }
|
||||
{
|
||||
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)
|
||||
if (seconds < 60) return `${seconds}s ago`
|
||||
const minutes = Math.floor(seconds / 60)
|
||||
if (minutes < 60) return `${minutes}m ago`
|
||||
const hours = Math.floor(minutes / 60)
|
||||
if (hours < 24) return `${hours}h ago`
|
||||
const days = Math.floor(hours / 24)
|
||||
return `${days}d ago`
|
||||
}
|
||||
|
||||
// Format playtime to hours for leaderboard
|
||||
const formatPlayTimeHours = (seconds: number) => {
|
||||
return Math.floor(seconds / 3600)
|
||||
}
|
||||
|
||||
return (
|
||||
<Layout currentPage="home">
|
||||
{/* Hero Section */}
|
||||
@@ -57,23 +175,23 @@ function App() {
|
||||
<div className="stats-container">
|
||||
<div className="stat-card">
|
||||
<div className="stat-icon">👥</div>
|
||||
<div className="stat-number">{stats.onlinePlayers.toLocaleString()}</div>
|
||||
<div className="stat-label">{t('stats.onlinePlayers')}</div>
|
||||
<div className="stat-number">{stats.totalPlayers.toLocaleString()}</div>
|
||||
<div className="stat-label">{t('stats.totalPlayers')}</div>
|
||||
</div>
|
||||
<div className="stat-card">
|
||||
<div className="stat-icon">🖥️</div>
|
||||
<div className="stat-number">{stats.totalServers}</div>
|
||||
<div className="stat-label">{t('stats.activeServers')}</div>
|
||||
<div className="stat-icon"><EFBFBD></div>
|
||||
<div className="stat-number">{stats.totalConnects.toLocaleString()}</div>
|
||||
<div className="stat-label">{t('stats.totalConnects')}</div>
|
||||
</div>
|
||||
<div className="stat-card">
|
||||
<div className="stat-icon">⏱️</div>
|
||||
<div className="stat-number">{stats.totalPlayTime}</div>
|
||||
<div className="stat-label">{t('stats.hoursPlayed')}</div>
|
||||
<div className="stat-number">{formatPlayTime(stats.totalPlayTime)}</div>
|
||||
<div className="stat-label">{t('stats.totalPlayTime')}</div>
|
||||
</div>
|
||||
<div className="stat-card">
|
||||
<div className="stat-icon">🎯</div>
|
||||
<div className="stat-number">{stats.activeGames}</div>
|
||||
<div className="stat-label">{t('stats.liveMatches')}</div>
|
||||
<div className="stat-number">{stats.totalKills.toLocaleString()}</div>
|
||||
<div className="stat-label">{t('stats.totalKills')}</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -125,9 +243,9 @@ function App() {
|
||||
<div className="chat-feed">
|
||||
{recentChats.map((chat, index) => (
|
||||
<div key={index} className="chat-message">
|
||||
<div className="chat-user">{chat.user}:</div>
|
||||
<div className="chat-user">{chat.userName}:</div>
|
||||
<div className="chat-text">{chat.message}</div>
|
||||
<div className="chat-time">{chat.time}</div>
|
||||
<div className="chat-time">{formatTimeAgo(chat.timeStamp)}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@@ -136,17 +254,19 @@ function App() {
|
||||
<div className="sidebar-card">
|
||||
<h3>{t('activity.topPlayers')}</h3>
|
||||
<div className="leaderboard">
|
||||
<div className="leader-item">1. ProGamer99 - 2,450 pts</div>
|
||||
<div className="leader-item">2. SniperElite - 2,180 pts</div>
|
||||
<div className="leader-item">3. HeadshotKing - 1,950 pts</div>
|
||||
{topPlayers.map((player, index) => (
|
||||
<div key={player.steamID64} className="leader-item">
|
||||
{index + 1}. {player.userName} - {formatPlayTimeHours(player.playTime)}h
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="sidebar-card">
|
||||
<h3>{t('activity.quickStats')}</h3>
|
||||
<h3>{t('activity.serverInfo')}</h3>
|
||||
<div className="quick-stats">
|
||||
<div>{t('activity.avgMatchTime')}</div>
|
||||
<div>{t('activity.mostPopularMap')}</div>
|
||||
<div>{t('activity.peakHours')}</div>
|
||||
<div>{t('activity.serverStatus')}</div>
|
||||
<div>{t('activity.currentMap')}</div>
|
||||
<div>{t('activity.nextRestart')}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user