Add tournament update functionality and enhance UI for tournament management
This commit introduces the ability to update tournament details, including name and date, in the backend and frontend. The new `updateTournament` method is added to the `tournamentController` and `tournamentService`, allowing for validation and error handling. The frontend `TournamentsView` is updated to include input fields for editing tournament details, with real-time updates reflected in the UI. Additionally, new CSS styles are introduced for improved layout and user interaction, enhancing the overall experience in tournament management.
This commit is contained in:
@@ -161,17 +161,12 @@ class TournamentService {
|
||||
throw new Error('Turnier nicht gefunden');
|
||||
}
|
||||
|
||||
// 1) Hole vorhandene Gruppen
|
||||
let groups = await TournamentGroup.findAll({ where: { tournamentId } });
|
||||
|
||||
// **Neu**: Falls noch keine Gruppen existieren, lege sie nach numberOfGroups an
|
||||
if (!groups.length) {
|
||||
const desired = tournament.numberOfGroups || 1; // Fallback auf 1, wenn undefiniert
|
||||
for (let i = 0; i < desired; i++) {
|
||||
await TournamentGroup.create({ tournamentId });
|
||||
}
|
||||
groups = await TournamentGroup.findAll({ where: { tournamentId } });
|
||||
}
|
||||
// 1) Stelle sicher, dass die richtige Anzahl von Gruppen existiert
|
||||
await this.createGroups(userToken, clubId, tournamentId);
|
||||
let groups = await TournamentGroup.findAll({
|
||||
where: { tournamentId },
|
||||
order: [['id', 'ASC']] // Stelle sicher, dass Gruppen sortiert sind
|
||||
});
|
||||
|
||||
const members = await TournamentMember.findAll({ where: { tournamentId } });
|
||||
if (!members.length) {
|
||||
@@ -181,32 +176,39 @@ class TournamentService {
|
||||
// 2) Alte Matches löschen
|
||||
await TournamentMatch.destroy({ where: { tournamentId } });
|
||||
|
||||
// 3) Prüfe, ob Spieler bereits manuell zugeordnet wurden
|
||||
const alreadyAssigned = members.filter(m => m.groupId !== null);
|
||||
const unassigned = members.filter(m => m.groupId === null);
|
||||
|
||||
if (alreadyAssigned.length > 0) {
|
||||
// Spieler sind bereits manuell zugeordnet - nicht neu verteilen
|
||||
devLog(`${alreadyAssigned.length} Spieler bereits zugeordnet, ${unassigned.length} noch nicht zugeordnet`);
|
||||
} else {
|
||||
// Keine manuellen Zuordnungen - zufällig verteilen
|
||||
const shuffled = members.slice();
|
||||
for (let i = shuffled.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
|
||||
}
|
||||
groups.forEach((g, idx) => {
|
||||
shuffled
|
||||
.filter((_, i) => i % groups.length === idx)
|
||||
.forEach(m => m.update({ groupId: g.id }));
|
||||
});
|
||||
}
|
||||
// 3) Alle Zuordnungen löschen und zufällig neu verteilen
|
||||
// (Bei "Zufällig verteilen" sollen alle alten Zuordnungen gelöscht werden)
|
||||
await TournamentMember.update(
|
||||
{ groupId: null },
|
||||
{ where: { tournamentId } }
|
||||
);
|
||||
|
||||
// 4) Round‑Robin anlegen wie gehabt - NUR innerhalb jeder Gruppe
|
||||
for (const g of groups) {
|
||||
// 4) Zufällig verteilen
|
||||
const shuffled = members.slice();
|
||||
for (let i = shuffled.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
|
||||
}
|
||||
|
||||
// Warte auf alle Updates, damit die Zuordnungen korrekt sind
|
||||
const updatePromises = [];
|
||||
groups.forEach((g, idx) => {
|
||||
const groupMembers = shuffled.filter((_, i) => i % groups.length === idx);
|
||||
groupMembers.forEach(m => {
|
||||
updatePromises.push(m.update({ groupId: g.id }));
|
||||
});
|
||||
});
|
||||
await Promise.all(updatePromises);
|
||||
|
||||
// 5) Round‑Robin anlegen wie gehabt - NUR innerhalb jeder Gruppe
|
||||
// Stelle sicher, dass Gruppen sortiert sind
|
||||
const sortedGroups = groups.sort((a, b) => a.id - b.id);
|
||||
|
||||
for (const g of sortedGroups) {
|
||||
const gm = await TournamentMember.findAll({ where: { groupId: g.id } });
|
||||
|
||||
if (gm.length < 2) {
|
||||
console.log(`⚠️ Gruppe ${g.id} hat weniger als 2 Spieler (${gm.length}), überspringe Spiele-Erstellung`);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -214,11 +216,10 @@ class TournamentService {
|
||||
|
||||
for (let roundIndex = 0; roundIndex < rounds.length; roundIndex++) {
|
||||
for (const [p1Id, p2Id] of rounds[roundIndex]) {
|
||||
// Prüfe, ob beide Spieler zur gleichen Gruppe gehören
|
||||
const p1 = gm.find(p => p.id === p1Id);
|
||||
const p2 = gm.find(p => p.id === p2Id);
|
||||
if (p1 && p2 && p1.groupId === p2.groupId && p1.groupId === g.id) {
|
||||
const match = await TournamentMatch.create({
|
||||
// p1Id und p2Id sind bereits aus gm, also müssen sie zur Gruppe g gehören
|
||||
// Prüfe nur, ob beide IDs vorhanden sind (nicht null, falls Bye)
|
||||
if (p1Id && p2Id) {
|
||||
await TournamentMatch.create({
|
||||
tournamentId,
|
||||
groupId: g.id,
|
||||
round: 'group',
|
||||
@@ -283,6 +284,29 @@ class TournamentService {
|
||||
return t;
|
||||
}
|
||||
|
||||
// Update Turnier (Name und Datum)
|
||||
async updateTournament(userToken, clubId, tournamentId, name, date) {
|
||||
await checkAccess(userToken, clubId);
|
||||
const tournament = await Tournament.findOne({ where: { id: tournamentId, clubId } });
|
||||
if (!tournament) {
|
||||
throw new Error('Turnier nicht gefunden');
|
||||
}
|
||||
|
||||
// Prüfe auf Duplikat, wenn Datum geändert wird
|
||||
if (date && date !== tournament.date) {
|
||||
const existing = await Tournament.findOne({ where: { clubId, date, id: { [Op.ne]: tournamentId } } });
|
||||
if (existing) {
|
||||
throw new Error('Ein Turnier mit diesem Datum existiert bereits');
|
||||
}
|
||||
}
|
||||
|
||||
if (name !== undefined) tournament.name = name;
|
||||
if (date !== undefined) tournament.date = date;
|
||||
|
||||
await tournament.save();
|
||||
return JSON.parse(JSON.stringify(tournament));
|
||||
}
|
||||
|
||||
// 11. Spiele eines Turniers
|
||||
async getTournamentMatches(userToken, clubId, tournamentId) {
|
||||
await checkAccess(userToken, clubId);
|
||||
@@ -296,8 +320,8 @@ class TournamentService {
|
||||
{ model: TournamentResult, as: 'tournamentResults' }
|
||||
],
|
||||
order: [
|
||||
['group_id', 'ASC'],
|
||||
['group_round', 'ASC'],
|
||||
['group_round', 'ASC'], // Zuerst nach Runde sortieren
|
||||
// group_id wird nicht sortiert, da die logische groupNumber im Frontend verwendet wird
|
||||
['id', 'ASC'],
|
||||
[{ model: TournamentResult, as: 'tournamentResults' }, 'set', 'ASC']
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user