feat: improve ux and security
This commit is contained in:
22
app/components/ConfirmModal.vue
Normal file
22
app/components/ConfirmModal.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
title: string;
|
||||
description?: string;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{ close: [confirmed: boolean] }>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UModal :title="title">
|
||||
<template #body>
|
||||
<p v-if="description" class="text-sm text-muted">{{ description }}</p>
|
||||
</template>
|
||||
<template #footer>
|
||||
<div class="flex gap-2 justify-end w-full">
|
||||
<UButton variant="ghost" color="neutral" @click="emit('close', false)">Cancel</UButton>
|
||||
<UButton color="error" @click="emit('close', true)">Delete</UButton>
|
||||
</div>
|
||||
</template>
|
||||
</UModal>
|
||||
</template>
|
||||
@@ -8,7 +8,7 @@ const props = defineProps<{
|
||||
|
||||
const schema = z.object({
|
||||
name: z.string({ error: "Required" }),
|
||||
path: z.string({ error: "Required" }),
|
||||
path: z.string({ error: "Required" }).startsWith("/", "Must start with /"),
|
||||
url: z.url({ error: (err) => err.code === "invalid_type" ? "Required" : "Invalid format", }),
|
||||
disabled: z.boolean().optional(),
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { LazyLinkModal } from "#components";
|
||||
import { LazyLinkModal, LazyConfirmModal } from "#components";
|
||||
|
||||
definePageMeta({ middleware: "auth" });
|
||||
|
||||
@@ -37,14 +37,18 @@ const openModal = async (link: Link | null) => {
|
||||
}
|
||||
|
||||
const deleteLink = async (link: Link) => {
|
||||
const modal = overlay.create(LazyConfirmModal, { destroyOnClose: true });
|
||||
const instance = modal.open({ title: "Delete link", description: `Are you sure you want to delete "${link.name}"?` });
|
||||
if (!await instance.result) return;
|
||||
|
||||
try {
|
||||
await $fetch(`/api/links/${link.id}`, { method: "DELETE" });
|
||||
toast.add({ title: "Link deleted", color: "success" });
|
||||
await refresh();
|
||||
} catch {
|
||||
toast.add({ title: "Failed to delete link", color: "error" });
|
||||
} catch (error) {
|
||||
toast.add({ title: getApiError(error), color: "error" });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user