Implement user sorting feature in Benutzer.vue
All checks were successful
Code Analysis and Production Deploy / analyze (push) Has been skipped
Code Analysis and Production Deploy / deploy-production (push) Has been skipped
Code Analysis and Production Deploy / deploy-test (push) Successful in 2m19s

- Added a dropdown for sorting active users by first name or last name.
- Updated the display of active users to reflect the selected sorting order.
- Introduced helper functions to split names and format display names accordingly.
This commit is contained in:
Torsten Schulz (local)
2026-04-27 15:04:41 +02:00
parent 20a1cdd7f2
commit 27a096546f
2 changed files with 85 additions and 7 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "harheimertc-website", "name": "harheimertc-website",
"version": "1.1.2", "version": "1.1.3",
"description": "Moderne Webseite für den Harheimer Tischtennis Club", "description": "Moderne Webseite für den Harheimer Tischtennis Club",
"private": true, "private": true,
"type": "module", "type": "module",

View File

@@ -106,9 +106,31 @@
<!-- Active Users --> <!-- Active Users -->
<div> <div>
<h2 class="text-2xl font-display font-bold text-gray-900 mb-4"> <div class="flex flex-col gap-3 mb-4 sm:flex-row sm:items-end sm:justify-between">
Aktive Benutzer ({{ activeUsers.length }}) <h2 class="text-2xl font-display font-bold text-gray-900">
</h2> Aktive Benutzer ({{ sortedActiveUsers.length }})
</h2>
<div class="flex items-center gap-2">
<label
for="user-sort-order"
class="text-sm font-medium text-gray-700"
>
Sortierung
</label>
<select
id="user-sort-order"
v-model="nameSortMode"
class="px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-primary-600"
>
<option value="firstLast">
Vorname Nachname
</option>
<option value="lastFirst">
Nachname, Vorname
</option>
</select>
</div>
</div>
<div class="bg-white rounded-xl shadow-lg overflow-hidden"> <div class="bg-white rounded-xl shadow-lg overflow-hidden">
<table class="min-w-full divide-y divide-gray-200"> <table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50"> <thead class="bg-gray-50">
@@ -135,13 +157,13 @@
</thead> </thead>
<tbody class="bg-white divide-y divide-gray-200"> <tbody class="bg-white divide-y divide-gray-200">
<tr <tr
v-for="user in activeUsers" v-for="user in sortedActiveUsers"
:key="user.id" :key="user.id"
class="hover:bg-gray-50" class="hover:bg-gray-50"
> >
<td class="px-6 py-4 whitespace-nowrap"> <td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm font-medium text-gray-900"> <div class="text-sm font-medium text-gray-900">
{{ user.name }} {{ getDisplayName(user) }}
</div> </div>
</td> </td>
<td class="px-6 py-4 whitespace-nowrap"> <td class="px-6 py-4 whitespace-nowrap">
@@ -253,7 +275,7 @@
> >
<div class="bg-white rounded-xl shadow-2xl max-w-md w-full p-6"> <div class="bg-white rounded-xl shadow-2xl max-w-md w-full p-6">
<h2 class="text-2xl font-display font-bold text-gray-900 mb-4"> <h2 class="text-2xl font-display font-bold text-gray-900 mb-4">
Rollen bearbeiten: {{ editingUser.name }} Rollen bearbeiten: {{ getDisplayName(editingUser) }}
</h2> </h2>
<div class="space-y-3 mb-6"> <div class="space-y-3 mb-6">
@@ -350,6 +372,7 @@ const errorMessage = ref('')
const showRoleModal = ref(false) const showRoleModal = ref(false)
const editingUser = ref(null) const editingUser = ref(null)
const selectedRoles = ref([]) const selectedRoles = ref([])
const nameSortMode = ref('firstLast')
const pendingUsers = computed(() => { const pendingUsers = computed(() => {
return allUsers.value return allUsers.value
@@ -364,6 +387,61 @@ const activeUsers = computed(() => {
return allUsers.value.filter(u => u.active === true) return allUsers.value.filter(u => u.active === true)
}) })
const splitNameParts = (name = '') => {
const trimmed = (name || '').trim()
if (!trimmed) {
return { firstName: '', lastName: '' }
}
if (trimmed.includes(',')) {
const [lastNameRaw, ...firstNameRaw] = trimmed.split(',')
return {
firstName: firstNameRaw.join(',').trim(),
lastName: (lastNameRaw || '').trim()
}
}
const parts = trimmed.split(/\s+/).filter(Boolean)
if (parts.length <= 1) {
return { firstName: parts[0] || '', lastName: '' }
}
return {
firstName: parts[0],
lastName: parts.slice(1).join(' ')
}
}
const getDisplayName = (user) => {
const { firstName, lastName } = splitNameParts(user?.name || '')
if (nameSortMode.value === 'lastFirst') {
if (!lastName) {
return firstName
}
return `${lastName}, ${firstName}`.trim()
}
return `${firstName} ${lastName}`.trim()
}
const sortedActiveUsers = computed(() => {
return [...activeUsers.value].sort((a, b) => {
const nameA = splitNameParts(a.name)
const nameB = splitNameParts(b.name)
if (nameSortMode.value === 'lastFirst') {
const lastNameCompare = nameA.lastName.localeCompare(nameB.lastName, 'de', { sensitivity: 'base' })
if (lastNameCompare !== 0) return lastNameCompare
return nameA.firstName.localeCompare(nameB.firstName, 'de', { sensitivity: 'base' })
}
const firstNameCompare = nameA.firstName.localeCompare(nameB.firstName, 'de', { sensitivity: 'base' })
if (firstNameCompare !== 0) return firstNameCompare
return nameA.lastName.localeCompare(nameB.lastName, 'de', { sensitivity: 'base' })
})
})
const formatDate = (dateString) => { const formatDate = (dateString) => {
return new Date(dateString).toLocaleString('de-DE', { return new Date(dateString).toLocaleString('de-DE', {
year: 'numeric', year: 'numeric',