Fügt die Methode listClubParticipations im OfficialTournamentController hinzu, um die Teilnahme von Mitgliedern an offiziellen Turnieren zu listen. Aktualisiert die Routen, um diese neue Funktionalität zu integrieren. Verbessert die Benutzeroberfläche in OfficialTournaments.vue mit Tabs zur Anzeige von Veranstaltungen und Turnierbeteiligungen sowie einer Filteroption für den Zeitraum der Beteiligungen.
This commit is contained in:
@@ -5,6 +5,8 @@ import { checkAccess } from '../utils/userUtils.js';
|
||||
import OfficialTournament from '../models/OfficialTournament.js';
|
||||
import OfficialCompetition from '../models/OfficialCompetition.js';
|
||||
import OfficialCompetitionMember from '../models/OfficialCompetitionMember.js';
|
||||
import Member from '../models/Member.js';
|
||||
import { Op } from 'sequelize';
|
||||
|
||||
// In-Memory Store (einfacher Start); später DB-Modell
|
||||
const parsedTournaments = new Map(); // key: id, value: { id, clubId, rawText, parsedData }
|
||||
@@ -170,6 +172,110 @@ export const listOfficialTournaments = async (req, res) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const listClubParticipations = async (req, res) => {
|
||||
try {
|
||||
const { authcode: userToken } = req.headers;
|
||||
const { clubId } = req.params;
|
||||
await checkAccess(userToken, clubId);
|
||||
const tournaments = await OfficialTournament.findAll({ where: { clubId } });
|
||||
if (!tournaments || tournaments.length === 0) return res.status(200).json([]);
|
||||
const tournamentIds = tournaments.map(t => t.id);
|
||||
|
||||
const rows = await OfficialCompetitionMember.findAll({
|
||||
where: { tournamentId: { [Op.in]: tournamentIds }, participated: true },
|
||||
include: [
|
||||
{ model: OfficialCompetition, as: 'competition', attributes: ['id', 'tournamentId', 'ageClassCompetition', 'startTime'] },
|
||||
{ model: OfficialTournament, as: 'tournament', attributes: ['id', 'title', 'eventDate'] },
|
||||
{ model: Member, as: 'member', attributes: ['id', 'firstName', 'lastName'] },
|
||||
]
|
||||
});
|
||||
|
||||
const parseDmy = (s) => {
|
||||
if (!s) return null;
|
||||
const m = String(s).match(/(\d{1,2})\.(\d{1,2})\.(\d{4})/);
|
||||
if (!m) return null;
|
||||
const d = new Date(Number(m[3]), Number(m[2]) - 1, Number(m[1]));
|
||||
return isNaN(d.getTime()) ? null : d;
|
||||
};
|
||||
const fmtDmy = (d) => {
|
||||
const dd = String(d.getDate()).padStart(2, '0');
|
||||
const mm = String(d.getMonth() + 1).padStart(2, '0');
|
||||
const yyyy = d.getFullYear();
|
||||
return `${dd}.${mm}.${yyyy}`;
|
||||
};
|
||||
|
||||
const byTournament = new Map();
|
||||
for (const r of rows) {
|
||||
const t = r.tournament;
|
||||
const c = r.competition;
|
||||
const m = r.member;
|
||||
if (!t || !c || !m) continue;
|
||||
if (!byTournament.has(t.id)) {
|
||||
byTournament.set(t.id, {
|
||||
tournamentId: String(t.id),
|
||||
title: t.title || null,
|
||||
startDate: null,
|
||||
endDate: null,
|
||||
entries: [],
|
||||
_dates: [],
|
||||
_eventDate: t.eventDate || null,
|
||||
});
|
||||
}
|
||||
const bucket = byTournament.get(t.id);
|
||||
const compDate = parseDmy(c.startTime || '') || null;
|
||||
if (compDate) bucket._dates.push(compDate);
|
||||
bucket.entries.push({
|
||||
memberId: m.id,
|
||||
memberName: `${m.firstName || ''} ${m.lastName || ''}`.trim(),
|
||||
competitionId: c.id,
|
||||
competitionName: c.ageClassCompetition || '',
|
||||
placement: r.placement || null,
|
||||
date: compDate ? fmtDmy(compDate) : null,
|
||||
});
|
||||
}
|
||||
|
||||
const out = [];
|
||||
for (const t of tournaments) {
|
||||
const bucket = byTournament.get(t.id) || {
|
||||
tournamentId: String(t.id),
|
||||
title: t.title || null,
|
||||
startDate: null,
|
||||
endDate: null,
|
||||
entries: [],
|
||||
_dates: [],
|
||||
_eventDate: t.eventDate || null,
|
||||
};
|
||||
// Ableiten Start/Ende
|
||||
if (bucket._dates.length) {
|
||||
bucket._dates.sort((a, b) => a - b);
|
||||
bucket.startDate = fmtDmy(bucket._dates[0]);
|
||||
bucket.endDate = fmtDmy(bucket._dates[bucket._dates.length - 1]);
|
||||
} else if (bucket._eventDate) {
|
||||
const all = String(bucket._eventDate).match(/(\d{1,2}\.\d{1,2}\.\d{4})/g) || [];
|
||||
if (all.length >= 1) {
|
||||
const d1 = parseDmy(all[0]);
|
||||
const d2 = all.length >= 2 ? parseDmy(all[1]) : d1;
|
||||
if (d1) bucket.startDate = fmtDmy(d1);
|
||||
if (d2) bucket.endDate = fmtDmy(d2);
|
||||
}
|
||||
}
|
||||
// Sort entries: Mitglied, dann Konkurrenz
|
||||
bucket.entries.sort((a, b) => {
|
||||
const mcmp = (a.memberName || '').localeCompare(b.memberName || '', 'de', { sensitivity: 'base' });
|
||||
if (mcmp !== 0) return mcmp;
|
||||
return (a.competitionName || '').localeCompare(b.competitionName || '', 'de', { sensitivity: 'base' });
|
||||
});
|
||||
delete bucket._dates;
|
||||
delete bucket._eventDate;
|
||||
out.push(bucket);
|
||||
}
|
||||
|
||||
res.status(200).json(out);
|
||||
} catch (e) {
|
||||
res.status(500).json({ error: 'Failed to list club participations' });
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteOfficialTournament = async (req, res) => {
|
||||
try {
|
||||
const { authcode: userToken } = req.headers;
|
||||
|
||||
Reference in New Issue
Block a user