- Remove the showLogoutConfirm state variable from Navbar.vue to streamline the logout confirmation process. - Update the LogoutConfirmDialog component to manage its own visibility state internally, enhancing encapsulation. - Refactor the logout button to directly trigger the confirmation dialog, improving code clarity and user experience. feat: Enhance Logout Confirmation Handling Across Components - Introduce a showLogoutConfirm state variable in ProfileDialog.vue, UserProfile.vue, and Navbar.vue to manage the visibility of the Logout Confirmation dialog. - Refactor logout buttons in these components to trigger the confirmation dialog, improving user experience and preventing accidental logouts. - Update the LogoutConfirmDialog component to accept an isOpen prop for better control of its visibility, ensuring consistent functionality across the application.
93 lines
2.9 KiB
Vue
93 lines
2.9 KiB
Vue
<script setup lang="ts">
|
|
import { ref, computed, watch } from 'vue'
|
|
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'
|
|
import { Button } from '@/components/ui/button'
|
|
import { LogOut, AlertTriangle } from 'lucide-vue-next'
|
|
|
|
interface Props {
|
|
variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link'
|
|
size?: 'default' | 'sm' | 'lg' | 'icon'
|
|
class?: string
|
|
isOpen?: boolean
|
|
}
|
|
|
|
interface Emits {
|
|
(e: 'confirm'): void
|
|
(e: 'update:isOpen', value: boolean): void
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
variant: 'ghost',
|
|
size: 'default'
|
|
})
|
|
|
|
const emit = defineEmits<Emits>()
|
|
const internalIsOpen = ref(false)
|
|
|
|
// Use external control if provided, otherwise use internal state
|
|
const isOpen = computed({
|
|
get: () => props.isOpen !== undefined ? props.isOpen : internalIsOpen.value,
|
|
set: (value: boolean) => {
|
|
if (props.isOpen !== undefined) {
|
|
emit('update:isOpen', value)
|
|
} else {
|
|
internalIsOpen.value = value
|
|
}
|
|
}
|
|
})
|
|
|
|
const buttonClasses = computed(() => {
|
|
const baseClasses = 'text-destructive hover:text-destructive/90 hover:bg-destructive/10'
|
|
return props.class ? `${baseClasses} ${props.class}` : baseClasses
|
|
})
|
|
|
|
const handleConfirm = () => {
|
|
isOpen.value = false
|
|
emit('confirm')
|
|
}
|
|
|
|
const handleCancel = () => {
|
|
isOpen.value = false
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<Dialog v-model:open="isOpen">
|
|
<DialogTrigger as-child v-if="props.isOpen === undefined">
|
|
<slot>
|
|
<Button :variant="variant" :size="size" :class="buttonClasses">
|
|
<LogOut class="h-4 w-4 mr-2" />
|
|
Logout
|
|
</Button>
|
|
</slot>
|
|
</DialogTrigger>
|
|
|
|
<DialogContent class="sm:max-w-md">
|
|
<DialogHeader class="space-y-4">
|
|
<div class="mx-auto w-12 h-12 rounded-full bg-gradient-to-br from-destructive to-destructive/80 p-0.5">
|
|
<div class="w-full h-full rounded-full bg-background flex items-center justify-center">
|
|
<AlertTriangle class="h-6 w-6 text-destructive" />
|
|
</div>
|
|
</div>
|
|
<div class="text-center space-y-2">
|
|
<DialogTitle class="text-xl font-semibold text-foreground">
|
|
Confirm Logout
|
|
</DialogTitle>
|
|
<DialogDescription class="text-muted-foreground">
|
|
Are you sure you want to logout? You will need to log in again to access your account.
|
|
</DialogDescription>
|
|
</div>
|
|
</DialogHeader>
|
|
|
|
<DialogFooter class="flex flex-col sm:flex-row gap-2 sm:gap-3">
|
|
<Button variant="ghost" @click="handleCancel" class="flex-1 sm:flex-none">
|
|
Cancel
|
|
</Button>
|
|
<Button variant="destructive" @click="handleConfirm" class="flex-1 sm:flex-none">
|
|
<LogOut class="h-4 w-4 mr-2" />
|
|
Logout
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
</template>
|