import { useEffect, useState } from "react";
import { createApiClient } from "../api/client";
import type { components } from "../api/schema";
import BorderedContainer from "../components/BorderedContainer";
import UserIcon from "../components/UserIcon";
import { APP_NAME } from "../config";
import { usePageTitle } from "../hooks/usePageTitle";
type TournamentMatch = components["schemas"]["TournamentMatch"];
type User = components["schemas"]["User"];
function Player({ player, rank }: { player: User | null; rank: number }) {
return (
予選 {rank} 位
{player?.display_name}
{player?.icon_path && (
)}
);
}
function BranchVL({ className = "" }: { className?: string }) {
return (
);
}
function BranchVR({ className = "" }: { className?: string }) {
return (
);
}
function BranchVL2({
score,
className = "",
}: {
score: number | null;
className?: string;
}) {
return (
);
}
function BranchVR2({
score,
className = "",
}: {
score: number | null;
className?: string;
}) {
return (
);
}
function BranchV3({ className = "" }: { className?: string }) {
return ;
}
function BranchH({
score,
className1,
className2,
className3,
}: {
score?: number | null;
className1: string;
className2: string;
className3: string;
}) {
return (
);
}
function BranchH2({
score,
className1,
className2,
className3,
}: {
score?: number | null;
className1: string;
className2: string;
className3: string;
}) {
return (
);
}
function BranchL({
score,
className = "",
}: {
score: number | null;
className?: string;
}) {
return (
);
}
function BranchR({
score,
className = "",
}: {
score: number | null;
className?: string;
}) {
return (
);
}
function BranchL2({ className = "" }: { className?: string }) {
return (
);
}
function BranchR2({ className = "" }: { className?: string }) {
return (
);
}
function getPlayer(match: TournamentMatch, playerID: number): User | null {
if (match.player1?.user_id === playerID) return match.player1;
if (match.player2?.user_id === playerID) return match.player2;
return null;
}
function getScore(match: TournamentMatch, playerIDs: number[]): number | null {
if (match.player1 && playerIDs.includes(match.player1.user_id))
return match.player1_score ?? null;
if (match.player2 && playerIDs.includes(match.player2.user_id))
return match.player2_score ?? null;
return null;
}
function getBorderColor(match: TournamentMatch, playerIDs: number[]): string {
if (!match.winner) {
return "border-black";
}
if (playerIDs.includes(match.winner)) {
return "border-pink-700";
}
return "border-gray-400";
}
export default function TournamentPage() {
usePageTitle(`Tournament | ${APP_NAME}`);
const params = new URLSearchParams(window.location.search);
const game1 = Number(params.get("game1"));
const game2 = Number(params.get("game2"));
const game3 = Number(params.get("game3"));
const game4 = Number(params.get("game4"));
const game5 = Number(params.get("game5"));
const gamesValid = game1 && game2 && game3 && game4 && game5;
const pIDs = [
Number(params.get("player1")),
Number(params.get("player2")),
Number(params.get("player3")),
Number(params.get("player4")),
Number(params.get("player5")),
Number(params.get("player6")),
];
const playersValid = pIDs.every((id) => id);
const paramsValid = gamesValid && playersValid;
const paramsError = !gamesValid
? "Missing or invalid game parameters"
: !playersValid
? "Missing or invalid player parameters"
: null;
const [tournament, setTournament] = useState<{
matches: TournamentMatch[];
} | null>(null);
const playerIDs = paramsValid ? pIDs : [];
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
if (!paramsValid) {
return;
}
const apiClient = createApiClient();
apiClient
.getTournament(game1, game2, game3, game4, game5)
.then(({ tournament }) => setTournament(tournament))
.catch(() => setError("Failed to load tournament"))
.finally(() => setLoading(false));
}, [paramsValid, game1, game2, game3, game4, game5]);
if (paramsError) {
return (
);
}
if (loading) {
return (
);
}
if (error || !tournament) {
return (
{error || "Failed to load tournament"}
);
}
const match1 = tournament.matches[0]!;
const match2 = tournament.matches[1]!;
const match3 = tournament.matches[2]!;
const match4 = tournament.matches[3]!;
const match5 = tournament.matches[4]!;
const playerID1 = playerIDs[0]!;
const playerID2 = playerIDs[1]!;
const playerID3 = playerIDs[2]!;
const playerID4 = playerIDs[3]!;
const playerID5 = playerIDs[4]!;
const playerID6 = playerIDs[5]!;
const player5 = getPlayer(match1, playerID5);
const player4 = getPlayer(match1, playerID4);
const player3 = getPlayer(match2, playerID3);
const player6 = getPlayer(match2, playerID6);
const player1 = getPlayer(match3, playerID1);
const player2 = getPlayer(match4, playerID2);
return (
iOSDC Japan 2025 Swift Code Battle
);
}