c1adb94abb
CI has been running `prettier --check` against a tree that was never formatted, so the check reported 63 files and failed every run. Nothing here is a behaviour change: `pnpm lint` and the four typecheck builds pass exactly as before. conduit-bringup-artifacts is added to .prettierignore instead. Those files are captured bring-up reports, not maintained sources; reflowing them would only churn a record of what happened.
80 lines
2.6 KiB
TypeScript
80 lines
2.6 KiB
TypeScript
import { useParams } from 'react-router';
|
|
import { useQuery } from '@tanstack/react-query';
|
|
import { Users, RefreshCw } from 'lucide-react';
|
|
import { api } from '@/lib/api';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Card, CardContent } from '@/components/ui/card';
|
|
|
|
interface Player {
|
|
name: string;
|
|
steamid?: string;
|
|
}
|
|
|
|
interface PlayerListResponse {
|
|
players: Player[];
|
|
maxPlayers: number;
|
|
}
|
|
|
|
export function PlayersPage() {
|
|
const { orgId, serverId } = useParams();
|
|
|
|
const { data, isLoading, refetch } = useQuery({
|
|
queryKey: ['players', orgId, serverId],
|
|
queryFn: () =>
|
|
api.get<PlayerListResponse>(`/organizations/${orgId}/servers/${serverId}/players`),
|
|
refetchInterval: 30000,
|
|
});
|
|
|
|
const players = data?.players ?? [];
|
|
const maxPlayers = data?.maxPlayers ?? 0;
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<h2 className="text-lg font-semibold">Active Players</h2>
|
|
<p className="text-sm text-muted-foreground">
|
|
{players.length} / {maxPlayers} players online
|
|
</p>
|
|
</div>
|
|
<Button variant="outline" size="sm" onClick={() => refetch()} disabled={isLoading}>
|
|
<RefreshCw className={`h-4 w-4 ${isLoading ? 'animate-spin' : ''}`} />
|
|
Refresh
|
|
</Button>
|
|
</div>
|
|
|
|
{players.length === 0 ? (
|
|
<Card>
|
|
<CardContent className="flex flex-col items-center justify-center py-12">
|
|
<Users className="mb-4 h-12 w-12 text-muted-foreground/50" />
|
|
<p className="text-muted-foreground">No players online</p>
|
|
<p className="mt-1 text-xs text-muted-foreground">
|
|
Player tracking requires RCON to be enabled on the server
|
|
</p>
|
|
</CardContent>
|
|
</Card>
|
|
) : (
|
|
<Card>
|
|
<CardContent className="p-0">
|
|
<div className="divide-y">
|
|
{players.map((player, i) => (
|
|
<div key={i} className="flex items-center gap-3 px-4 py-3">
|
|
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-primary/10 text-sm font-medium text-primary">
|
|
{player.name.charAt(0).toUpperCase()}
|
|
</div>
|
|
<div>
|
|
<p className="font-medium">{player.name}</p>
|
|
{player.steamid && (
|
|
<p className="text-xs text-muted-foreground">{player.steamid}</p>
|
|
)}
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|