checkpoint before gorm fix
This commit is contained in:
@@ -1,44 +1,69 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
DropdownMenu, DropdownMenuItem,
|
||||
DropdownMenuTrigger, DropdownMenuContent
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
DropdownMenu, DropdownMenuItem,
|
||||
DropdownMenuTrigger, DropdownMenuContent
|
||||
} from '@/components/ui/dropdown-menu'
|
||||
|
||||
import EditUserDialog from './EditUserDialog.vue';
|
||||
import DeleteUserDialog from './DeleteUserDialog.vue';
|
||||
import { Ellipsis } from 'lucide-vue-next';
|
||||
import { ref } from 'vue';
|
||||
import EditUserDialog from './EditUserDialog.vue'
|
||||
import DeleteUserDialog from './DeleteUserDialog.vue'
|
||||
import { Ellipsis } from 'lucide-vue-next'
|
||||
import { ref } from 'vue'
|
||||
import { api } from '@/lib/api' // <-- use your axios/fetch wrapper
|
||||
|
||||
const props = defineProps<{ userId: string }>()
|
||||
const emit = defineEmits<{
|
||||
(e: 'deleted', id: string): void
|
||||
(e: 'error', err: unknown): void
|
||||
}>()
|
||||
|
||||
const isEditOpen = ref(false)
|
||||
const isDeleteOpen = ref(false)
|
||||
const deleting = ref(false)
|
||||
|
||||
// your actual delete logic
|
||||
function onDeleteConfirmed() {
|
||||
// e.g. await api.deleteUser(props.userId)
|
||||
isDeleteOpen.value = false
|
||||
// DELETE /users/:id
|
||||
async function onDeleteConfirmed() {
|
||||
try {
|
||||
deleting.value = true
|
||||
await api.delete(`/users/${encodeURIComponent(props.userId)}`)
|
||||
emit('deleted', props.userId)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
emit('error', err)
|
||||
} finally {
|
||||
deleting.value = false
|
||||
// The dialog already closes itself on confirm; nothing else required.
|
||||
}
|
||||
}
|
||||
|
||||
function onEditConfirm() {
|
||||
isEditOpen.value = false
|
||||
isEditOpen.value = false
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button class="p-2 rounded hover:bg-muted">
|
||||
<Ellipsis />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" class="w-[160px]">
|
||||
<DropdownMenuItem @click.prevent="isEditOpen = true">
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem @click.prevent="isDeleteOpen = true">
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<EditUserDialog v-model:modelValue="isEditOpen" @confirm="onEditConfirm()" />
|
||||
<DeleteUserDialog v-model:modelValue="isDeleteOpen" @confirm="onDeleteConfirmed" />
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button class="p-2 rounded hover:bg-muted" :disabled="deleting">
|
||||
<Ellipsis />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
<DropdownMenuContent align="end" class="w-[160px]">
|
||||
<DropdownMenuItem @click.prevent="isEditOpen = true">
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem @click.prevent="isDeleteOpen = true" :disabled="deleting">
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
<EditUserDialog v-model:modelValue="isEditOpen" @confirm="onEditConfirm()" />
|
||||
|
||||
<!-- pass 'deleting' to disable the confirm button during request -->
|
||||
<DeleteUserDialog
|
||||
v-model:modelValue="isDeleteOpen"
|
||||
:loading="deleting"
|
||||
@confirm="onDeleteConfirmed"
|
||||
/>
|
||||
</template>
|
||||
@@ -12,10 +12,8 @@ import {
|
||||
import { defineProps, defineEmits, type PropType } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean as PropType<boolean>,
|
||||
required: true,
|
||||
},
|
||||
modelValue: { type: Boolean as PropType<boolean>, required: true },
|
||||
loading: { type: Boolean as PropType<boolean>, default: false },
|
||||
})
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', v: boolean): void
|
||||
@@ -36,10 +34,12 @@ const emit = defineEmits<{
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||
<AlertDialogCancel :disabled="props.loading">Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
:disabled="props.loading"
|
||||
@click="() => { emit('confirm'); emit('update:modelValue', false) }"
|
||||
> Delete
|
||||
>
|
||||
{{ props.loading ? 'Deleting…' : 'Delete' }}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
|
||||
@@ -1,57 +1,73 @@
|
||||
<script setup lang="ts">
|
||||
// import { Card, CardHeader, CardContent } from '@/components/ui/card';
|
||||
import {
|
||||
DropdownMenu, DropdownMenuContent,
|
||||
DropdownMenuTrigger, DropdownMenuSeparator,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
DropdownMenu, DropdownMenuContent,
|
||||
DropdownMenuTrigger, DropdownMenuSeparator,
|
||||
DropdownMenuItem, DropdownMenuLabel
|
||||
} from '@/components/ui/dropdown-menu'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { Settings } from 'lucide-vue-next';
|
||||
import { Settings } from 'lucide-vue-next'
|
||||
import { RouterLink, useRoute } from 'vue-router'
|
||||
|
||||
const { customComponent } = defineProps<{ customComponent?: any }>()
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
function isActive(prefix: string) {
|
||||
const p = route.path.replace(/\/+$/, '')
|
||||
const tgt = prefix.replace(/\/+$/, '')
|
||||
return p === tgt || p.startsWith(tgt + '/')
|
||||
}
|
||||
|
||||
function navLinkClass(prefix: string) {
|
||||
return cn(
|
||||
'text-sm font-medium transition-colors',
|
||||
isActive(prefix) ? 'text-primary' : 'text-muted-foreground hover:text-primary'
|
||||
)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col min-h-screen">
|
||||
<div class="flex items-center justify-end space-x-6 p-4">
|
||||
<nav :class="cn('flex items-center space-x-4 lg:space-x-6', $attrs.class ?? '')">
|
||||
<a href="/admin" class="text-sm font-medium transition-colors hover:text-primary">
|
||||
Admin
|
||||
</a>
|
||||
<a href="/devices"
|
||||
class="text-sm font-medium text-muted-foreground transition-colors hover:text-primary">
|
||||
Devices
|
||||
</a>
|
||||
</nav>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button class="p-2 rounded hover:bg-muted">
|
||||
<Settings />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent class="w-48">
|
||||
<DropdownMenuLabel>
|
||||
Admin
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<a href="/settings">
|
||||
<DropdownMenuItem>
|
||||
Settings
|
||||
</DropdownMenuItem>
|
||||
</a>
|
||||
<DropdownMenuSeparator />
|
||||
<a href="/login">
|
||||
<DropdownMenuItem>
|
||||
Logout
|
||||
</DropdownMenuItem>
|
||||
</a>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
<div class="flex flex-1 flex-col gap-4 p-4">
|
||||
<!-- <component v-if="customComponent" :is="customComponent" /> -->
|
||||
<slot></slot>
|
||||
</div>
|
||||
<div class="flex flex-col min-h-screen">
|
||||
<div class="flex items-center justify-end space-x-6 p-4">
|
||||
<nav :class="cn('flex items-center space-x-4 lg:space-x-6', $attrs.class ?? '')">
|
||||
<RouterLink
|
||||
to="/admin"
|
||||
:class="navLinkClass('/admin')"
|
||||
:aria-current="isActive('/admin') ? 'page' : undefined"
|
||||
>
|
||||
Admin
|
||||
</RouterLink>
|
||||
<RouterLink
|
||||
to="/devices"
|
||||
:class="navLinkClass('/devices')"
|
||||
:aria-current="isActive('/devices') ? 'page' : undefined"
|
||||
>
|
||||
Devices
|
||||
</RouterLink>
|
||||
</nav>
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button class="p-2 rounded hover:bg-muted">
|
||||
<Settings />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent class="w-48">
|
||||
<DropdownMenuLabel>Admin</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<RouterLink to="/settings">
|
||||
<DropdownMenuItem>Settings</DropdownMenuItem>
|
||||
</RouterLink>
|
||||
<DropdownMenuSeparator />
|
||||
<RouterLink to="/login">
|
||||
<DropdownMenuItem>Logout</DropdownMenuItem>
|
||||
</RouterLink>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-1 flex-col gap-4 p-4">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user