diff --git a/app/routes/to/$organization.$tournament/map-pool.tsx b/app/routes/to/$organization.$tournament/map-pool.tsx
index a964f6212..cdfdd84c2 100644
--- a/app/routes/to/$organization.$tournament/map-pool.tsx
+++ b/app/routes/to/$organization.$tournament/map-pool.tsx
@@ -1,4 +1,4 @@
-import mapPoolStylesUrl from "~/styles/map-pool.css";
+import stylesUrl from "~/styles/map-pool.css";
import type { Mode } from ".prisma/client";
import classNames from "classnames";
import { modesShort, stages } from "~/utils";
@@ -6,7 +6,7 @@ import { LinksFunction, useMatches } from "remix";
import { FindTournamentByNameForUrlI } from "../../../../services/tournament";
export const links: LinksFunction = () => {
- return [{ rel: "stylesheet", href: mapPoolStylesUrl }];
+ return [{ rel: "stylesheet", href: stylesUrl }];
};
export default function MapPoolTab() {
diff --git a/app/routes/to/$organization.$tournament/teams.tsx b/app/routes/to/$organization.$tournament/teams.tsx
new file mode 100644
index 000000000..085482be9
--- /dev/null
+++ b/app/routes/to/$organization.$tournament/teams.tsx
@@ -0,0 +1,88 @@
+import { useMatches, LinksFunction } from "remix";
+import { FindTournamentByNameForUrlI } from "../../../../services/tournament";
+import stylesUrl from "~/styles/teams.css";
+import { Fragment } from "react";
+
+export const links: LinksFunction = () => {
+ return [{ rel: "stylesheet", href: stylesUrl }];
+};
+
+export default function TeamsTab() {
+ const [, parentRoute] = useMatches();
+ const { teams } = parentRoute.data as FindTournamentByNameForUrlI;
+
+ if (!teams.length) return null;
+
+ const sortedTeams = teams
+ // TODO: user id here
+ .sort(sortOwnTeamsAndFullTeamsFirst(-1))
+ .map((team) => {
+ return {
+ ...team,
+ members: team.members.sort(sortCaptainFirst),
+ };
+ });
+
+ return (
+
+
+
+ {sortedTeams.map((team) => (
+
+ {team.name}
+
+ {team.members.map(({ member, captain }, i) => (
+
+
+ {captain ? "C" : i + 1}
+
+
+
+ {member.discordAvatar && (
+

+ )}
+
+
{member.discordName}
+
+
+ ))}
+
+
+ ))}
+
+
+
+ );
+}
+
+function sortCaptainFirst(a: { captain: boolean }, b: { captain: boolean }) {
+ return Number(b.captain) - Number(a.captain);
+}
+
+function sortOwnTeamsAndFullTeamsFirst(userId?: number) {
+ return function (
+ a: { members: { member: { id: number } }[] },
+ b: { members: { member: { id: number } }[] }
+ ) {
+ if (userId) {
+ const aSortValue = Number(
+ a.members.some(({ member }) => userId === member.id)
+ );
+ const bSortValue = Number(
+ b.members.some(({ member }) => userId === member.id)
+ );
+
+ if (aSortValue !== bSortValue) return bSortValue - aSortValue;
+ }
+
+ const aSortValue = a.members.length >= 4 ? 1 : 0;
+ const bSortValue = b.members.length >= 4 ? 1 : 0;
+
+ return bSortValue - aSortValue;
+ };
+}
diff --git a/app/styles/teams.css b/app/styles/teams.css
new file mode 100644
index 000000000..aa0d4691d
--- /dev/null
+++ b/app/styles/teams.css
@@ -0,0 +1,77 @@
+.teams-tab {
+ display: flex;
+ flex-direction: column;
+ gap: var(--s-10);
+}
+
+.teams-tab__teams-container {
+ display: grid;
+ column-gap: var(--s-6);
+ grid-template-columns: 1fr;
+ row-gap: var(--s-10);
+}
+
+.teams-tab__team-name {
+ display: flex;
+ align-self: center;
+ border-block-end: 2px solid var(--theme);
+ font-size: var(--fonts-lg);
+ font-weight: var(--extra-bold);
+ justify-self: center;
+}
+
+.teams-tab__members-container {
+ display: flex;
+ flex-direction: column;
+ gap: var(--s-4);
+}
+
+.teams-tab__member {
+ display: flex;
+ align-items: center;
+ gap: var(--s-3);
+}
+
+.teams-tab__member__order-number {
+ color: var(--theme-secondary);
+ font-size: var(--fonts-sm);
+ font-weight: bold;
+}
+
+.teams-tab__member__container {
+ display: flex;
+ align-items: center;
+ font-weight: var(--semi-bold);
+ gap: var(--s-3);
+}
+
+.teams-tab__member__avatar {
+ block-size: 2.5rem;
+ border-radius: var(--rounded);
+ filter: none;
+ inline-size: 2.5rem;
+ text-indent: -10000px;
+}
+
+.teams-tab__member__placeholder {
+ background-image: url("/svg/background-pattern.svg");
+ block-size: 2.5rem;
+ border-radius: var(--rounded);
+ inline-size: 2.5rem;
+}
+
+@media screen and (min-width: 640px) {
+ .teams-tab__teams-container {
+ grid-template-columns: 1fr 1fr;
+ }
+
+ .teams-tab__team-name {
+ border-bottom: none;
+ justify-self: flex-end;
+ }
+
+ .teams-tab__members-container {
+ border-inline-start: 2px solid var(--theme);
+ padding-inline-start: var(--s-6);
+ }
+}