191 lines
5.0 KiB
TypeScript
191 lines
5.0 KiB
TypeScript
import React, { createContext, useContext, useState, ReactNode, useMemo } from 'react';
|
|
import { Team, Round, TeamScore, Match, MatchResult } from '@/types/tournament';
|
|
import { generateMatches, createNextRoundMatches } from '@/utils/tournamentUtils';
|
|
|
|
interface TournamentContextType {
|
|
teams: Team[];
|
|
fieldCount: number;
|
|
rounds: Round[];
|
|
currentRound: Round | null;
|
|
addTeam: (team: Omit<Team, 'id'>) => void;
|
|
removeTeam: (id: string) => void;
|
|
setFieldCount: (count: number) => void;
|
|
resetTournament: () => void;
|
|
startNewRound: () => void;
|
|
updateMatchResult: (matchId: string, scoreA: number, scoreB: number) => void;
|
|
completeCurrentRound: () => void;
|
|
getTeamScores: (league: 'bundesliga' | 'champions') => TeamScore[];
|
|
}
|
|
|
|
const TournamentContext = createContext<TournamentContextType | undefined>(undefined);
|
|
|
|
export const TournamentProvider = ({ children }: { children: ReactNode }) => {
|
|
const [teams, setTeams] = useState<Team[]>([]);
|
|
const [fieldCount, setFieldCountState] = useState<number>(4);
|
|
const [rounds, setRounds] = useState<Round[]>([]);
|
|
|
|
const currentRound = useMemo(() => {
|
|
return rounds.find((r) => !r.completed) || null;
|
|
}, [rounds]);
|
|
|
|
const addTeam = (team: Omit<Team, 'id'>) => {
|
|
const newTeam: Team = {
|
|
...team,
|
|
id: crypto.randomUUID(),
|
|
};
|
|
setTeams((prev) => [...prev, newTeam]);
|
|
};
|
|
|
|
const removeTeam = (id: string) => {
|
|
setTeams((prev) => prev.filter((team) => team.id !== id));
|
|
};
|
|
|
|
const setFieldCount = (count: number) => {
|
|
setFieldCountState(Math.max(1, count));
|
|
};
|
|
|
|
const resetTournament = () => {
|
|
setTeams([]);
|
|
setFieldCountState(4);
|
|
setRounds([]);
|
|
};
|
|
|
|
const startNewRound = () => {
|
|
if (currentRound && !currentRound.completed) return;
|
|
|
|
let state;
|
|
|
|
if (rounds.length === 0) {
|
|
// First round: initial random generation
|
|
state = generateMatches(teams, fieldCount);
|
|
} else {
|
|
// Subsequent rounds: rotation system
|
|
const lastRound = rounds[rounds.length - 1];
|
|
state = createNextRoundMatches(lastRound, fieldCount);
|
|
}
|
|
|
|
const allMatches = [...state.bundesligaMatches, ...state.championsMatches];
|
|
|
|
const newRound: Round = {
|
|
id: crypto.randomUUID(),
|
|
roundNumber: rounds.length + 1,
|
|
matches: allMatches,
|
|
bundesligaWaiting: state.bundesligaWaiting,
|
|
championsWaiting: state.championsWaiting,
|
|
completed: false,
|
|
};
|
|
|
|
setRounds((prev) => [...prev, newRound]);
|
|
};
|
|
|
|
const updateMatchResult = (matchId: string, scoreA: number, scoreB: number) => {
|
|
const diff = Math.abs(scoreB - scoreA);
|
|
|
|
let pointsA: number;
|
|
let pointsB: number;
|
|
|
|
if (scoreA > scoreB) {
|
|
// Team A gewinnt
|
|
pointsA = diff + 2;
|
|
pointsB = -diff;
|
|
} else {
|
|
// Team B gewinnt
|
|
pointsA = -diff;
|
|
pointsB = diff + 2;
|
|
}
|
|
|
|
const result: MatchResult = {
|
|
scoreA,
|
|
scoreB,
|
|
pointsA,
|
|
pointsB,
|
|
};
|
|
|
|
setRounds((prev) =>
|
|
prev.map((round) => ({
|
|
...round,
|
|
matches: round.matches.map((match) =>
|
|
match.id === matchId ? { ...match, result } : match
|
|
),
|
|
}))
|
|
);
|
|
};
|
|
|
|
const completeCurrentRound = () => {
|
|
if (!currentRound) return;
|
|
|
|
// Check if all matches have results
|
|
const allMatchesHaveResults = currentRound.matches.every((m) => m.result);
|
|
if (!allMatchesHaveResults) return;
|
|
|
|
setRounds((prev) =>
|
|
prev.map((round) =>
|
|
round.id === currentRound.id ? { ...round, completed: true } : round
|
|
)
|
|
);
|
|
};
|
|
|
|
const getTeamScores = (league: 'bundesliga' | 'champions'): TeamScore[] => {
|
|
const leagueTeams = teams.filter((t) => t.league === league);
|
|
|
|
return leagueTeams.map((team) => {
|
|
const pointsHistory: number[] = [];
|
|
let totalPoints = 0;
|
|
let matchesPlayed = 0;
|
|
|
|
rounds.forEach((round) => {
|
|
let roundPoints = 0;
|
|
round.matches.forEach((match) => {
|
|
if (match.result) {
|
|
if (match.teamA.id === team.id) {
|
|
roundPoints += match.result.pointsA;
|
|
matchesPlayed++;
|
|
} else if (match.teamB.id === team.id) {
|
|
roundPoints += match.result.pointsB;
|
|
matchesPlayed++;
|
|
}
|
|
}
|
|
});
|
|
pointsHistory.push(roundPoints);
|
|
totalPoints += roundPoints;
|
|
});
|
|
|
|
return {
|
|
team,
|
|
totalPoints,
|
|
pointsHistory,
|
|
matchesPlayed,
|
|
};
|
|
}).sort((a, b) => b.totalPoints - a.totalPoints);
|
|
};
|
|
|
|
return (
|
|
<TournamentContext.Provider
|
|
value={{
|
|
teams,
|
|
fieldCount,
|
|
rounds,
|
|
currentRound,
|
|
addTeam,
|
|
removeTeam,
|
|
setFieldCount,
|
|
resetTournament,
|
|
startNewRound,
|
|
updateMatchResult,
|
|
completeCurrentRound,
|
|
getTeamScores,
|
|
}}
|
|
>
|
|
{children}
|
|
</TournamentContext.Provider>
|
|
);
|
|
};
|
|
|
|
export const useTournament = () => {
|
|
const context = useContext(TournamentContext);
|
|
if (!context) {
|
|
throw new Error('useTournament must be used within a TournamentProvider');
|
|
}
|
|
return context;
|
|
};
|