feat(Tournament): add official tournament participation feature
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 43s
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 43s
- Introduced functionality to load and display official tournament participation events in the CalendarView. - Updated the API client to fetch official tournament data, enhancing the event management capabilities. - Added new UI elements to represent official tournaments, including visual indicators and event details. - Enhanced the ClubManager to support fetching and managing official tournament data. - Updated the mobile app's TODO list to reflect progress on tournament-related features.
This commit is contained in:
@@ -138,6 +138,7 @@ export default {
|
||||
activeTypes: {
|
||||
training: true,
|
||||
tournament: true,
|
||||
officialTournament: true,
|
||||
match: true,
|
||||
holiday: true,
|
||||
schoolHoliday: true,
|
||||
@@ -160,6 +161,7 @@ export default {
|
||||
return [
|
||||
{ key: 'training', label: 'Training' },
|
||||
{ key: 'tournament', label: 'Turnier' },
|
||||
{ key: 'officialTournament', label: 'Teilnahme' },
|
||||
{ key: 'match', label: 'Punktspiel' },
|
||||
{ key: 'holiday', label: 'Feiertag' },
|
||||
{ key: 'schoolHoliday', label: 'Ferien' },
|
||||
@@ -188,7 +190,7 @@ export default {
|
||||
return this.events.reduce((counts, event) => {
|
||||
counts[event.type] = (counts[event.type] || 0) + 1;
|
||||
return counts;
|
||||
}, { training: 0, tournament: 0, match: 0, holiday: 0, schoolHoliday: 0, trainingCancellation: 0 });
|
||||
}, { training: 0, tournament: 0, officialTournament: 0, match: 0, holiday: 0, schoolHoliday: 0, trainingCancellation: 0 });
|
||||
},
|
||||
visibleTrainingCancellations() {
|
||||
const month = this.cursor.getMonth();
|
||||
@@ -253,6 +255,7 @@ export default {
|
||||
this.loadSource('Trainingszeiten', () => this.loadRecurringTrainingEvents()),
|
||||
this.loadSource('Trainingsausfälle', () => this.loadTrainingCancellationEvents()),
|
||||
this.loadSource('Turniere', () => this.loadTournamentEvents()),
|
||||
this.loadSource('Turnierteilnahmen', () => this.loadOfficialTournamentEvents()),
|
||||
this.loadSource('Punktspiele', () => this.loadMatchEvents()),
|
||||
this.loadSource('Ferien/Feiertage', () => this.loadHolidayEvents())
|
||||
]);
|
||||
@@ -435,6 +438,31 @@ export default {
|
||||
};
|
||||
});
|
||||
},
|
||||
async loadOfficialTournamentEvents() {
|
||||
const response = await apiClient.get(`/official-tournaments/${this.currentClub}/participations/summary`);
|
||||
this.ensureSuccess(response, 'Turnierteilnahmen');
|
||||
return (response.data || [])
|
||||
.filter(tournament => Array.isArray(tournament.entries) && tournament.entries.length > 0)
|
||||
.map(tournament => {
|
||||
const date = this.parseDmyDate(tournament.startDate);
|
||||
const endDate = this.parseDmyDate(tournament.endDate || tournament.startDate);
|
||||
if (!date) return null;
|
||||
const entries = tournament.entries || [];
|
||||
const participantCount = new Set(entries.map(entry => entry.memberId).filter(Boolean)).size;
|
||||
return {
|
||||
id: `official-tournament-${tournament.tournamentId}`,
|
||||
type: 'officialTournament',
|
||||
date,
|
||||
endDate: endDate || date,
|
||||
startsAt: this.combineDateTime(date),
|
||||
time: '',
|
||||
title: tournament.tournamentName || tournament.title || 'Turnierteilnahme',
|
||||
subtitle: participantCount > 0 ? `${participantCount} Teilnehmer` : `${entries.length} Starts`,
|
||||
route: '/tournament-participations'
|
||||
};
|
||||
})
|
||||
.filter(Boolean);
|
||||
},
|
||||
async loadHolidayEvents() {
|
||||
const response = await apiClient.get(`/calendar/club/${this.currentClub}/holidays`, {
|
||||
params: { year: this.displayedYear }
|
||||
@@ -483,6 +511,12 @@ export default {
|
||||
if (!year || !month || !day) return new Date(value);
|
||||
return new Date(year, month - 1, day);
|
||||
},
|
||||
parseDmyDate(value) {
|
||||
const match = String(value || '').match(/(\d{1,2})\.(\d{1,2})\.(\d{4})/);
|
||||
if (!match) return null;
|
||||
const date = new Date(Number(match[3]), Number(match[2]) - 1, Number(match[1]));
|
||||
return Number.isNaN(date.getTime()) ? null : date;
|
||||
},
|
||||
combineDateTime(date, time) {
|
||||
if (!date) return Number.POSITIVE_INFINITY;
|
||||
const result = new Date(date);
|
||||
@@ -659,6 +693,7 @@ export default {
|
||||
|
||||
.legend-training::before { background: #2f7a5f; }
|
||||
.legend-tournament::before { background: #b7791f; }
|
||||
.legend-officialTournament::before { background: #9333ea; }
|
||||
.legend-match::before { background: #2563eb; }
|
||||
.legend-holiday::before { background: #dc2626; }
|
||||
.legend-schoolHoliday::before { background: #7c3aed; }
|
||||
@@ -823,6 +858,7 @@ export default {
|
||||
|
||||
.event-training { background: #e8f4ef; border-left: 4px solid #2f7a5f; }
|
||||
.event-tournament { background: #fff7e6; border-left: 4px solid #b7791f; }
|
||||
.event-officialTournament { background: #f3e8ff; border-left: 4px solid #9333ea; }
|
||||
.event-match { background: #eaf1ff; border-left: 4px solid #2563eb; }
|
||||
.event-holiday { background: #fee2e2; border-left: 4px solid #dc2626; }
|
||||
.event-schoolHoliday { background: #f3e8ff; border-left: 4px solid #7c3aed; }
|
||||
|
||||
Reference in New Issue
Block a user