feat: Add ProfileDialog component for user profile management

- Introduce ProfileDialog.vue to display user information and account settings.
- Integrate ProfileDialog into Navbar.vue for easy access to user profile.
- Implement logout functionality within the ProfileDialog, enhancing user experience.
This commit is contained in:
padreug 2025-07-31 22:04:19 +02:00
parent 82e8c230ab
commit eb238ca380
2 changed files with 135 additions and 2 deletions

View file

@ -0,0 +1,123 @@
<script setup lang="ts">
import { computed } from 'vue'
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog'
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
import { User, LogOut, Settings, Mail, Key } from 'lucide-vue-next'
import { auth } from '@/composables/useAuth'
import { toast } from 'vue-sonner'
interface Props {
isOpen: boolean
}
interface Emits {
(e: 'update:isOpen', value: boolean): void
}
defineProps<Props>()
const emit = defineEmits<Emits>()
const userDisplay = computed(() => auth.userDisplay.value)
function handleLogout() {
auth.logout()
toast.success('Logged out successfully')
handleClose()
}
function handleClose() {
emit('update:isOpen', false)
}
</script>
<template>
<Dialog :open="isOpen" @update:open="handleClose">
<DialogContent class="sm:max-w-[500px]">
<DialogHeader>
<DialogTitle class="flex items-center gap-2">
<User class="w-5 h-5" />
User Profile
</DialogTitle>
<DialogDescription>
Your account information and settings
</DialogDescription>
</DialogHeader>
<div v-if="userDisplay" class="space-y-6">
<!-- User Info Card -->
<Card>
<CardHeader>
<CardTitle class="flex items-center gap-2">
<User class="w-5 h-5" />
Account Information
</CardTitle>
<CardDescription>
Your profile details
</CardDescription>
</CardHeader>
<CardContent class="space-y-4">
<div class="grid gap-4">
<div class="flex items-center justify-between">
<span class="text-sm font-medium">Name:</span>
<span class="text-sm">{{ userDisplay.name }}</span>
</div>
<div v-if="userDisplay.username" class="flex items-center justify-between">
<span class="text-sm font-medium">Username:</span>
<span class="text-sm">{{ userDisplay.username }}</span>
</div>
<div v-if="userDisplay.email" class="flex items-center justify-between">
<span class="text-sm font-medium">Email:</span>
<span class="text-sm">{{ userDisplay.email }}</span>
</div>
<div class="flex items-center justify-between">
<span class="text-sm font-medium">User ID:</span>
<Badge variant="secondary" class="text-xs">{{ userDisplay.shortId }}</Badge>
</div>
</div>
</CardContent>
</Card>
<!-- Actions Card -->
<Card>
<CardHeader>
<CardTitle class="flex items-center gap-2">
<Settings class="w-5 h-5" />
Account Actions
</CardTitle>
<CardDescription>
Manage your account settings
</CardDescription>
</CardHeader>
<CardContent class="space-y-4">
<div class="grid gap-3">
<Button variant="outline" class="w-full justify-start gap-2">
<Settings class="w-4 h-4" />
Account Settings
</Button>
<Button variant="outline" class="w-full justify-start gap-2">
<Key class="w-4 h-4" />
Change Password
</Button>
<Button variant="destructive" @click="handleLogout" class="w-full justify-start gap-2">
<LogOut class="w-4 h-4" />
Logout
</Button>
</div>
</CardContent>
</Card>
</div>
<div v-else class="text-center py-8">
<User class="w-12 h-12 mx-auto text-muted-foreground mb-4" />
<p class="text-muted-foreground">No user information available</p>
</div>
</DialogContent>
</Dialog>
</template>

View file

@ -9,6 +9,7 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSepara
import { Sun, Moon, Menu, X, User, LogOut } from 'lucide-vue-next' import { Sun, Moon, Menu, X, User, LogOut } from 'lucide-vue-next'
import LanguageSwitcher from '@/components/LanguageSwitcher.vue' import LanguageSwitcher from '@/components/LanguageSwitcher.vue'
import LoginDialog from '@/components/auth/LoginDialog.vue' import LoginDialog from '@/components/auth/LoginDialog.vue'
import ProfileDialog from '@/components/auth/ProfileDialog.vue'
import { auth } from '@/composables/useAuth' import { auth } from '@/composables/useAuth'
interface NavigationItem { interface NavigationItem {
@ -21,6 +22,7 @@ const { t } = useI18n()
const { theme, setTheme } = useTheme() const { theme, setTheme } = useTheme()
const isOpen = ref(false) const isOpen = ref(false)
const showLoginDialog = ref(false) const showLoginDialog = ref(false)
const showProfileDialog = ref(false)
const navigation = computed<NavigationItem[]>(() => [ const navigation = computed<NavigationItem[]>(() => [
{ name: t('nav.home'), href: '/' }, { name: t('nav.home'), href: '/' },
@ -41,6 +43,11 @@ const openLoginDialog = () => {
isOpen.value = false // Close mobile menu isOpen.value = false // Close mobile menu
} }
const openProfileDialog = () => {
showProfileDialog.value = true
isOpen.value = false // Close mobile menu
}
const handleLogout = async () => { const handleLogout = async () => {
try { try {
auth.logout() auth.logout()
@ -87,7 +94,7 @@ const handleLogout = async () => {
</Button> </Button>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent align="end" class="w-56"> <DropdownMenuContent align="end" class="w-56">
<DropdownMenuItem class="gap-2"> <DropdownMenuItem @click="openProfileDialog" class="gap-2">
<User class="h-4 w-4" /> <User class="h-4 w-4" />
Profile Profile
</DropdownMenuItem> </DropdownMenuItem>
@ -146,7 +153,7 @@ const handleLogout = async () => {
<Badge variant="secondary" class="text-xs ml-auto">Logged In</Badge> <Badge variant="secondary" class="text-xs ml-auto">Logged In</Badge>
</div> </div>
<div class="space-y-1"> <div class="space-y-1">
<Button variant="ghost" size="sm" class="w-full justify-start gap-2"> <Button variant="ghost" size="sm" @click="openProfileDialog" class="w-full justify-start gap-2">
<User class="h-4 w-4" /> <User class="h-4 w-4" />
Profile Profile
</Button> </Button>
@ -181,5 +188,8 @@ const handleLogout = async () => {
<!-- Login Dialog --> <!-- Login Dialog -->
<LoginDialog v-model:is-open="showLoginDialog" /> <LoginDialog v-model:is-open="showLoginDialog" />
<!-- Profile Dialog -->
<ProfileDialog v-model:is-open="showProfileDialog" />
</nav> </nav>
</template> </template>