import React, { useEffect, useState, useRef } from 'react' import { Users, Globe, Server, HardDrive, Activity, AlertTriangle } from 'lucide-react' import { AreaChart, Area, XAxis, YAxis, Tooltip, ResponsiveContainer } from 'recharts' import { api } from '../api/client' interface SystemStats { cpu: number memory: { total: number; used: number; free: number; percent: number } disk: { total: number; used: number; free: number; percent: number } load: [number, number, number] uptime: number } interface AccountStats { total: number active: number suspended: number terminated: number } interface StatCard { label: string value: string | number sub?: string icon: React.ComponentType<{ size?: number; className?: string }> color: string } const formatBytes = (bytes: number) => { const gb = bytes / 1024 / 1024 / 1024 return gb >= 1 ? `${gb.toFixed(1)} GB` : `${(bytes / 1024 / 1024).toFixed(0)} MB` } export default function Dashboard() { const [stats, setStats] = useState(null) const [accountStats, setAccountStats] = useState(null) const [cpuHistory, setCpuHistory] = useState<{ t: string; cpu: number; mem: number }[]>([]) const wsRef = useRef(null) useEffect(() => { api.get('/nixserver/accounts/stats').then(r => setAccountStats(r.data.data)).catch(() => {}) api.get('/nixserver/system/stats').then(r => setStats(r.data.data)).catch(() => {}) // WebSocket live stats const token = localStorage.getItem('access_token') if (token) { const ws = new WebSocket(`ws://${window.location.hostname}:2087/ws/stats?token=${token}`) wsRef.current = ws ws.onmessage = e => { const msg = JSON.parse(e.data) if (msg.type === 'stats') { setStats(msg.data) setCpuHistory(prev => [ ...prev.slice(-29), { t: new Date().toLocaleTimeString(), cpu: msg.data.cpu, mem: msg.data.memory.percent }, ]) } } } return () => wsRef.current?.close() }, []) const cards: StatCard[] = [ { label: 'Total Accounts', value: accountStats?.total ?? '—', sub: `${accountStats?.active ?? 0} active`, icon: Users, color: 'text-indigo-400', }, { label: 'CPU Usage', value: stats ? `${stats.cpu}%` : '—', sub: `Load: ${stats?.load[0].toFixed(2) ?? '—'}`, icon: Activity, color: 'text-emerald-400', }, { label: 'Memory', value: stats ? `${stats.memory.percent}%` : '—', sub: stats ? `${formatBytes(stats.memory.used)} / ${formatBytes(stats.memory.total)}` : '—', icon: Server, color: 'text-blue-400', }, { label: 'Disk', value: stats ? `${stats.disk.percent}%` : '—', sub: stats ? `${formatBytes(stats.disk.used)} / ${formatBytes(stats.disk.total)}` : '—', icon: HardDrive, color: 'text-amber-400', }, ] return (

Dashboard

Server overview and real-time metrics

{/* Stat cards */}
{cards.map(card => (
{card.label}

{card.value}

{card.sub &&

{card.sub}

}
))}
{/* CPU / Memory chart */}

CPU & Memory — Live

{cpuHistory.length > 0 ? ( ) : (
Connecting to live stats...
)}
{/* Account status breakdown */} {accountStats && (

Account Status

{[ { label: 'Active', value: accountStats.active, color: 'text-emerald-400' }, { label: 'Suspended', value: accountStats.suspended, color: 'text-amber-400' }, { label: 'Terminated', value: accountStats.terminated, color: 'text-red-400' }, ].map(s => (

{s.value}

{s.label}

))}
)}
) }