Player Statistics Dashboard
Build a player stats dashboard with charts and trends
Fetching Player Data
api/player.ts
import { CitoAPI } from '@citoapi/sdk';
const cito = new CitoAPI(process.env.CITO_API_KEY!);
export async function getPlayer(username: string, game: string) {
const { data } = await cito[game].players.get(username);
return data;
}
export async function getPlayerHistory(username: string, game: string) {
const { data } = await cito[game].players.matches(username, {
limit: 50,
sort: 'desc'
});
return data;
}Dashboard Component
PlayerDashboard.tsx
import { useQuery } from '@tanstack/react-query';
import { LineChart, Line, XAxis, YAxis, Tooltip } from 'recharts';
export function PlayerDashboard({ username, game }) {
const { data: player, isLoading } = useQuery({
queryKey: ['player', username, game],
queryFn: () => getPlayer(username, game)
});
const { data: history } = useQuery({
queryKey: ['player-history', username, game],
queryFn: () => getPlayerHistory(username, game)
});
if (isLoading) return <Skeleton />;
const kdTrend = history?.map(match => ({
date: new Date(match.played_at).toLocaleDateString(),
kd: match.eliminations / Math.max(match.deaths, 1)
}));
return (
<div className="space-y-6">
{/* Player Header */}
<div className="flex items-center gap-4">
<Avatar username={player.username} />
<div>
<h1 className="text-2xl font-bold">{player.username}</h1>
<p className="text-muted">{player.team || 'Free Agent'}</p>
</div>
</div>
{/* Stats Grid */}
<div className="grid grid-cols-4 gap-4">
<StatCard label="Wins" value={player.stats.career.wins} />
<StatCard label="K/D" value={player.stats.career.kd_ratio.toFixed(2)} />
<StatCard label="Win Rate" value={`${player.stats.career.win_rate}%`} />
<StatCard label="Earnings" value={`$${player.stats.competitive.earnings.toLocaleString()}`} />
</div>
{/* K/D Trend Chart */}
<div className="p-4 bg-secondary rounded-lg">
<h3 className="font-semibold mb-4">K/D Trend (Last 50 Games)</h3>
<LineChart width={600} height={200} data={kdTrend}>
<XAxis dataKey="date" />
<YAxis />
<Tooltip />
<Line type="monotone" dataKey="kd" stroke="#00E5CC" />
</LineChart>
</div>
{/* Recent Matches */}
<div>
<h3 className="font-semibold mb-4">Recent Matches</h3>
<MatchList matches={history?.slice(0, 10)} />
</div>
</div>
);
}Caching Strategies
Player stats don't change frequently. Use aggressive caching:
// Next.js API route with caching
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const username = searchParams.get('username');
const data = await getPlayer(username);
return Response.json(data, {
headers: {
'Cache-Control': 'public, s-maxage=300, stale-while-revalidate=600'
}
});
}
// React Query with stale time
const { data } = useQuery({
queryKey: ['player', username],
queryFn: () => getPlayer(username),
staleTime: 5 * 60 * 1000, // 5 minutes
cacheTime: 30 * 60 * 1000 // 30 minutes
});Player Comparison
export function PlayerComparison({ players }: { players: string[] }) {
const queries = useQueries({
queries: players.map(username => ({
queryKey: ['player', username],
queryFn: () => getPlayer(username)
}))
});
const data = queries.map(q => q.data).filter(Boolean);
return (
<table>
<thead>
<tr>
<th>Stat</th>
{data.map(p => <th key={p.username}>{p.username}</th>)}
</tr>
</thead>
<tbody>
<tr>
<td>Wins</td>
{data.map(p => <td key={p.username}>{p.stats.career.wins}</td>)}
</tr>
<tr>
<td>K/D</td>
{data.map(p => <td key={p.username}>{p.stats.career.kd_ratio.toFixed(2)}</td>)}
</tr>
{/* More stats... */}
</tbody>
</table>
);
}