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>
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
"viewStats": "📊 View Stats"
|
||||
},
|
||||
"stats": {
|
||||
"onlinePlayers": "Online Players",
|
||||
"activeServers": "Active Servers",
|
||||
"hoursPlayed": "Hours Played",
|
||||
"liveMatches": "Live Matches"
|
||||
"totalPlayers": "Total Players",
|
||||
"totalConnects": "Total Connections",
|
||||
"totalPlayTime": "Hours Played",
|
||||
"totalKills": "Total Kills"
|
||||
},
|
||||
"features": {
|
||||
"title": "Community Features",
|
||||
@@ -53,11 +53,11 @@
|
||||
},
|
||||
"activity": {
|
||||
"title": "Recent Activity",
|
||||
"topPlayers": "🏆 Top Players",
|
||||
"quickStats": "🎯 Quick Stats",
|
||||
"avgMatchTime": "Avg Match Time: 12m 34s",
|
||||
"mostPopularMap": "Most Popular Map: Dust2",
|
||||
"peakHours": "Peak Hours: 8-11 PM"
|
||||
"topPlayers": "Top Players by Playtime",
|
||||
"serverInfo": "Server Info",
|
||||
"serverStatus": "Status: Online ✓",
|
||||
"currentMap": "Map: de_dust2",
|
||||
"nextRestart": "Restart: 6h 30m"
|
||||
},
|
||||
"footer": {
|
||||
"community": "🎯 CS Community",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"nav": {
|
||||
"logo": "CS 社区",
|
||||
"home": "首页",
|
||||
"servers": "服务器",
|
||||
"blog": "博客",
|
||||
@@ -18,10 +17,10 @@
|
||||
"viewStats": "📊 查看统计"
|
||||
},
|
||||
"stats": {
|
||||
"onlinePlayers": "在线玩家",
|
||||
"activeServers": "活跃服务器",
|
||||
"hoursPlayed": "游戏时长",
|
||||
"liveMatches": "实时比赛"
|
||||
"totalPlayers": "总玩家数",
|
||||
"totalConnects": "总连接数",
|
||||
"totalPlayTime": "游戏时长",
|
||||
"totalKills": "总击杀数"
|
||||
},
|
||||
"features": {
|
||||
"title": "社区功能",
|
||||
@@ -53,11 +52,11 @@
|
||||
},
|
||||
"activity": {
|
||||
"title": "最近活动",
|
||||
"topPlayers": "🏆 顶级玩家",
|
||||
"quickStats": "🎯 快速统计",
|
||||
"avgMatchTime": "平均比赛时长:12分34秒",
|
||||
"mostPopularMap": "最受欢迎地图:Dust2",
|
||||
"peakHours": "高峰时段:晚上8-11点"
|
||||
"topPlayers": "游戏时长排行榜",
|
||||
"serverInfo": "服务器信息",
|
||||
"serverStatus": "状态:在线 ✓",
|
||||
"currentMap": "地图:de_dust2",
|
||||
"nextRestart": "重启:6小时30分钟"
|
||||
},
|
||||
"footer": {
|
||||
"community": "🎯 CS 社区",
|
||||
|
||||
Reference in New Issue
Block a user