69 lines
2.2 KiB
Vue
69 lines
2.2 KiB
Vue
<script setup lang="ts">
|
|
import { onMounted } from 'vue'
|
|
import { useState, useRuntimeConfig } from '#imports'
|
|
|
|
// Using Nuxt's useState composable instead of Vue's ref
|
|
const config = useRuntimeConfig()
|
|
const apiBase = config.public.apiBase
|
|
|
|
const user = useState('user', () => ({}))
|
|
const isLoggedIn = useState('isLoggedIn', () => false)
|
|
|
|
onMounted(() => {
|
|
// Checking if code is running in browser environment before accessing localStorage
|
|
if (process.client) {
|
|
try {
|
|
const userData = JSON.parse(localStorage.getItem('user') || '{}')
|
|
user.value = userData
|
|
if (Object.keys(userData).length > 0) {
|
|
isLoggedIn.value = true
|
|
|
|
}
|
|
} catch (error) {
|
|
console.error('Error accessing localStorage:', error)
|
|
}
|
|
}
|
|
})
|
|
|
|
const logout = () => {
|
|
if (process.client) {
|
|
try {
|
|
localStorage.removeItem('user')
|
|
isLoggedIn.value = false
|
|
user.value = {}
|
|
} catch (error) {
|
|
console.error('Error during logout:', error)
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<header class="p-4 shadow-md flex justify-between bg-slate-100">
|
|
<h1><NuxtLink to="/">Eurovision 2025</NuxtLink></h1>
|
|
<nav>
|
|
<ul class="flex items-center gap-4">
|
|
<li v-if="isLoggedIn" class="flex items-center gap-2">
|
|
<NuxtLink to="/profile">
|
|
<NuxtImg
|
|
v-if="'avatar_id' in user"
|
|
:src="`${apiBase}/static/avatars/${user.avatar_id}.webp`"
|
|
class="w-4 h-4 rounded-full object-cover"
|
|
:alt="user.username"
|
|
/></NuxtLink>
|
|
</li>
|
|
<li v-if="!isLoggedIn">
|
|
<NuxtLink to="/login" class="flex items-center gap-1">
|
|
<Icon name="qlementine-icons:log-in-16" class="w-5 h-5" />
|
|
</NuxtLink>
|
|
</li>
|
|
<li v-if="isLoggedIn">
|
|
<button @click="logout" class="flex items-center gap-1">
|
|
<Icon name="qlementine-icons:log-out-16" class="w-5 h-5" />
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
</header>
|
|
</template>
|
|
|