refactor: Simplify Logout Confirmation Handling in Navbar
- 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.
This commit is contained in:
parent
1631c23717
commit
9e9137e6b0
4 changed files with 53 additions and 43 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog'
|
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||||
|
|
@ -21,6 +21,7 @@ defineProps<Props>()
|
||||||
const emit = defineEmits<Emits>()
|
const emit = defineEmits<Emits>()
|
||||||
|
|
||||||
const userDisplay = computed(() => auth.userDisplay.value)
|
const userDisplay = computed(() => auth.userDisplay.value)
|
||||||
|
const showLogoutConfirm = ref(false)
|
||||||
|
|
||||||
// Get the API base URL from environment variables
|
// Get the API base URL from environment variables
|
||||||
const apiBaseUrl = import.meta.env.VITE_LNBITS_BASE_URL || ''
|
const apiBaseUrl = import.meta.env.VITE_LNBITS_BASE_URL || ''
|
||||||
|
|
@ -126,10 +127,10 @@ function handleClose() {
|
||||||
Change Password
|
Change Password
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<LogoutConfirmDialog variant="destructive" class="w-full justify-start gap-2" @confirm="handleLogout">
|
<Button variant="ghost" @click="showLogoutConfirm = true" class="w-full justify-start gap-2 text-destructive hover:text-destructive/90 hover:bg-destructive/10">
|
||||||
<LogOut class="w-4 h-4" />
|
<LogOut class="w-4 h-4" />
|
||||||
Logout
|
Logout
|
||||||
</LogoutConfirmDialog>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
@ -141,4 +142,10 @@ function handleClose() {
|
||||||
</div>
|
</div>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
|
<!-- Logout Confirm Dialog -->
|
||||||
|
<LogoutConfirmDialog v-model:is-open="showLogoutConfirm" variant="ghost" class="w-full justify-start gap-2" @confirm="handleLogout">
|
||||||
|
<LogOut class="w-4 h-4" />
|
||||||
|
Logout
|
||||||
|
</LogoutConfirmDialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||||
|
|
@ -11,6 +11,7 @@ import { toast } from 'vue-sonner'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const userDisplay = computed(() => auth.userDisplay.value)
|
const userDisplay = computed(() => auth.userDisplay.value)
|
||||||
|
const showLogoutConfirm = ref(false)
|
||||||
|
|
||||||
function handleLogout() {
|
function handleLogout() {
|
||||||
auth.logout()
|
auth.logout()
|
||||||
|
|
@ -59,12 +60,18 @@ function handleLogout() {
|
||||||
<Settings class="w-4 h-4 mr-2" />
|
<Settings class="w-4 h-4 mr-2" />
|
||||||
Settings
|
Settings
|
||||||
</Button>
|
</Button>
|
||||||
<LogoutConfirmDialog variant="destructive" size="sm" class="flex-1" @confirm="handleLogout">
|
<Button variant="ghost" size="sm" @click="showLogoutConfirm = true" class="flex-1 text-destructive hover:text-destructive/90 hover:bg-destructive/10">
|
||||||
<LogOut class="w-4 h-4 mr-2" />
|
<LogOut class="w-4 h-4 mr-2" />
|
||||||
Logout
|
Logout
|
||||||
</LogoutConfirmDialog>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Logout Confirm Dialog -->
|
||||||
|
<LogoutConfirmDialog v-model:is-open="showLogoutConfirm" variant="ghost" size="sm" class="flex-1 text-destructive hover:text-destructive/90 hover:bg-destructive/10" @confirm="handleLogout">
|
||||||
|
<LogOut class="w-4 h-4 mr-2" />
|
||||||
|
Logout
|
||||||
|
</LogoutConfirmDialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -156,11 +156,9 @@ const handleLogout = async () => {
|
||||||
Relay Hub Status
|
Relay Hub Status
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItem @click="() => {}" class="text-destructive p-0">
|
<DropdownMenuItem @click="showLogoutConfirm = true" class="gap-2 text-destructive">
|
||||||
<LogoutConfirmDialog variant="destructive" size="sm" class="w-full justify-start" @confirm="handleLogout">
|
<LogOut class="h-4 w-4" />
|
||||||
<LogOut class="h-4 w-4" />
|
Logout
|
||||||
Logout
|
|
||||||
</LogoutConfirmDialog>
|
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
|
|
@ -243,7 +241,7 @@ const handleLogout = async () => {
|
||||||
<Activity class="h-4 w-4" />
|
<Activity class="h-4 w-4" />
|
||||||
Relay Hub Status
|
Relay Hub Status
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="destructive" size="sm" class="w-full justify-start gap-2" @click="() => showLogoutConfirm = true">
|
<Button variant="ghost" size="sm" @click="showLogoutConfirm = true" class="w-full justify-start gap-2 text-destructive hover:text-destructive/90 hover:bg-destructive/10">
|
||||||
<LogOut class="h-4 w-4" />
|
<LogOut class="h-4 w-4" />
|
||||||
Logout
|
Logout
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -280,7 +278,10 @@ const handleLogout = async () => {
|
||||||
<!-- Profile Dialog -->
|
<!-- Profile Dialog -->
|
||||||
<ProfileDialog v-model:is-open="showProfileDialog" />
|
<ProfileDialog v-model:is-open="showProfileDialog" />
|
||||||
|
|
||||||
<!-- Logout Confirmation Dialog -->
|
<!-- Logout Confirm Dialog -->
|
||||||
<LogoutConfirmDialog v-model:is-open="showLogoutConfirm" @confirm="handleLogout" />
|
<LogoutConfirmDialog v-model:is-open="showLogoutConfirm" variant="ghost" size="sm" class="w-full justify-start gap-2" @confirm="handleLogout">
|
||||||
|
<LogOut class="h-4 w-4" />
|
||||||
|
Logout
|
||||||
|
</LogoutConfirmDialog>
|
||||||
</nav>
|
</nav>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,13 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed, watch } from 'vue'
|
||||||
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'
|
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { LogOut, AlertTriangle } from 'lucide-vue-next'
|
import { LogOut, AlertTriangle } from 'lucide-vue-next'
|
||||||
|
|
||||||
// Define component name for better debugging
|
|
||||||
defineOptions({
|
|
||||||
name: 'LogoutConfirmDialog'
|
|
||||||
})
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link'
|
variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link'
|
||||||
size?: 'default' | 'sm' | 'lg' | 'icon'
|
size?: 'default' | 'sm' | 'lg' | 'icon'
|
||||||
class?: string
|
class?: string
|
||||||
children?: any
|
|
||||||
isOpen?: boolean
|
isOpen?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -23,27 +17,28 @@ interface Emits {
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
variant: 'destructive',
|
variant: 'ghost',
|
||||||
size: 'default'
|
size: 'default'
|
||||||
})
|
})
|
||||||
|
|
||||||
// Default classes for the logout button styling
|
const emit = defineEmits<Emits>()
|
||||||
const defaultClasses = computed(() => {
|
const internalIsOpen = ref(false)
|
||||||
const baseClasses = 'gap-2 text-destructive hover:text-destructive/90 hover:bg-destructive/10'
|
|
||||||
|
// Use external control if provided, otherwise use internal state
|
||||||
if (props.class) {
|
const isOpen = computed({
|
||||||
// Merge custom classes with base classes, ensuring red styling is preserved
|
get: () => props.isOpen !== undefined ? props.isOpen : internalIsOpen.value,
|
||||||
return `${props.class} ${baseClasses}`
|
set: (value: boolean) => {
|
||||||
|
if (props.isOpen !== undefined) {
|
||||||
|
emit('update:isOpen', value)
|
||||||
|
} else {
|
||||||
|
internalIsOpen.value = value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default styling that matches the original red logout button
|
|
||||||
return baseClasses
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits<Emits>()
|
const buttonClasses = computed(() => {
|
||||||
const isOpen = computed({
|
const baseClasses = 'text-destructive hover:text-destructive/90 hover:bg-destructive/10'
|
||||||
get: () => props.isOpen ?? false,
|
return props.class ? `${baseClasses} ${props.class}` : baseClasses
|
||||||
set: (value: boolean) => emit('update:isOpen', value)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleConfirm = () => {
|
const handleConfirm = () => {
|
||||||
|
|
@ -58,10 +53,10 @@ const handleCancel = () => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Dialog v-model:open="isOpen">
|
<Dialog v-model:open="isOpen">
|
||||||
<DialogTrigger v-if="props.isOpen === undefined" as-child>
|
<DialogTrigger as-child v-if="props.isOpen === undefined">
|
||||||
<slot>
|
<slot>
|
||||||
<Button :variant="variant" :size="size" :class="defaultClasses">
|
<Button :variant="variant" :size="size" :class="buttonClasses">
|
||||||
<LogOut class="h-4 w-4" />
|
<LogOut class="h-4 w-4 mr-2" />
|
||||||
Logout
|
Logout
|
||||||
</Button>
|
</Button>
|
||||||
</slot>
|
</slot>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue