dark mode default, basic tournament stats/podium

This commit is contained in:
yohlo
2025-09-22 19:33:58 -05:00
parent b93ce38d48
commit 7ff26229d9
8 changed files with 228 additions and 71 deletions

View File

@@ -1,48 +1,27 @@
import {
Badge,
Card,
Text,
Stack,
Group,
Box,
ThemeIcon,
UnstyledButton,
Badge,
} from "@mantine/core";
import { Tournament } from "@/features/tournaments/types";
import { useMemo } from "react";
import { TournamentInfo } from "@/features/tournaments/types";
import {
TrophyIcon,
CalendarIcon,
MapPinIcon,
UsersIcon,
CrownIcon,
MedalIcon,
} from "@phosphor-icons/react";
import { useNavigate } from "@tanstack/react-router";
import Avatar from "@/components/avatar";
interface TournamentCardProps {
tournament: Tournament;
tournament: TournamentInfo;
}
export const TournamentCard = ({ tournament }: TournamentCardProps) => {
const navigate = useNavigate();
const displayDate = useMemo(() => {
if (!tournament.start_time) return null;
const date = new Date(tournament.start_time);
if (isNaN(date.getTime())) return null;
return date.toLocaleDateString(undefined, {
month: "short",
day: "numeric",
year: "numeric",
});
}, [tournament.start_time]);
const enrollmentDeadline = tournament.enroll_time
? new Date(tournament.enroll_time)
: new Date(tournament.start_time);
const isEnrollmentOpen = enrollmentDeadline > new Date();
const enrolledTeamsCount = tournament.teams?.length || 0;
return (
<UnstyledButton
w="100%"
@@ -93,31 +72,62 @@ export const TournamentCard = ({ tournament }: TournamentCardProps) => {
<Text fw={600} size="lg" lineClamp={2}>
{tournament.name}
</Text>
{displayDate && (
<Group gap="xs">
<ThemeIcon
size="sm"
variant="light"
radius="sm"
color="gray"
>
<CalendarIcon size={12} />
</ThemeIcon>
<Text size="sm" c="dimmed">
{displayDate}
</Text>
</Group>
{(tournament.first_place || tournament.second_place || tournament.third_place) && (
<Stack gap={6} >
{tournament.first_place && (
<Badge
size="md"
radius="md"
variant="filled"
color="yellow"
leftSection={
<CrownIcon size={16} />
}
style={{
textTransform: 'none',
fontWeight: 600,
color: 'white',
}}
>
{tournament.first_place.name}
</Badge>
)}
{tournament.second_place && (
<Badge
size="md"
radius="md"
color="gray"
variant="filled"
leftSection={
<MedalIcon size={16} />
}
style={{
textTransform: 'none',
fontWeight: 500,
}}
>
{tournament.second_place.name}
</Badge>
)}
{tournament.third_place && (
<Badge
size="md"
radius="md"
color="orange"
variant="filled"
leftSection={
<MedalIcon size={16} />
}
style={{
textTransform: 'none',
fontWeight: 500,
}}
>
{tournament.third_place.name}
</Badge>
)}
</Stack>
)}
<Group gap="xs">
<ThemeIcon size="sm" variant="light" radius="sm" color="gray">
<UsersIcon size={12} />
</ThemeIcon>
<Text size="sm" c="dimmed">
{enrolledTeamsCount} team
{enrolledTeamsCount !== 1 ? "s" : ""}
</Text>
</Group>
</Stack>
</Group>
</Group>

View File

@@ -2,6 +2,22 @@ import { TeamInfo } from "@/features/teams/types";
import { Match } from "@/features/matches/types";
import { z } from "zod";
export interface TournamentTeamStats {
id: string;
team_id: string;
tournament_id: string;
team_name: string;
matches: number;
wins: number;
losses: number;
total_cups_made: number;
total_cups_against: number;
margin_of_victory: number;
margin_of_loss: number;
win_percentage: number;
avg_cups_per_match: number;
}
export interface TournamentInfo {
id: string;
name: string;
@@ -9,6 +25,9 @@ export interface TournamentInfo {
start_time?: string;
end_time?: string;
logo?: string;
first_place?: TeamInfo;
second_place?: TeamInfo;
third_place?: TeamInfo;
}
export interface Tournament {
@@ -25,6 +44,10 @@ export interface Tournament {
updated: string;
teams?: TeamInfo[];
matches?: Match[];
first_place?: TeamInfo;
second_place?: TeamInfo;
third_place?: TeamInfo;
team_stats?: TournamentTeamStats[];
}
export const tournamentInputSchema = z.object({