import { useEffect, useState, useCallback } from 'react' import { Link } from 'react-router-dom' import { Plus, Search, MoreVertical, UserX, UserCheck, Trash2, RefreshCw } from 'lucide-react' import { api } from '../api/client' interface Account { id: number username: string domain: string email: string status: string diskUsedMb: number bandwidthUsedMb: number ipAddress: string | null createdAt: string package?: { name: string; diskMb: number } } interface PageData { items: Account[] total: number page: number totalPages: number } const statusColor: Record = { active: 'bg-emerald-500/10 text-emerald-400 border-emerald-500/20', suspended: 'bg-amber-500/10 text-amber-400 border-amber-500/20', terminated: 'bg-red-500/10 text-red-400 border-red-500/20', } export default function Accounts() { const [data, setData] = useState(null) const [search, setSearch] = useState('') const [status, setStatus] = useState('') const [page, setPage] = useState(1) const [loading, setLoading] = useState(false) const [actionMenu, setActionMenu] = useState(null) const fetch = useCallback(async () => { setLoading(true) try { const params = new URLSearchParams({ page: String(page), limit: '25' }) if (search) params.set('search', search) if (status) params.set('status', status) const r = await api.get(`/nixserver/accounts?${params}`) setData(r.data.data) } finally { setLoading(false) } }, [page, search, status]) useEffect(() => { fetch() }, [fetch]) const action = async (id: number, act: 'suspend' | 'unsuspend' | 'terminate') => { setActionMenu(null) if (act === 'terminate' && !confirm('Terminate this account? This cannot be undone.')) return try { if (act === 'suspend') await api.post(`/nixserver/accounts/${id}/suspend`) else if (act === 'unsuspend') await api.post(`/nixserver/accounts/${id}/unsuspend`) else await api.delete(`/nixserver/accounts/${id}`) fetch() } catch (e: unknown) { alert((e as { response?: { data?: { error?: string } } })?.response?.data?.error ?? 'Action failed') } } return (

Accounts

{data?.total ?? 0} total

Create Account
{/* Filters */}
{ setSearch(e.target.value); setPage(1) }} placeholder="Search username, domain, email..." className="w-full bg-[#1a1d27] border border-[#2a2d3e] text-white text-sm rounded-lg pl-9 pr-3 py-2 focus:outline-none focus:border-indigo-500" />
{/* Table */}
{['Username', 'Domain', 'Package', 'Status', 'IP', 'Created', ''].map(h => ( ))} {loading && !data && ( )} {data?.items.map(acc => ( ))} {data?.items.length === 0 && ( )}
{h}
Loading...
{acc.username}

{acc.email}

{acc.domain} {acc.package?.name ?? '—'} {acc.status} {acc.ipAddress ?? '—'} {new Date(acc.createdAt).toLocaleDateString()} {actionMenu === acc.id && (
{acc.status === 'active' ? ( ) : acc.status === 'suspended' ? ( ) : null}
)}
No accounts found
{/* Pagination */} {data && data.totalPages > 1 && (
Page {data.page} of {data.totalPages} ({data.total} total)
)}
) }