Enhance participant update handling and UI responsiveness in DiaryView
This commit improves the participant update process by ensuring the latest participant data is fetched from the database before emitting socket events. It also refines the DiaryView component's UI, adding better handling for dropdowns and member group selections, enhancing user experience. Additionally, new CSS styles are introduced for member group select elements to ensure consistent appearance across browsers.
This commit is contained in:
@@ -77,7 +77,12 @@ export const onParticipantRemoved = (callback) => {
|
||||
|
||||
export const onParticipantUpdated = (callback) => {
|
||||
if (socket) {
|
||||
socket.on('participant:updated', callback);
|
||||
socket.on('participant:updated', (data) => {
|
||||
console.log('📡 [Socket] participant:updated empfangen:', data);
|
||||
callback(data);
|
||||
});
|
||||
} else {
|
||||
console.warn('⚠️ [Socket] onParticipantUpdated: Socket nicht verbunden');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -189,37 +189,39 @@
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<button v-if="!item.isTimeblock" @click="toggleActivityMembers(item)" title="Teilnehmer zuordnen"
|
||||
class="person-btn">👤</button>
|
||||
<button v-if="item.isTimeblock" @click="addGroupActivityToTimeblock(item.id)" title="Gruppen-Aktivität hinzufügen"
|
||||
class="btn-primary" style="font-size: 12px; padding: 2px 6px;">+ Gruppe</button>
|
||||
<button @click="removePlanItem(item.id)" class="trash-btn">🗑️</button>
|
||||
<div v-if="activityMembersOpenId === item.id" class="dropdown"
|
||||
style="max-height: 12em; padding: 0.25rem;">
|
||||
<div style="margin-bottom: 0.25rem; font-weight: 600; display: flex; align-items: center; gap: 0.5rem;">
|
||||
<span>Teilnehmer zuordnen</span>
|
||||
<button @click="assignAllMembersToActivity(item.id)"
|
||||
style="font-size: 10px; padding: 1px 4px; background: #28a745; color: white; border: none; border-radius: 2px;">
|
||||
Alle
|
||||
</button>
|
||||
<select v-if="groups.length > 0"
|
||||
@change="assignGroupToActivity(item.id, $event.target.value)"
|
||||
style="font-size: 10px; width: 80px;">
|
||||
<option value="">Gruppe...</option>
|
||||
<option v-for="group in groups" :key="group.id" :value="String(group.id)">
|
||||
{{ group.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div style="max-height: 9.5em; overflow-y: auto;">
|
||||
<label v-for="m in presentMembers" :key="m.id"
|
||||
style="display:flex; align-items:center; gap:0.5rem;">
|
||||
<input type="checkbox"
|
||||
:checked="isAssignedToActivity(item.id, m.id)"
|
||||
@change="toggleMemberForActivity(item.id, m.id, $event.target.checked)">
|
||||
<span>{{ m.firstName }} {{ m.lastName }}</span>
|
||||
</label>
|
||||
<div style="position: relative; display: inline-block;">
|
||||
<button v-if="!item.isTimeblock" @click="toggleActivityMembers(item)" title="Teilnehmer zuordnen"
|
||||
class="person-btn">👤</button>
|
||||
<button v-if="item.isTimeblock" @click="addGroupActivityToTimeblock(item.id)" title="Gruppen-Aktivität hinzufügen"
|
||||
class="btn-primary" style="font-size: 12px; padding: 2px 6px;">+ Gruppe</button>
|
||||
<button @click="removePlanItem(item.id)" class="trash-btn">🗑️</button>
|
||||
<div v-if="activityMembersOpenId === item.id" class="dropdown"
|
||||
style="max-height: 12em; padding: 0.25rem;">
|
||||
<div style="margin-bottom: 0.25rem; font-weight: 600; display: flex; align-items: center; gap: 0.5rem;">
|
||||
<span>Teilnehmer zuordnen</span>
|
||||
<button @click="assignAllMembersToActivity(item.id)"
|
||||
style="font-size: 10px; padding: 1px 4px; background: #28a745; color: white; border: none; border-radius: 2px;">
|
||||
Alle
|
||||
</button>
|
||||
<select v-if="groups.length > 0"
|
||||
@change="assignGroupToActivity(item.id, $event.target.value)"
|
||||
style="font-size: 10px; width: 80px;">
|
||||
<option value="">Gruppe...</option>
|
||||
<option v-for="group in groups" :key="group.id" :value="String(group.id)">
|
||||
{{ group.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div style="max-height: 9.5em; overflow-y: auto;">
|
||||
<label v-for="m in presentMembers" :key="m.id"
|
||||
style="display:flex; align-items:center; gap:0.5rem;">
|
||||
<input type="checkbox"
|
||||
:checked="isAssignedToActivity(item.id, m.id)"
|
||||
@change="toggleMemberForActivity(item.id, m.id, $event.target.checked)">
|
||||
<span>{{ m.firstName }} {{ m.lastName }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
@@ -277,11 +279,12 @@
|
||||
<td>{{ groupItem.groupsGroupActivity.name }}</td>
|
||||
<td></td>
|
||||
<td>
|
||||
<button @click="toggleGroupActivityMembers(groupItem)" title="Teilnehmer zuordnen"
|
||||
class="person-btn">👤</button>
|
||||
<button @click="removeGroupActivity(groupItem.id)" class="trash-btn" title="Löschen">🗑️</button>
|
||||
<div v-if="groupActivityMembersOpenId === groupItem.id" class="dropdown"
|
||||
style="max-height: 12em; padding: 0.25rem;">
|
||||
<div style="position: relative; display: inline-block;">
|
||||
<button @click="toggleGroupActivityMembers(groupItem)" title="Teilnehmer zuordnen"
|
||||
class="person-btn">👤</button>
|
||||
<button @click="removeGroupActivity(groupItem.id)" class="trash-btn" title="Löschen">🗑️</button>
|
||||
<div v-if="groupActivityMembersOpenId === groupItem.id" class="dropdown"
|
||||
style="max-height: 12em; padding: 0.25rem;">
|
||||
<div style="margin-bottom: 0.25rem; font-weight: 600; display: flex; align-items: center; gap: 0.5rem;">
|
||||
<span>Teilnehmer zuordnen</span>
|
||||
<button @click="assignAllMembersToGroupActivity(groupItem.id)"
|
||||
@@ -307,6 +310,7 @@
|
||||
<span>{{ m.firstName }} {{ m.lastName }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -424,10 +428,11 @@
|
||||
<div class="participant-actions">
|
||||
<!-- Gruppenzuordnung für aktive Teilnehmer -->
|
||||
<select v-if="isParticipant(member.id) && groups.length > 0"
|
||||
:key="`group-select-${member.id}-${getMemberGroup(member.id)}`"
|
||||
:value="getMemberGroup(member.id)"
|
||||
@change="updateMemberGroup(member.id, $event.target.value)"
|
||||
@input="updateMemberGroup(member.id, $event.target.value)"
|
||||
style="margin-left: 10px; font-size: 8px; width: 5em;">
|
||||
class="member-group-select"
|
||||
style="margin-left: 10px; font-size: 10px; width: 5em; padding: 2px 4px; border: 1px solid #ccc; border-radius: 3px; background-color: white; color: #333;">
|
||||
<option value="">-</option>
|
||||
<option v-for="group in groups" :key="group.id" :value="String(group.id)">
|
||||
{{ group.name }}
|
||||
@@ -513,10 +518,11 @@
|
||||
<div class="participant-actions">
|
||||
<!-- Gruppenzuordnung für aktive Teilnehmer -->
|
||||
<select v-if="isParticipant(member.id) && groups.length > 0"
|
||||
:key="`group-select-${member.id}-${getMemberGroup(member.id)}`"
|
||||
:value="getMemberGroup(member.id)"
|
||||
@change="updateMemberGroup(member.id, $event.target.value)"
|
||||
@input="updateMemberGroup(member.id, $event.target.value)"
|
||||
style="margin-left: 10px; font-size: 8px; width: 5em;">
|
||||
class="member-group-select"
|
||||
style="margin-left: 10px; font-size: 10px; width: 5em; padding: 2px 4px; border: 1px solid #ccc; border-radius: 3px; background-color: white; color: #333;">
|
||||
<option value="">-</option>
|
||||
<option v-for="group in groups" :key="group.id" :value="String(group.id)">
|
||||
{{ group.name }}
|
||||
@@ -2198,12 +2204,29 @@ export default {
|
||||
},
|
||||
|
||||
async toggleActivityMembers(item) {
|
||||
console.log('🔍 [toggleActivityMembers] Aufgerufen für item.id:', item.id);
|
||||
console.log('🔍 [toggleActivityMembers] Aktuelle activityMembersOpenId:', this.activityMembersOpenId);
|
||||
|
||||
if (this.activityMembersOpenId === item.id) {
|
||||
console.log('🔍 [toggleActivityMembers] Schließe Dropdown');
|
||||
this.activityMembersOpenId = null;
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('🔍 [toggleActivityMembers] Öffne Dropdown für item.id:', item.id);
|
||||
this.activityMembersOpenId = item.id;
|
||||
|
||||
// Verwende $set für Vue 2 Reaktivität
|
||||
if (this.$set) {
|
||||
this.$set(this, 'activityMembersOpenId', item.id);
|
||||
}
|
||||
|
||||
await this.ensureActivityMembersLoaded(item.id);
|
||||
|
||||
// Force update um sicherzustellen, dass das Dropdown angezeigt wird
|
||||
await this.$nextTick();
|
||||
this.$forceUpdate();
|
||||
console.log('🔍 [toggleActivityMembers] Dropdown sollte jetzt sichtbar sein');
|
||||
},
|
||||
|
||||
async ensureActivityMembersLoaded(activityId) {
|
||||
@@ -2327,12 +2350,29 @@ export default {
|
||||
|
||||
// Group Activity Members Methods
|
||||
async toggleGroupActivityMembers(groupItem) {
|
||||
console.log('🔍 [toggleGroupActivityMembers] Aufgerufen für groupItem.id:', groupItem.id);
|
||||
console.log('🔍 [toggleGroupActivityMembers] Aktuelle groupActivityMembersOpenId:', this.groupActivityMembersOpenId);
|
||||
|
||||
if (this.groupActivityMembersOpenId === groupItem.id) {
|
||||
console.log('🔍 [toggleGroupActivityMembers] Schließe Dropdown');
|
||||
this.groupActivityMembersOpenId = null;
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('🔍 [toggleGroupActivityMembers] Öffne Dropdown für groupItem.id:', groupItem.id);
|
||||
this.groupActivityMembersOpenId = groupItem.id;
|
||||
|
||||
// Verwende $set für Vue 2 Reaktivität
|
||||
if (this.$set) {
|
||||
this.$set(this, 'groupActivityMembersOpenId', groupItem.id);
|
||||
}
|
||||
|
||||
await this.ensureGroupActivityMembersLoaded(groupItem.id);
|
||||
|
||||
// Force update um sicherzustellen, dass das Dropdown angezeigt wird
|
||||
await this.$nextTick();
|
||||
this.$forceUpdate();
|
||||
console.log('🔍 [toggleGroupActivityMembers] Dropdown sollte jetzt sichtbar sein');
|
||||
},
|
||||
|
||||
async ensureGroupActivityMembersLoaded(groupActivityId) {
|
||||
@@ -2425,8 +2465,14 @@ export default {
|
||||
|
||||
// Gruppenzuordnung für Teilnehmer
|
||||
getMemberGroup(memberId) {
|
||||
const value = this.memberGroupsMap ? this.memberGroupsMap[memberId] : undefined;
|
||||
return value !== undefined && value !== null ? String(value) : '';
|
||||
if (!this.memberGroupsMap) {
|
||||
return '';
|
||||
}
|
||||
const value = this.memberGroupsMap[memberId];
|
||||
if (value === undefined || value === null) {
|
||||
return '';
|
||||
}
|
||||
return String(value);
|
||||
},
|
||||
|
||||
async updateMemberGroup(memberId, groupId) {
|
||||
@@ -2605,16 +2651,41 @@ export default {
|
||||
|
||||
async handleParticipantUpdated(data) {
|
||||
// Nur aktualisieren, wenn das aktuelle Datum betroffen ist
|
||||
if (this.date && this.date !== 'new' && this.date.id === data.dateId) {
|
||||
if (this.date && this.date !== 'new' && String(this.date.id) === String(data.dateId)) {
|
||||
console.log('📡 Teilnehmer aktualisiert (Socket):', data);
|
||||
console.log('📡 [DiaryView] Aktuelle memberGroupsMap vor Update:', JSON.parse(JSON.stringify(this.memberGroupsMap)));
|
||||
|
||||
// Aktualisiere groupId in memberGroupsMap
|
||||
const groupValue = (data.participant.groupId !== null && data.participant.groupId !== undefined)
|
||||
? String(data.participant.groupId)
|
||||
: '';
|
||||
this.memberGroupsMap = {
|
||||
...this.memberGroupsMap,
|
||||
[data.participant.memberId]: groupValue
|
||||
};
|
||||
|
||||
console.log('📡 [DiaryView] Setze groupValue für memberId', data.participant.memberId, 'auf:', groupValue);
|
||||
console.log('📡 [DiaryView] data.participant:', JSON.parse(JSON.stringify(data.participant)));
|
||||
|
||||
// Verwende $set für Vue 2 - das ist wichtig für Reaktivität
|
||||
if (this.$set) {
|
||||
this.$set(this.memberGroupsMap, data.participant.memberId, groupValue);
|
||||
console.log('📡 [DiaryView] Verwendet $set für Vue 2');
|
||||
} else {
|
||||
// Vue 3: Erstelle neues Objekt für Reaktivität
|
||||
this.memberGroupsMap = {
|
||||
...this.memberGroupsMap,
|
||||
[data.participant.memberId]: groupValue
|
||||
};
|
||||
console.log('📡 [DiaryView] Verwendet Spread-Operator für Vue 3');
|
||||
}
|
||||
|
||||
// Warte auf Vue-Update und force dann ein Re-Render
|
||||
await this.$nextTick();
|
||||
console.log('📡 [DiaryView] memberGroupsMap nach Update:', JSON.parse(JSON.stringify(this.memberGroupsMap)));
|
||||
console.log('📡 [DiaryView] getMemberGroup für memberId', data.participant.memberId, ':', this.getMemberGroup(data.participant.memberId));
|
||||
|
||||
// Force Vue update um sicherzustellen, dass die UI aktualisiert wird
|
||||
this.$forceUpdate();
|
||||
console.log('✅ [DiaryView] UI-Update erzwungen');
|
||||
} else {
|
||||
console.log('⚠️ [DiaryView] Datum stimmt nicht überein - Event dateId:', data.dateId, 'Aktuelles Datum:', this.date?.id);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -3718,6 +3789,29 @@ img {
|
||||
}
|
||||
}
|
||||
|
||||
/* Member Group Select - Chrome Fix */
|
||||
.member-group-select {
|
||||
font-size: 10px !important;
|
||||
padding: 2px 4px !important;
|
||||
border: 1px solid #ccc !important;
|
||||
border-radius: 3px !important;
|
||||
background-color: white !important;
|
||||
color: #333 !important;
|
||||
-webkit-appearance: menulist !important;
|
||||
appearance: menulist !important;
|
||||
}
|
||||
|
||||
.member-group-select option {
|
||||
background-color: white !important;
|
||||
color: #333 !important;
|
||||
padding: 4px !important;
|
||||
}
|
||||
|
||||
.member-group-select:focus {
|
||||
outline: 2px solid #007bff !important;
|
||||
outline-offset: 2px !important;
|
||||
}
|
||||
|
||||
/* Render Container */
|
||||
.render-container {
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user