diff --git a/backend/controllers/officialTournamentController.js b/backend/controllers/officialTournamentController.js index 679642e4..99b3ab53 100755 --- a/backend/controllers/officialTournamentController.js +++ b/backend/controllers/officialTournamentController.js @@ -2,6 +2,20 @@ import { checkAccess } from '../utils/userUtils.js'; import officialTournamentService from '../services/officialTournamentService.js'; import clickTtTournamentRegistrationService from '../services/clickTtTournamentRegistrationService.js'; +export const saveTournamentSuggestion = async (req, res) => { + try { + const { authcode: userToken } = req.headers; + const { clubId, id } = req.params; + await checkAccess(userToken, clubId); + const result = await officialTournamentService.saveTournamentSuggestion(clubId, id); + if (!result) return res.status(404).json({ error: 'Turniervorschlag nicht gefunden.' }); + return res.status(result.created ? 201 : 200).json(result); + } catch (error) { + console.error('[saveTournamentSuggestion] Error:', error); + return res.status(error.status || 500).json({ error: error.message || 'Turniervorschlag konnte nicht gespeichert werden.' }); + } +}; + export const updateOfficialTournament = async (req, res) => { try { const { authcode: userToken } = req.headers; diff --git a/backend/routes/officialTournamentRoutes.js b/backend/routes/officialTournamentRoutes.js index 787c584a..05a5babf 100755 --- a/backend/routes/officialTournamentRoutes.js +++ b/backend/routes/officialTournamentRoutes.js @@ -11,7 +11,7 @@ import { listClubParticipations, updateParticipantStatus, autoRegisterOfficialTournamentParticipants - , listTacticPlans, saveTacticPlan, deleteTacticPlan + , listTacticPlans, saveTacticPlan, deleteTacticPlan, saveTournamentSuggestion } from '../controllers/officialTournamentController.js'; import { fetchTournamentSuggestions, listTournamentSuggestions, updateTournamentSuggestion } from '../controllers/tournamentSuggestionController.js'; @@ -23,6 +23,7 @@ router.use(authenticate); router.get('/:clubId', listOfficialTournaments); router.get('/:clubId/suggestions', listTournamentSuggestions); router.post('/:clubId/suggestions/fetch', fetchTournamentSuggestions); +router.post('/:clubId/suggestions/:id/save', saveTournamentSuggestion); router.patch('/:clubId/suggestions/:id', updateTournamentSuggestion); router.get('/:clubId/participations/summary', listClubParticipations); router.post('/:clubId/upload', upload.single('pdf'), uploadTournamentPdf); diff --git a/backend/services/officialTournamentService.js b/backend/services/officialTournamentService.js index 86c695d0..0573cbd3 100755 --- a/backend/services/officialTournamentService.js +++ b/backend/services/officialTournamentService.js @@ -7,10 +7,36 @@ import OfficialTournament from '../models/OfficialTournament.js'; import OfficialCompetition from '../models/OfficialCompetition.js'; import OfficialCompetitionMember from '../models/OfficialCompetitionMember.js'; import OfficialTournamentTacticPlan from '../models/OfficialTournamentTacticPlan.js'; +import TournamentSuggestion from '../models/TournamentSuggestion.js'; import Member from '../models/Member.js'; import OfficialTournamentParserService from './officialTournamentParserService.js'; class OfficialTournamentService { + async saveTournamentSuggestion(clubId, suggestionId) { + const suggestion = await TournamentSuggestion.findOne({ where: { id: suggestionId, clubId } }); + if (!suggestion) return null; + + let tournament = await OfficialTournament.findOne({ + where: { clubId, title: suggestion.title, eventDate: suggestion.eventDate }, + }); + const created = !tournament; + if (!tournament) { + tournament = await OfficialTournament.create({ + clubId, + title: suggestion.title, + eventDate: suggestion.eventDate, + organizer: suggestion.organizer, + host: suggestion.organizer, + venues: JSON.stringify(suggestion.location ? [suggestion.location] : []), + competitionTypes: JSON.stringify([]), + registrationDeadlines: JSON.stringify([]), + entryFees: JSON.stringify({}), + }); + } + await suggestion.update({ status: 'reviewed' }); + return { id: String(tournament.id), created }; + } + async listTacticPlans(clubId, tournamentId) { const tournament = await OfficialTournament.findOne({ where: { id: tournamentId, clubId } }); if (!tournament) return null; diff --git a/frontend/src/views/OfficialTournaments.vue b/frontend/src/views/OfficialTournaments.vue index f73324f9..ff1713e6 100755 --- a/frontend/src/views/OfficialTournaments.vue +++ b/frontend/src/views/OfficialTournaments.vue @@ -32,7 +32,7 @@

{{ suggestionError }}

{{ suggestionSearch ? 'Keine passenden Turniervorschläge gefunden.' : 'Keine Turniervorschläge in dieser Ansicht. „Jetzt abrufen“ aktualisiert den Kalender.' }}

@@ -1642,6 +1642,15 @@ export default { try { await apiClient.patch(`/official-tournaments/${this.currentClub}/suggestions/${suggestion.id}`, { status }); await this.loadSuggestions(); } catch (error) { this.suggestionError = getSafeErrorMessage(error, 'Der Vorschlag konnte nicht aktualisiert werden.'); } }, + async saveSuggestion(suggestion) { + this.suggestionError = ''; + try { + const response = await apiClient.post(`/official-tournaments/${this.currentClub}/suggestions/${suggestion.id}/save`); + await Promise.all([this.loadSuggestions(), this.loadList()]); + this.uploadedId = String(response.data.id); + this.workspaceTab = 'saved'; + } catch (error) { this.suggestionError = getSafeErrorMessage(error, 'Der Vorschlag konnte nicht gespeichert werden.'); } + }, buildParticipationMap(entries) { const map = {}; for (const e of entries) {