From c7d51efb5dfdef9454348caff054a76c4234f9da Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Wed, 25 Mar 2026 18:43:52 +0100 Subject: [PATCH] feat(MatchReportApiDialog): implement meeting details polling functionality - Added methods to start and stop polling for meeting details at regular intervals. - Introduced logic to build a signature for meeting details to detect changes. - Enhanced data handling to update meeting information based on the latest fetched details. - Improved error handling during polling to ensure robustness in data retrieval. --- .../src/components/MatchReportApiDialog.vue | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/frontend/src/components/MatchReportApiDialog.vue b/frontend/src/components/MatchReportApiDialog.vue index 80cecd58..82f02479 100644 --- a/frontend/src/components/MatchReportApiDialog.vue +++ b/frontend/src/components/MatchReportApiDialog.vue @@ -752,6 +752,9 @@ export default { // Aktive Zelle der schwebenden Satz-Tastatur: { matchIndex, setIndex } oder null editingSetCell: null, broadcastDraftTimer: null, + meetingDetailsPollInterval: null, + isMeetingDetailsPolling: false, + lastMeetingDetailsSignature: '', // Abschluss-Felder protestText: '', finalHomePin: '', @@ -912,6 +915,7 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr await this.loadData(); this.initializeResults(); this.initializeFinalPins(); + this.startMeetingDetailsPolling(); this._matchReportSubmittedHandler = (payload) => { if (!payload?.matchCode || !this.match?.code || String(payload.matchCode) !== String(this.match.code)) { return; @@ -928,6 +932,7 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr if (this._matchReportSubmittedHandler) { offMatchReportSubmitted(this._matchReportSubmittedHandler); } + this.stopMeetingDetailsPolling(); if (this.broadcastDraftTimer) { clearTimeout(this.broadcastDraftTimer); } @@ -978,6 +983,118 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr } }, methods: { + startMeetingDetailsPolling() { + this.stopMeetingDetailsPolling(); + this.meetingDetailsPollInterval = setInterval(() => { + this.pollLatestMeetingDetails(); + }, 15000); + }, + stopMeetingDetailsPolling() { + if (this.meetingDetailsPollInterval) { + clearInterval(this.meetingDetailsPollInterval); + this.meetingDetailsPollInterval = null; + } + }, + buildMeetingDetailsSignature(details) { + if (!details || typeof details !== 'object') { + return ''; + } + + const normalizePlayer = (player) => ({ + nuLigaPersonId: player?.nuLigaPersonId ?? null, + firstName: player?.firstName ?? player?.firstname ?? '', + lastName: player?.lastName ?? player?.lastname ?? '', + isSelected: Boolean(player?.isSelected), + rank: player?.rank ?? null, + positionSingle: player?.positionSingle ?? null, + positionDouble: player?.positionDouble ?? null, + positions: Array.isArray(player?.positions) ? [...player.positions] : [] + }); + + const normalizeMatch = (match) => ({ + name: match?.name ?? '', + homePlayer: match?.homePlayer ?? '', + guestPlayer: match?.guestPlayer ?? '', + matchesA: match?.matchesA ?? null, + matchesB: match?.matchesB ?? null, + set1A: match?.set1A ?? null, + set1B: match?.set1B ?? null, + set2A: match?.set2A ?? null, + set2B: match?.set2B ?? null, + set3A: match?.set3A ?? null, + set3B: match?.set3B ?? null, + set4A: match?.set4A ?? null, + set4B: match?.set4B ?? null, + set5A: match?.set5A ?? null, + set5B: match?.set5B ?? null + }); + + return JSON.stringify({ + isCompleted: details.isCompleted ?? null, + wo: details.wo ?? null, + startDate: details.startDate ?? null, + endDate: details.endDate ?? null, + homePin: details.homePin ?? null, + guestPin: details.guestPin ?? null, + signature: details.signature ?? null, + teamLineupHomePlayers: Array.isArray(details.teamLineupHomePlayers) + ? details.teamLineupHomePlayers.map(normalizePlayer) + : [], + teamLineupGuestPlayers: Array.isArray(details.teamLineupGuestPlayers) + ? details.teamLineupGuestPlayers.map(normalizePlayer) + : [], + matches: Array.isArray(details.matches) ? details.matches.map(normalizeMatch) : [] + }); + }, + async pollLatestMeetingDetails() { + if (this.loading || this.isMeetingDetailsPolling) { + return; + } + + const meetingUuid = this.meetingData?.nuLigaMeetingUuid; + if (!meetingUuid) { + return; + } + + this.isMeetingDetailsPolling = true; + try { + const response = await fetch(`${backendBaseUrl}/api/nuscore/meetingdetails/${meetingUuid}`); + if (!response.ok) { + return; + } + + const latestMeetingDetails = await response.json(); + const latestSignature = this.buildMeetingDetailsSignature(latestMeetingDetails); + + if (latestSignature === this.lastMeetingDetailsSignature) { + return; + } + + this.lastMeetingDetailsSignature = latestSignature; + this.meetingDetails = latestMeetingDetails; + + if (latestMeetingDetails.startDate != null && this.meetingData) { + this.meetingData.startDate = latestMeetingDetails.startDate; + } + if (latestMeetingDetails.endDate != null && this.meetingData) { + this.meetingData.endDate = latestMeetingDetails.endDate; + } + + this.initialCompletionState = Boolean( + ((typeof latestMeetingDetails?.isCompleted === 'boolean' && latestMeetingDetails.isCompleted) && + this.hasReleaseSignatureForCompletion(latestMeetingDetails)) || + ((typeof this.meetingData?.isCompleted === 'boolean' && this.meetingData.isCompleted) && + this.hasReleaseSignatureForCompletion(this.meetingData)) + ); + + this.populateResultsFromMeetingDetails(); + this.applyLineupCertificationFromMeetingDetails(); + } catch (error) { + console.warn('⚠️ Polling der Meeting-Details fehlgeschlagen:', error); + } finally { + this.isMeetingDetailsPolling = false; + } + }, logBraunschweigerDebugSnapshot(context, payload = this.meetingDetails) { if (!payload || typeof payload !== 'object') { console.log(`[Braunschweiger Debug] ${context}: keine Daten`); @@ -2213,6 +2330,7 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr const detailsResponse = await fetch(`${backendBaseUrl}/api/nuscore/meetingdetails/${this.meetingData.nuLigaMeetingUuid}`); if (detailsResponse.ok) { this.meetingDetails = await detailsResponse.json(); + this.lastMeetingDetailsSignature = this.buildMeetingDetailsSignature(this.meetingDetails); console.log('[nuscore] /meetingdetails response:', this.meetingDetails); this.logBraunschweigerDebugSnapshot('Server /meetingdetails'); }