Add authentication system with login, password reset, and member area
This commit is contained in:
@@ -5,13 +5,73 @@
|
||||
<p class="text-sm text-gray-400">
|
||||
© {{ currentYear }} Harheimer TC
|
||||
</p>
|
||||
<div class="flex items-center space-x-6 text-sm">
|
||||
<div class="flex items-center space-x-6 text-sm relative">
|
||||
<NuxtLink to="/impressum" class="text-gray-400 hover:text-primary-400 transition-colors">
|
||||
Impressum
|
||||
</NuxtLink>
|
||||
<NuxtLink to="/kontakt" class="text-gray-400 hover:text-primary-400 transition-colors">
|
||||
Kontakt
|
||||
</NuxtLink>
|
||||
|
||||
<!-- Mitglieder Dropdown -->
|
||||
<div class="relative">
|
||||
<button
|
||||
@click="toggleMemberMenu"
|
||||
class="flex items-center space-x-1 text-gray-400 hover:text-primary-400 transition-colors"
|
||||
>
|
||||
<User :size="16" />
|
||||
<span>Mitglieder</span>
|
||||
<ChevronUp :size="14" :class="['transition-transform', isMemberMenuOpen ? 'rotate-0' : 'rotate-180']" />
|
||||
</button>
|
||||
|
||||
<!-- Dropdown Menu (appears above) -->
|
||||
<Transition
|
||||
enter-active-class="transition duration-200 ease-out"
|
||||
enter-from-class="transform translate-y-2 opacity-0"
|
||||
enter-to-class="transform translate-y-0 opacity-100"
|
||||
leave-active-class="transition duration-150 ease-in"
|
||||
leave-from-class="transform translate-y-0 opacity-100"
|
||||
leave-to-class="transform translate-y-2 opacity-0"
|
||||
>
|
||||
<div
|
||||
v-if="isMemberMenuOpen"
|
||||
class="absolute bottom-full right-0 mb-2 w-48 bg-gray-800 border border-gray-700 rounded-lg shadow-xl overflow-hidden"
|
||||
>
|
||||
<template v-if="isLoggedIn">
|
||||
<NuxtLink
|
||||
to="/mitgliederbereich"
|
||||
@click="isMemberMenuOpen = false"
|
||||
class="block px-4 py-2 text-sm text-gray-300 hover:bg-primary-600 hover:text-white transition-colors"
|
||||
>
|
||||
Mitgliederbereich
|
||||
</NuxtLink>
|
||||
<NuxtLink
|
||||
v-if="isAdmin"
|
||||
to="/cms"
|
||||
@click="isMemberMenuOpen = false"
|
||||
class="block px-4 py-2 text-sm text-gray-300 hover:bg-primary-600 hover:text-white transition-colors"
|
||||
>
|
||||
CMS
|
||||
</NuxtLink>
|
||||
<button
|
||||
@click="handleLogout"
|
||||
class="w-full text-left px-4 py-2 text-sm text-gray-300 hover:bg-primary-600 hover:text-white transition-colors"
|
||||
>
|
||||
Abmelden
|
||||
</button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<NuxtLink
|
||||
to="/login"
|
||||
@click="isMemberMenuOpen = false"
|
||||
class="block px-4 py-2 text-sm text-gray-300 hover:bg-primary-600 hover:text-white transition-colors"
|
||||
>
|
||||
Anmelden
|
||||
</NuxtLink>
|
||||
</template>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -19,5 +79,57 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { User, ChevronUp } from 'lucide-vue-next'
|
||||
|
||||
const currentYear = new Date().getFullYear()
|
||||
const isMemberMenuOpen = ref(false)
|
||||
const isLoggedIn = ref(false)
|
||||
const userRole = ref(null)
|
||||
|
||||
const isAdmin = computed(() => {
|
||||
return userRole.value === 'admin' || userRole.value === 'vorstand'
|
||||
})
|
||||
|
||||
const toggleMemberMenu = () => {
|
||||
isMemberMenuOpen.value = !isMemberMenuOpen.value
|
||||
}
|
||||
|
||||
const handleLogout = async () => {
|
||||
try {
|
||||
await $fetch('/api/auth/logout', { method: 'POST' })
|
||||
isLoggedIn.value = false
|
||||
userRole.value = null
|
||||
isMemberMenuOpen.value = false
|
||||
navigateTo('/')
|
||||
} catch (error) {
|
||||
console.error('Logout fehlgeschlagen:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// Check auth status on mount
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const response = await $fetch('/api/auth/status')
|
||||
isLoggedIn.value = response.isLoggedIn
|
||||
userRole.value = response.role
|
||||
} catch (error) {
|
||||
isLoggedIn.value = false
|
||||
}
|
||||
})
|
||||
|
||||
// Close menu when clicking outside
|
||||
const handleClickOutside = (event) => {
|
||||
if (!event.target.closest('.relative')) {
|
||||
isMemberMenuOpen.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener('click', handleClickOutside)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener('click', handleClickOutside)
|
||||
})
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user