feat(MembersOverview, MembersView): add training group filtering and display enhancements

- Introduced a new training group filter in MembersOverviewSection for improved member management.
- Updated MembersView to support the new training group selection and display last training date for members.
- Enhanced computed properties to dynamically generate training group options based on member data.
- Improved filtering logic to include selected training group, refining member search capabilities.
This commit is contained in:
Torsten Schulz (local)
2026-03-19 16:10:39 +01:00
parent 9d01ab6ce1
commit 542d741428
2 changed files with 42 additions and 0 deletions

View File

@@ -106,6 +106,15 @@
<option value="unknown">{{ $t('members.genderUnknown') }}</option>
</select>
</div>
<div class="filter-group">
<label>{{ $t('members.trainingGroups') }}:</label>
<select :value="selectedTrainingGroup" class="filter-select" @change="$emit('update:selected-training-group', $event.target.value)">
<option value="">{{ $t('common.all') }}</option>
<option v-for="group in trainingGroupOptions" :key="group.id" :value="group.id">
{{ group.name }}
</option>
</select>
</div>
<button @click="$emit('clear-filters')" class="btn-clear-filters">{{ $t('members.clearFilters') }}</button>
</div>
</details>
@@ -193,6 +202,8 @@ export default {
selectedAgeFrom: { type: [String, Number], required: true },
selectedAgeTo: { type: [String, Number], required: true },
selectedGender: { type: String, required: true },
selectedTrainingGroup: { type: String, required: true },
trainingGroupOptions: { type: Array, required: true },
selectedSort: { type: String, required: true },
sortDirection: { type: String, required: true },
filteredMembersWithoutFormCount: { type: Number, required: true },
@@ -213,6 +224,7 @@ export default {
'update:selected-age-from',
'update:selected-age-to',
'update:selected-gender',
'update:selected-training-group',
'clear-filters',
'update:selected-sort',
'toggle-sort-direction',

View File

@@ -15,6 +15,8 @@
:selected-age-from="selectedAgeFrom"
:selected-age-to="selectedAgeTo"
:selected-gender="selectedGender"
:selected-training-group="selectedTrainingGroup"
:training-group-options="trainingGroupFilterOptions"
:selected-sort="selectedSort"
:sort-direction="sortDirection"
:filtered-members-without-form-count="filteredMembersWithoutForm.length"
@@ -33,6 +35,7 @@
@update:selected-age-from="selectedAgeFrom = $event"
@update:selected-age-to="selectedAgeTo = $event"
@update:selected-gender="selectedGender = $event"
@update:selected-training-group="selectedTrainingGroup = $event"
@clear-filters="clearFilters"
@update:selected-sort="selectedSort = $event"
@toggle-sort-direction="toggleSortDirection"
@@ -326,6 +329,7 @@
<th>{{ $t('members.contact') }}</th>
<th>{{ $t('members.birthdate') }}</th>
<th>{{ $t('members.age') }}</th>
<th>{{ $t('members.lastTraining') }}</th>
<th v-if="hasTestMembers">{{ $t('members.trainingParticipations') }}</th>
<th>{{ $t('members.actions') }}</th>
</tr>
@@ -398,6 +402,7 @@
</td>
<td>{{ getFormattedBirthdate(member.birthDate) }}</td>
<td>{{ getAgeLabel(member.birthDate) }}</td>
<td>{{ getOptionalFormattedDate(member.lastTraining, 'members.previewNoLastTraining') }}</td>
<td v-if="hasTestMembers">
<span v-if="member.testMembership">{{ member.trainingParticipations || 0 }}</span>
<span v-else>-</span>
@@ -578,6 +583,22 @@ export default {
inactiveMembersCount() {
return this.members.filter(member => !member.active).length;
},
trainingGroupFilterOptions() {
const groups = new Map();
this.members.forEach((member) => {
this.getMemberTrainingGroups(member).forEach((group) => {
if (!group || group.id == null) {
return;
}
groups.set(String(group.id), group.name || `#${group.id}`);
});
});
return Array.from(groups.entries())
.map(([id, name]) => ({ id, name }))
.sort((a, b) => a.name.localeCompare(b.name, 'de-DE'));
},
filteredMembers() {
return this.members.filter(member => {
@@ -648,6 +669,13 @@ export default {
}
}
if (this.selectedTrainingGroup) {
const memberGroupIds = this.getMemberTrainingGroups(member).map(group => String(group.id));
if (!memberGroupIds.includes(String(this.selectedTrainingGroup))) {
return false;
}
}
if (search) {
const haystack = [
member.firstName,
@@ -885,6 +913,7 @@ export default {
selectedAgeFrom: '',
selectedAgeTo: '',
selectedGender: '',
selectedTrainingGroup: '',
clickTtPendingMemberIds: [],
searchQuery: '',
selectedMemberScope: 'active',
@@ -2323,6 +2352,7 @@ export default {
this.selectedAgeFrom = '';
this.selectedAgeTo = '';
this.selectedGender = '';
this.selectedTrainingGroup = '';
this.showInactiveMembers = false;
this.searchQuery = '';
this.selectedMemberScope = 'active';