diff --git a/src/app/routes/_authed/admin/tournaments/run.$id.tsx b/src/app/routes/_authed/admin/tournaments/run.$id.tsx
index 25034a1..3de4ccf 100644
--- a/src/app/routes/_authed/admin/tournaments/run.$id.tsx
+++ b/src/app/routes/_authed/admin/tournaments/run.$id.tsx
@@ -86,6 +86,7 @@ function RouteComponent() {
)}
diff --git a/src/components/team-avatar.tsx b/src/components/team-avatar.tsx
new file mode 100644
index 0000000..a639936
--- /dev/null
+++ b/src/components/team-avatar.tsx
@@ -0,0 +1,139 @@
+import { Box, AvatarGroup } from "@mantine/core";
+import { CrownIcon } from "@phosphor-icons/react";
+import { TeamInfo } from "@/features/teams/types";
+import Avatar from "./avatar";
+import PlayerAvatar from "./player-avatar";
+
+interface TeamAvatarProps {
+ team: TeamInfo;
+ size?: number;
+ radius?: string | number;
+ withBorder?: boolean;
+ disableFullscreen?: boolean;
+ contain?: boolean;
+ style?: React.CSSProperties;
+ winner?: boolean;
+ isRegional?: boolean;
+}
+
+const TeamAvatar = ({
+ team,
+ size = 35,
+ radius = "sm",
+ withBorder = true,
+ disableFullscreen = false,
+ contain = false,
+ style,
+ winner = false,
+ isRegional,
+}: TeamAvatarProps) => {
+ const hasNoLogo = !team.logo;
+ const hasTwoPlayers = team.players?.length === 2;
+
+ let shouldShowPlayerAvatars = false;
+
+ if (isRegional !== undefined) {
+ shouldShowPlayerAvatars = isRegional && hasTwoPlayers && hasNoLogo;
+ } else {
+ const tournaments = (team as any).tournaments;
+ const hasTournaments = tournaments && tournaments.length > 0;
+ const allTournamentsAreRegional = hasTournaments && tournaments.every((t: any) => t.regional === true);
+
+ shouldShowPlayerAvatars = hasTwoPlayers && hasNoLogo && (allTournamentsAreRegional || !hasTournaments);
+ }
+
+ if (shouldShowPlayerAvatars && team.players?.length === 2) {
+ const playerSize = size * 0.6;
+ const crownSize = Math.max(12, size * 0.35);
+
+ return (
+
+
+
+
+ {winner && (
+
+
+
+ )}
+
+
+
+ {winner && (
+
+
+
+ )}
+
+
+
+ );
+ }
+
+ const crownSize = Math.max(14, size * 0.4);
+
+ return (
+
+
+ {winner && (
+
+
+
+ )}
+
+ );
+};
+
+export default TeamAvatar;
diff --git a/src/features/matches/components/match-card.tsx b/src/features/matches/components/match-card.tsx
index 827942c..37d3ebe 100644
--- a/src/features/matches/components/match-card.tsx
+++ b/src/features/matches/components/match-card.tsx
@@ -1,8 +1,8 @@
import { Text, Group, Stack, Paper, Indicator, Box, Tooltip, ActionIcon } from "@mantine/core";
-import { CrownIcon, FootballHelmetIcon } from "@phosphor-icons/react";
+import { FootballHelmetIcon } from "@phosphor-icons/react";
import { useNavigate } from "@tanstack/react-router";
import { Match } from "../types";
-import Avatar from "@/components/avatar";
+import TeamAvatar from "@/components/team-avatar";
import EmojiBar from "@/features/reactions/components/emoji-bar";
import { Suspense } from "react";
import { useSheet } from "@/hooks/use-sheet";
@@ -113,32 +113,16 @@ const MatchCard = ({ match, hideH2H = false }: MatchCardProps) => {
-
- {isHomeWin && (
-
-
-
- )}
{
-
- {isAwayWin && (
-
-
-
- )}
{
>
- {
key={`team-list-${team.id}`}
p="xs"
icon={
-
}
style={{ cursor: "pointer" }}
diff --git a/src/features/tournaments/components/edit-enrolled-teams.tsx b/src/features/tournaments/components/edit-enrolled-teams.tsx
index 02f0d80..1fd105e 100644
--- a/src/features/tournaments/components/edit-enrolled-teams.tsx
+++ b/src/features/tournaments/components/edit-enrolled-teams.tsx
@@ -11,7 +11,7 @@ import { useState, useCallback, useMemo, memo } from "react";
import { useTournament, useUnenrolledTeams } from "../queries";
import useEnrollTeam from "../hooks/use-enroll-team";
import useUnenrollTeam from "../hooks/use-unenroll-team";
-import Avatar from "@/components/avatar";
+import TeamAvatar from "@/components/team-avatar";
import { Team, TeamInfo } from "@/features/teams/types";
interface EditEnrolledTeamsProps {
@@ -22,9 +22,10 @@ interface TeamItemProps {
team: TeamInfo;
onUnenroll: (teamId: string) => void;
disabled: boolean;
+ isRegional?: boolean;
}
-const TeamItem = memo(({ team, onUnenroll, disabled }: TeamItemProps) => {
+const TeamItem = memo(({ team, onUnenroll, disabled, isRegional }: TeamItemProps) => {
const playerNames = useMemo(
() =>
team.players?.map((p) => `${p.first_name} ${p.last_name}`).join(", ") ||
@@ -34,15 +35,11 @@ const TeamItem = memo(({ team, onUnenroll, disabled }: TeamItemProps) => {
return (
-
@@ -73,6 +70,8 @@ const EditEnrolledTeams = ({ tournamentId }: EditEnrolledTeamsProps) => {
const { data: unenrolledTeams = [], isLoading: unenrolledLoading } =
useUnenrolledTeams(tournamentId);
+ const isRegional = tournament?.regional;
+
const { mutate: enrollTeam, isPending: isEnrolling } = useEnrollTeam();
const { mutate: unenrollTeam, isPending: isUnenrolling } = useUnenrollTeam();
@@ -107,15 +106,11 @@ const EditEnrolledTeams = ({ tournamentId }: EditEnrolledTeamsProps) => {
const team = option.data;
return (
-
{team.name}
@@ -174,6 +169,7 @@ const EditEnrolledTeams = ({ tournamentId }: EditEnrolledTeamsProps) => {
team={team}
onUnenroll={handleUnenrollTeam}
disabled={isUnenrolling}
+ isRegional={isRegional}
/>
))}
diff --git a/src/features/tournaments/components/seed-tournament.tsx b/src/features/tournaments/components/seed-tournament.tsx
index 8cafb19..f82a89c 100644
--- a/src/features/tournaments/components/seed-tournament.tsx
+++ b/src/features/tournaments/components/seed-tournament.tsx
@@ -13,7 +13,7 @@ import { DotsNineIcon } from "@phosphor-icons/react";
import { useServerMutation } from "@/lib/tanstack-query/hooks/use-server-mutation";
import { generateTournamentBracket } from "../../matches/server";
import { TeamInfo } from "@/features/teams/types";
-import Avatar from "@/components/avatar";
+import TeamAvatar from "@/components/team-avatar";
import { useBracketPreview } from "@/features/bracket/queries";
import { BracketData } from "@/features/bracket/types";
import BracketView from "@/features/bracket/components/bracket-view";
@@ -23,11 +23,13 @@ import { tournamentKeys } from "../queries";
interface SeedTournamentProps {
tournamentId: string;
teams: TeamInfo[];
+ isRegional?: boolean;
}
const SeedTournament: React.FC = ({
tournamentId,
teams,
+ isRegional,
}) => {
const [orderedTeams, setOrderedTeams] = useState(teams);
const { data: bracketPreview } = useBracketPreview(teams.length);
@@ -171,15 +173,11 @@ const SeedTournament: React.FC = ({
}}
/>
-
diff --git a/src/lib/pocketbase/services/matches.ts b/src/lib/pocketbase/services/matches.ts
index 9bcb325..72c101d 100644
--- a/src/lib/pocketbase/services/matches.ts
+++ b/src/lib/pocketbase/services/matches.ts
@@ -7,7 +7,7 @@ export function createMatchesService(pb: PocketBase) {
return {
async getMatch(id: string): Promise {
const result = await pb.collection("matches").getOne(id, {
- expand: "tournament, home, away",
+ expand: "tournament, home, away, home.players, away.players",
});
return transformMatch(result);
},
@@ -19,7 +19,7 @@ export function createMatchesService(pb: PocketBase) {
const result = await pb.collection("matches").getFullList({
filter: `tournament="${match.tournament.id}" && (home_from_lid = ${match.lid} || away_from_lid = ${match.lid}) && bye = false`,
- expand: "tournament, home, away",
+ expand: "tournament, home, away, home.players, away.players",
});
const winnerMatch = result.find(m => (m.home_from_lid === match.lid && !m.home_from_loser) || (m.away_from_lid === match.lid && !m.away_from_loser));
@@ -50,7 +50,7 @@ export function createMatchesService(pb: PocketBase) {
async updateMatch(id: string, data: Partial): Promise {
logger.info("PocketBase | Updating match", { id, data });
const result = await pb.collection("matches").update(id, data, {
- expand: 'home, away, tournament'
+ expand: 'home, away, tournament, home.players, away.players'
});
return transformMatch(result);
},
diff --git a/src/lib/pocketbase/services/players.ts b/src/lib/pocketbase/services/players.ts
index 2d4c638..e95120e 100644
--- a/src/lib/pocketbase/services/players.ts
+++ b/src/lib/pocketbase/services/players.ts
@@ -126,7 +126,7 @@ export function createPlayersService(pb: PocketBase) {
const result = await pb.collection("matches").getFullList({
filter: `(${teamFilter}) && (status = "ended" || status = "started")`,
sort: "-created",
- expand: "tournament,home,away",
+ expand: "tournament,home,away,home.players,away.players",
});
return result.map((match) => transformMatch(match));
diff --git a/src/lib/pocketbase/services/teams.ts b/src/lib/pocketbase/services/teams.ts
index e041932..4b1aac5 100644
--- a/src/lib/pocketbase/services/teams.ts
+++ b/src/lib/pocketbase/services/teams.ts
@@ -105,7 +105,7 @@ export function createTeamsService(pb: PocketBase) {
const result = await pb.collection("matches").getFullList({
filter: `(${teamFilter}) && (status = "ended" || status = "started")`,
sort: "-start_time",
- expand: "tournament,home,away",
+ expand: "tournament,home,away,home.players,away.players",
});
return result.map((match) => transformMatch(match));