import { useState, useEffect, useRef } from 'react' import { useParams, useNavigate } from 'react-router-dom' import { getServers, serverAction, sendRcon, getServerLogs } from '../api' import { useUser } from '../context/UserContext' import MetricsChart from '../components/MetricsChart' export default function ServerDetail() { const { serverId } = useParams() const navigate = useNavigate() const { token, isModerator } = useUser() const [server, setServer] = useState(null) const [loading, setLoading] = useState(true) const [actionLoading, setActionLoading] = useState(false) const [activeTab, setActiveTab] = useState('overview') const [rconCommand, setRconCommand] = useState('') const [rconHistory, setRconHistory] = useState([]) const [logs, setLogs] = useState('') const logsRef = useRef(null) const rconRef = useRef(null) const fetchServer = async () => { try { const servers = await getServers(token) const found = servers.find(s => s.id === serverId) if (found) { setServer(found) } else { navigate('/') } } catch (err) { console.error(err) navigate('/') } finally { setLoading(false) } } useEffect(() => { fetchServer() const interval = setInterval(fetchServer, 10000) return () => clearInterval(interval) }, [token, serverId]) const handleAction = async (action) => { setActionLoading(true) try { await serverAction(token, server.id, action) setTimeout(() => { fetchServer() setActionLoading(false) }, 2000) } catch (err) { console.error(err) setActionLoading(false) } } const handleRcon = async (e) => { e.preventDefault() if (!rconCommand.trim()) return const cmd = rconCommand setRconCommand('') try { const { response } = await sendRcon(token, server.id, cmd) setRconHistory([...rconHistory, { cmd, res: response, time: new Date() }]) } catch (err) { setRconHistory([...rconHistory, { cmd, res: 'Error: ' + err.message, time: new Date(), error: true }]) } } const fetchLogs = async () => { try { const data = await getServerLogs(token, server.id, 20) setLogs(data.logs || '') if (logsRef.current) { logsRef.current.scrollTop = logsRef.current.scrollHeight } } catch (err) { console.error(err) } } useEffect(() => { if (activeTab === 'logs' && isModerator && server) { fetchLogs() const interval = setInterval(fetchLogs, 5000) return () => clearInterval(interval) } }, [activeTab, isModerator, server]) useEffect(() => { if (rconRef.current) { rconRef.current.scrollTop = rconRef.current.scrollHeight } }, [rconHistory]) const formatUptime = (seconds) => { const days = Math.floor(seconds / 86400) const hours = Math.floor((seconds % 86400) / 3600) const minutes = Math.floor((seconds % 3600) / 60) if (days > 0) return days + 'd ' + hours + 'h ' + minutes + 'm' return hours + 'h ' + minutes + 'm' } const tabs = [ { id: 'overview', label: 'Overview' }, { id: 'metrics', label: 'Metrics' }, ...(isModerator ? [ { id: 'console', label: 'Console' }, { id: 'logs', label: 'Logs' }, ] : []), ] if (loading) { return (
Loading...
) } if (!server) { return (
Server not found
) } const cpuPercent = Math.min(server.metrics.cpu, 100) const memPercent = Math.min(server.metrics.memory, 100) return (
{/* Header */}

{server.name}

{server.running ? 'Online' : 'Offline'}
{server.running && (

Uptime: {formatUptime(server.metrics.uptime)}

)}
{/* Tabs */}
{tabs.map((tab) => ( ))}
{/* Content */}
{/* Overview Tab */} {activeTab === 'overview' && (
{/* Stats Grid */}
CPU Usage
{server.metrics.cpu.toFixed(1)}%
Memory
{server.metrics.memoryUsed?.toFixed(1)} {server.metrics.memoryUnit}
of {server.metrics.memoryTotal?.toFixed(1)} {server.metrics.memoryUnit}
Players
{server.players.online}
{server.players.max ? 'of ' + server.players.max + ' max' : 'No limit'}
CPU Cores
{server.metrics.cpuCores}
{/* Players List */} {server.players?.list?.length > 0 && (

Online Players

{server.players.list.map((player, i) => ( {player} ))}
)} {/* Power Controls */} {isModerator && (

Server Controls

{server.running ? ( <> ) : ( )}
)}
)} {/* Metrics Tab */} {activeTab === 'metrics' && ( )} {/* Console Tab */} {activeTab === 'console' && isModerator && (
RCON Console - {server.name}
{rconHistory.length === 0 && (
Waiting for commands...
)} {rconHistory.map((entry, i) => (
[{entry.time.toLocaleTimeString()}] > {entry.cmd}
{entry.res}
))}
setRconCommand(e.target.value)} placeholder="Enter command..." className="input flex-1" />
)} {/* Logs Tab */} {activeTab === 'logs' && isModerator && (
Last 20 lines
{logs || 'Loading...'}
)}
) }