Implement user sorting feature in Benutzer.vue
- 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:
@@ -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",
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
Reference in New Issue
Block a user