From 617a94262b23f0b15a2664e65781d66f93ced7d9 Mon Sep 17 00:00:00 2001 From: yohlo Date: Sat, 13 Sep 2025 11:36:30 -0500 Subject: [PATCH] redesign stats --- src/app/routes/_authed/profile.$playerId.tsx | 1 + .../players/components/stats-overview.tsx | 346 ++++++++++++------ 2 files changed, 230 insertions(+), 117 deletions(-) diff --git a/src/app/routes/_authed/profile.$playerId.tsx b/src/app/routes/_authed/profile.$playerId.tsx index aed4459..e9f6cbf 100644 --- a/src/app/routes/_authed/profile.$playerId.tsx +++ b/src/app/routes/_authed/profile.$playerId.tsx @@ -24,6 +24,7 @@ export const Route = createFileRoute("/_authed/profile/$playerId")({ settingsLink: context?.auth.user.id === params.playerId ? "/settings" : undefined, }, + withPadding: false, refresh: [playerQueries.details(params.playerId).queryKey], }), component: () => { diff --git a/src/features/players/components/stats-overview.tsx b/src/features/players/components/stats-overview.tsx index 41ccdc6..a1ae4d4 100644 --- a/src/features/players/components/stats-overview.tsx +++ b/src/features/players/components/stats-overview.tsx @@ -1,40 +1,96 @@ -import { Box, Grid, Text, Group, Stack, ThemeIcon, Card, Avatar } from "@mantine/core"; -import { TrophyIcon, CrownIcon, XIcon, FireIcon, ShieldIcon, ChartLineUpIcon, ShieldCheckIcon, BoxingGloveIcon, Icon } from "@phosphor-icons/react"; +import { Box, Grid, Text, Group, Stack, ThemeIcon, Card, Avatar, Progress, Badge, Divider } from "@mantine/core"; +import { CrownIcon, XIcon, FireIcon, ShieldIcon, ChartLineUpIcon, ShieldCheckIcon, BoxingGloveIcon, Icon, TrendUpIcon, ArrowUpIcon, ArrowDownIcon } from "@phosphor-icons/react"; import { usePlayerStats } from "../queries"; interface StatsOverviewProps { playerId: string; } -const StatCard = ({ - label, - value, - suffix = "", - Icon -}: { - label: string; - value: number | null; +const StatCard = ({ + label, + value, + suffix = "", + Icon, + variant = "default" +}: { + label: string; + value: number | null; suffix?: string; Icon?: Icon; -}) => ( - - -
- - {label} - - + variant?: "default" | "featured" | "compact"; +}) => { + if (variant === "featured") { + return ( + + + {Icon && ( + + + + )} +
+ + {value !== null ? `${value}${suffix}` : "—"} + + + {label} + +
+
+
+ ); + } + + if (variant === "compact") { + return ( + + + + + {label} + + + {value !== null ? `${value}${suffix}` : "—"} + + + {Icon && ( + + + + )} + + + ); + } + + return ( + + + + + {label} + + {Icon && ( + + + + )} + + {value !== null ? `${value}${suffix}` : "—"} -
- {Icon && ( - - - - )} -
-
-); + + + ); +}; const StatsOverview = ({ playerId }: StatsOverviewProps) => { const { data: statsData } = usePlayerStats(playerId); @@ -51,7 +107,6 @@ const StatsOverview = ({ playerId }: StatsOverviewProps) => { ); } - // Aggregate stats across all teams const overallStats = statsData.reduce( (acc, stat) => ({ matches: acc.matches + stat.matches, @@ -75,7 +130,6 @@ const StatsOverview = ({ playerId }: StatsOverviewProps) => { ? (overallStats.total_cups_against / overallStats.matches) : 0; - // Calculate average margins from individual team stats const validMarginOfVictory = statsData.filter(stat => stat.margin_of_victory > 0); const validMarginOfLoss = statsData.filter(stat => stat.margin_of_loss > 0); @@ -87,97 +141,155 @@ const StatsOverview = ({ playerId }: StatsOverviewProps) => { ? (validMarginOfLoss.reduce((acc, stat) => acc + stat.margin_of_loss, 0) / validMarginOfLoss.length) : 0; - return ( - - - Stats - - - - - - - - - - - - - - - - - - - - - - - - - - + const getWinRateColor = (rate: number) => { + if (rate >= 70) return "green"; + if (rate >= 50) return "blue"; + if (rate >= 30) return "orange"; + return "red"; + }; - {/* Team Breakdown */} + return ( + + + + + + + Match Statistics + + + + + + + + + + + + + + + Metrics + + + + + + + + + + + + + + + 0 ? parseFloat(avgMarginOfVictory.toFixed(1)) : null} + Icon={ArrowUpIcon} + /> + + + 0 ? parseFloat(avgMarginOfLoss.toFixed(1)) : null} + Icon={ArrowDownIcon} + /> + + + + + {/* Team Performance */} {statsData.length > 1 && ( -
- Teams - - {statsData.map((stat) => ( -
- - - - {stat.player_name.split(' ').map(n => n[0]).join('')} - -
- {stat.player_name} - - {stat.matches}M • {stat.wins}W - {stat.losses}L - -
-
- - {((stat.wins / stat.matches) * 100).toFixed(0)}% - -
-
- ))} + <> + + + Team Performance + + {statsData.map((stat) => { + const teamWinRate = (stat.wins / stat.matches) * 100; + return ( + + + + + {stat.player_name.split(' ').map(n => n[0]).join('')} + + + {stat.player_name} + + + {stat.matches} matches + + + + {stat.wins}W + + + {stat.losses}L + + + + + + + {teamWinRate.toFixed(0)}% + + + + + + ); + })} + -
+ )}