'use client' import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, } from '@/components/ui/card' import { type ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent, } from '@/components/ui/chart' import { Slider } from '@/components/ui/slider' import type { SelectGames } from '@/server/db/types' import { useState } from 'react' import { CartesianGrid, Line, LineChart, XAxis, YAxis } from 'recharts' const chartConfig = { winrate: { label: 'Winrate', color: 'var(--color-emerald-500)', }, } satisfies ChartConfig export function WinrateTrendChart({ games }: { games: SelectGames[] }) { const [gamesWindow, setGamesWindow] = useState(30) // Sort games by date (oldest to newest) const sortedGames = [...games] .sort((a, b) => a.gameTime.getTime() - b.gameTime.getTime()) .filter((game) => game.result === 'win' || game.result === 'loss') // Calculate rolling winrate const chartData = calculateRollingWinrate(sortedGames, gamesWindow) return (
Winrate Trends Rolling winrate over time
Window size: {gamesWindow} games
setGamesWindow(value[0] ?? 0)} min={5} max={Math.min(100, games.length)} step={1} />
new Date(value).toLocaleDateString('en-US', { month: 'short', day: 'numeric', }) } /> `${value}%`} domain={[0, 100]} /> { const date = new Date(entry.payload.date) const formattedDate = date.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric', }) return (
{value}% {formattedDate}
) }} /> } />
Showing rolling winrate over the last {gamesWindow} games
) } function calculateRollingWinrate( games: SelectGames[], windowSize: number ): { date: Date; winrate: number }[] { if (games.length === 0 || windowSize <= 0) return [] // Use all games if windowSize is greater than the number of games const effectiveWindowSize = Math.min(windowSize, games.length) const result: { date: Date; winrate: number }[] = [] // We need at least windowSize games to start calculating for (let i = effectiveWindowSize - 1; i < games.length; i++) { // Get the window of games const windowGames = games.slice( Math.max(0, i - effectiveWindowSize + 1), i + 1 ) // Count wins in the window const wins = windowGames.filter((game) => game.result === 'win').length // Calculate winrate as percentage const winrate = Math.round((wins / windowGames.length) * 100) // Add data point if (games[i]) { result.push({ date: games[i]!.gameTime, winrate: winrate, }) } } return result }