diff --git a/backend/controllers/memberController.js b/backend/controllers/memberController.js index 36ddbc1..b146803 100644 --- a/backend/controllers/memberController.js +++ b/backend/controllers/memberController.js @@ -1,5 +1,6 @@ import MemberService from "../services/memberService.js"; import MemberTransferService from "../services/memberTransferService.js"; +import { emitMemberChanged } from '../services/socketService.js'; import { devLog } from '../utils/logger.js'; const getClubMembers = async(req, res) => { @@ -32,6 +33,12 @@ const setClubMembers = async (req, res) => { const { authcode: userToken } = req.headers; const addResult = await MemberService.setClubMember(userToken, clubId, memberId, firstName, lastName, street, city, postalCode, birthdate, phone, email, active, testMembership, picsInInternetAllowed, gender, ttr, qttr, memberFormHandedOver, contacts); + + // Emit Socket-Event wenn Member erfolgreich erstellt/aktualisiert wurde + if (addResult.status === 200) { + emitMemberChanged(clubId); + } + res.status(addResult.status || 500).json(addResult.response); } catch (error) { console.error('[setClubMembers] - Error:', error); diff --git a/backend/services/socketService.js b/backend/services/socketService.js index 7edfce6..a1e0238 100644 --- a/backend/services/socketService.js +++ b/backend/services/socketService.js @@ -104,3 +104,8 @@ export const emitActivityChanged = (clubId, dateId) => { emitToClub(clubId, 'activity:changed', { dateId }); }; +// Event für Member-Änderungen (erstellen, aktualisieren) +export const emitMemberChanged = (clubId) => { + emitToClub(clubId, 'member:changed', { clubId }); +}; + diff --git a/frontend/src/services/socketService.js b/frontend/src/services/socketService.js index ae1571c..2a3574a 100644 --- a/frontend/src/services/socketService.js +++ b/frontend/src/services/socketService.js @@ -150,6 +150,17 @@ export const onActivityChanged = (callback) => { } }; +export const onMemberChanged = (callback) => { + if (socket) { + socket.on('member:changed', (data) => { + console.log('📡 [Socket] member:changed empfangen:', data); + callback(data); + }); + } else { + console.warn('⚠️ [Socket] onMemberChanged: Socket nicht verbunden'); + } +}; + // Event-Listener entfernen export const offParticipantAdded = (callback) => { if (socket) { @@ -223,3 +234,9 @@ export const offActivityChanged = (callback) => { } }; +export const offMemberChanged = (callback) => { + if (socket) { + socket.off('member:changed', callback); + } +}; + diff --git a/frontend/src/views/DiaryView.vue b/frontend/src/views/DiaryView.vue index c1f8427..7684e37 100644 --- a/frontend/src/views/DiaryView.vue +++ b/frontend/src/views/DiaryView.vue @@ -579,6 +579,7 @@ import { onActivityMemberAdded, onActivityMemberRemoved, onActivityChanged, + onMemberChanged, offParticipantAdded, offParticipantRemoved, offParticipantUpdated, @@ -589,7 +590,8 @@ import { offDiaryDateUpdated, offActivityMemberAdded, offActivityMemberRemoved, - offActivityChanged + offActivityChanged, + offMemberChanged } from '../services/socketService.js'; export default { @@ -1054,7 +1056,9 @@ export default { async loadMembers() { const response = await apiClient.get(`/clubmembers/get/${this.currentClub}/false`); - this.members = response.data; + // Erstelle ein neues Array, um Vue-Reaktivität sicherzustellen + this.members = Array.isArray(response.data) ? [...response.data] : []; + console.log('📡 [DiaryView] loadMembers: Mitglieder geladen, Anzahl:', this.members?.length || 0); }, async loadParticipants(dateId) { @@ -1615,7 +1619,8 @@ export default { pdf.save('trainingsplan.pdf'); }, sortedMembers() { - return this.members.sort((a, b) => { + // Erstelle eine Kopie des Arrays, um Mutation zu vermeiden + return [...this.members].sort((a, b) => { const firstNameComparison = a.firstName.localeCompare(b.firstName); if (firstNameComparison === 0) { return a.lastName.localeCompare(b.lastName); @@ -2451,6 +2456,9 @@ export default { onActivityMemberAdded(this.handleActivityMemberAdded); onActivityMemberRemoved(this.handleActivityMemberRemoved); onActivityChanged(this.handleActivityChanged); + + // Event-Handler für Member-Änderungen + onMemberChanged(this.handleMemberChanged); console.log('✅ [DiaryView] Alle Event-Handler registriert'); }, @@ -2466,6 +2474,7 @@ export default { offActivityMemberAdded(this.handleActivityMemberAdded); offActivityMemberRemoved(this.handleActivityMemberRemoved); offActivityChanged(this.handleActivityChanged); + offMemberChanged(this.handleMemberChanged); }, async handleParticipantAdded(data) { @@ -2624,6 +2633,28 @@ export default { console.log('⚠️ [DiaryView] Datum stimmt nicht überein oder kein Datum ausgewählt'); } }, + + async handleMemberChanged(data) { + console.log('📡 [DiaryView] handleMemberChanged aufgerufen:', data); + console.log('📡 [DiaryView] Aktueller Club:', this.currentClub, 'Event Club:', data.clubId); + // Prüfe, ob der Club übereinstimmt + if (data.clubId && String(data.clubId) === String(this.currentClub)) { + console.log('✅ [DiaryView] Club stimmt überein, lade Mitgliederliste neu'); + console.log('📡 [DiaryView] Aktuelle Mitgliederanzahl vor Reload:', this.members?.length || 0); + // Lade Mitgliederliste neu + try { + await this.loadMembers(); + console.log('✅ [DiaryView] Mitgliederliste neu geladen, neue Anzahl:', this.members?.length || 0); + console.log('📡 [DiaryView] Mitgliederliste:', this.members); + // Force Vue update + this.$forceUpdate(); + } catch (error) { + console.error('❌ [DiaryView] Fehler beim Neuladen der Mitgliederliste:', error); + } + } else { + console.log('⚠️ [DiaryView] Club stimmt nicht überein - Event Club:', data.clubId, 'Aktueller Club:', this.currentClub); + } + }, }, async mounted() { await this.init();