Implement toggle functionality for Mannschaftsspieler status in Mitgliederbereich. Add button for editing status and update local state upon toggling. Enhance API response handling to include isMannschaftsspieler attribute for user data retrieval.

This commit is contained in:
Torsten Schulz (local)
2025-12-19 10:14:41 +01:00
parent 5a85c3d31a
commit 6b24ac0071
3 changed files with 174 additions and 11 deletions

View File

@@ -81,13 +81,30 @@
<span v-else class="text-sm text-gray-400">Nur für Vorstand</span> <span v-else class="text-sm text-gray-400">Nur für Vorstand</span>
</td> </td>
<td class="px-4 py-3 whitespace-nowrap"> <td class="px-4 py-3 whitespace-nowrap">
<span <button
v-if="member.isMannschaftsspieler" v-if="canEdit"
class="px-2 py-1 bg-blue-100 text-blue-800 text-xs font-medium rounded-full" @click="toggleMannschaftsspieler(member)"
:class="[
'px-2 py-1 text-xs font-medium rounded-full transition-colors',
member.isMannschaftsspieler
? 'bg-blue-100 text-blue-800 hover:bg-blue-200'
: 'bg-gray-100 text-gray-600 hover:bg-gray-200'
]"
title="Klicken zum Umschalten"
> >
Ja {{ member.isMannschaftsspieler ? 'Ja' : 'Nein' }}
</button>
<span
v-else
:class="[
'px-2 py-1 text-xs font-medium rounded-full',
member.isMannschaftsspieler
? 'bg-blue-100 text-blue-800'
: 'bg-gray-100 text-gray-600'
]"
>
{{ member.isMannschaftsspieler ? 'Ja' : 'Nein' }}
</span> </span>
<span v-else class="text-sm text-gray-400">-</span>
</td> </td>
<td class="px-4 py-3 whitespace-nowrap"> <td class="px-4 py-3 whitespace-nowrap">
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
@@ -163,11 +180,29 @@
> >
Aus Login-System Aus Login-System
</span> </span>
<span <button
v-if="member.isMannschaftsspieler" v-if="canEdit"
class="ml-2 px-2 py-1 bg-blue-100 text-blue-800 text-xs font-medium rounded-full" @click="toggleMannschaftsspieler(member)"
:class="[
'ml-2 px-2 py-1 text-xs font-medium rounded-full transition-colors',
member.isMannschaftsspieler
? 'bg-blue-100 text-blue-800 hover:bg-blue-200'
: 'bg-gray-100 text-gray-600 hover:bg-gray-200'
]"
title="Klicken zum Umschalten"
> >
Mannschaftsspieler Mannschaftsspieler: {{ member.isMannschaftsspieler ? 'Ja' : 'Nein' }}
</button>
<span
v-else
:class="[
'ml-2 px-2 py-1 text-xs font-medium rounded-full',
member.isMannschaftsspieler
? 'bg-blue-100 text-blue-800'
: 'bg-gray-100 text-gray-600'
]"
>
Mannschaftsspieler: {{ member.isMannschaftsspieler ? 'Ja' : 'Nein' }}
</span> </span>
</div> </div>
@@ -618,6 +653,27 @@ const saveMember = async () => {
} }
} }
const toggleMannschaftsspieler = async (member) => {
try {
const response = await $fetch('/api/members/toggle-mannschaftsspieler', {
method: 'POST',
body: { memberId: member.id }
})
// Update local state immediately
member.isMannschaftsspieler = response.isMannschaftsspieler
// Reload to ensure consistency
await loadMembers()
} catch (error) {
console.error('Fehler beim Umschalten des Mannschaftsspieler-Status:', error)
const errorMsg = error.data?.message || error.message || 'Fehler beim Umschalten des Status.'
if (window.showErrorModal) {
window.showErrorModal('Fehler', errorMsg)
}
}
}
const confirmDelete = async (member) => { const confirmDelete = async (member) => {
window.showConfirmModal('Mitglied löschen', `Möchten Sie "${member.name}" wirklich löschen?`, async () => { window.showConfirmModal('Mitglied löschen', `Möchten Sie "${member.name}" wirklich löschen?`, async () => {
try { try {

View File

@@ -83,7 +83,8 @@ export default defineEventHandler(async (event) => {
loginEmail: user.email, loginEmail: user.email,
loginRoles: roles, loginRoles: roles,
loginRole: roles[0] || 'mitglied', // Rückwärtskompatibilität loginRole: roles[0] || 'mitglied', // Rückwärtskompatibilität
lastLogin: user.lastLogin lastLogin: user.lastLogin,
isMannschaftsspieler: user.isMannschaftsspieler === true || mergedMembers[matchedManualIndex].isMannschaftsspieler === true
} }
} else { } else {
// Add as new member (from login system) // Add as new member (from login system)
@@ -102,7 +103,8 @@ export default defineEventHandler(async (event) => {
loginEmail: user.email, loginEmail: user.email,
loginRoles: roles, loginRoles: roles,
loginRole: roles[0] || 'mitglied', // Rückwärtskompatibilität loginRole: roles[0] || 'mitglied', // Rückwärtskompatibilität
lastLogin: user.lastLogin lastLogin: user.lastLogin,
isMannschaftsspieler: user.isMannschaftsspieler === true
}) })
} }
} }

View File

@@ -0,0 +1,105 @@
import { verifyToken, getUserById, hasAnyRole, readUsers, writeUsers } from '../../utils/auth.js'
import { readMembers, writeMembers, getMemberById } from '../../utils/members.js'
export default defineEventHandler(async (event) => {
try {
// Support both Cookie and Authorization Header
let token = getCookie(event, 'auth_token')
if (!token) {
const authHeader = getHeader(event, 'authorization')
if (authHeader && authHeader.startsWith('Bearer ')) {
token = authHeader.substring(7)
}
}
if (!token) {
throw createError({
statusCode: 401,
message: 'Nicht authentifiziert.'
})
}
const decoded = verifyToken(token)
if (!decoded) {
throw createError({
statusCode: 401,
message: 'Ungültiges Token.'
})
}
const user = await getUserById(decoded.id)
if (!user) {
throw createError({
statusCode: 401,
message: 'Benutzer nicht gefunden.'
})
}
// Only admin and vorstand can toggle this flag
if (!hasAnyRole(user, 'admin', 'vorstand')) {
throw createError({
statusCode: 403,
message: 'Keine Berechtigung.'
})
}
const body = await readBody(event)
const { memberId } = body
if (!memberId) {
throw createError({
statusCode: 400,
message: 'Mitglieds-ID ist erforderlich.'
})
}
// Prüfe ob es ein Login-System-Mitglied ist (user.id === memberId)
const users = await readUsers()
const loginUser = users.find(u => u.id === memberId)
if (loginUser) {
// Login-System-Mitglied: Flag in users.json speichern
loginUser.isMannschaftsspieler = !loginUser.isMannschaftsspieler
await writeUsers(users)
return {
success: true,
message: 'Mannschaftsspieler-Status aktualisiert.',
isMannschaftsspieler: loginUser.isMannschaftsspieler
}
} else {
// Manuelles Mitglied: Flag in members.json speichern
const members = await readMembers()
const member = members.find(m => m.id === memberId)
if (!member) {
throw createError({
statusCode: 404,
message: 'Mitglied nicht gefunden.'
})
}
member.isMannschaftsspieler = !member.isMannschaftsspieler
await writeMembers(members)
return {
success: true,
message: 'Mannschaftsspieler-Status aktualisiert.',
isMannschaftsspieler: member.isMannschaftsspieler
}
}
} catch (error) {
console.error('Fehler beim Umschalten des Mannschaftsspieler-Status:', error)
if (error.statusCode) {
throw error
}
throw createError({
statusCode: error.statusCode || 500,
message: error.message || 'Fehler beim Umschalten des Mannschaftsspieler-Status.'
})
}
})