feat(Tournament): add doubles tournament support and related UI enhancements

- Updated tournamentController.js and tournamentService.js to include isDoublesTournament parameter for tournament creation and updates.
- Modified Tournament model to add isDoublesTournament field, allowing differentiation between singles and doubles tournaments.
- Enhanced frontend components (TournamentConfigTab, TournamentParticipantsTab, TournamentTab) to support doubles tournament configuration and display.
- Added internationalization keys for doubles tournament labels and hints in multiple languages.
- Improved participant assignment logic for doubles tournaments to ensure proper class assignments.
This commit is contained in:
Torsten Schulz (local)
2026-03-25 11:49:47 +01:00
parent 64090d9ff0
commit c2a31d3b24
12 changed files with 686 additions and 214 deletions

View File

@@ -832,13 +832,13 @@ class TournamentService {
const tournaments = await Tournament.findAll({
where,
order: [['date', 'DESC']],
attributes: ['id', 'name', 'date', 'allowsExternal', 'miniChampionshipYear']
attributes: ['id', 'name', 'date', 'allowsExternal', 'miniChampionshipYear', 'isDoublesTournament']
});
return JSON.parse(JSON.stringify(tournaments));
}
Ve // 2. Neues Turnier anlegen
async addTournament(userToken, clubId, tournamentName, date, winningSets, allowsExternal) {
async addTournament(userToken, clubId, tournamentName, date, winningSets, allowsExternal, isDoublesTournament = false) {
await checkAccess(userToken, clubId);
const t = await Tournament.create({
name: tournamentName,
@@ -847,7 +847,8 @@ Ve // 2. Neues Turnier anlegen
bestOfEndroundSize: 0,
type: '',
winningSets: winningSets || 3, // Default: 3 Sätze
allowsExternal: allowsExternal || false
allowsExternal: allowsExternal || false,
isDoublesTournament: Boolean(isDoublesTournament)
});
return JSON.parse(JSON.stringify(t));
}
@@ -2281,7 +2282,7 @@ Ve // 2. Neues Turnier anlegen
}
// Update Turnier (Name, Datum, Gewinnsätze und Tischanzahl)
async updateTournament(userToken, clubId, tournamentId, name, date, winningSets, numberOfTables) {
async updateTournament(userToken, clubId, tournamentId, name, date, winningSets, numberOfTables, isDoublesTournament) {
await checkAccess(userToken, clubId);
const tournament = await Tournament.findOne({ where: { id: tournamentId, clubId } });
if (!tournament) {
@@ -2310,6 +2311,9 @@ Ve // 2. Neues Turnier anlegen
}
tournament.numberOfTables = numberOfTables;
}
if (isDoublesTournament !== undefined) {
tournament.isDoublesTournament = Boolean(isDoublesTournament);
}
await tournament.save();
return JSON.parse(JSON.stringify(tournament));
@@ -3945,6 +3949,22 @@ Ve // 2. Neues Turnier anlegen
if (existingPairing) {
throw new Error('Diese Paarung existiert bereits');
}
const playerAssignments = [];
if (player1Type === 'member') playerAssignments.push({ member1Id: player1Id }, { member2Id: player1Id });
if (player1Type === 'external') playerAssignments.push({ external1Id: player1Id }, { external2Id: player1Id });
if (player2Type === 'member') playerAssignments.push({ member1Id: player2Id }, { member2Id: player2Id });
if (player2Type === 'external') playerAssignments.push({ external1Id: player2Id }, { external2Id: player2Id });
const participantAlreadyAssigned = await TournamentPairing.findOne({
where: {
tournamentId,
classId,
[Op.or]: playerAssignments
}
});
if (participantAlreadyAssigned) {
throw new Error('Mindestens ein Spieler ist bereits einer Doppelpaarung zugeordnet');
}
return await TournamentPairing.create({
tournamentId,
classId,