1<template>
2 <Dialog v-model:open="open" :title="dialogTitle" size="md">
3 <template #default>
4 <div class="flex flex-col gap-4">
5 <p class="text-p-base text-ink-gray-7">{{ message }}</p>
6 <Checkbox
7 v-if="count"
8 size="sm"
9 v-model="deleteLinkedTickets"
10 :label="__('Delete {0} ticket(s)', [count])"
11 />
12 </div>
13 </template>
14 <template #actions>
15 <div class="flex justify-end">
16 <Button
17 variant="solid"
18 theme="red"
19 icon-left="lucide-trash-2"
20 :label="__('Delete')"
21 :loading="isDeleting"
22 @click="confirmDelete"
23 />
24 </div>
25 </template>
26 </Dialog>
27</template>
28
29<script setup lang="ts">
30import { __ } from "@/translation";
31import { Button, Checkbox, createResource, Dialog } from "frappe-ui";
32import { computed, ref, watch } from "vue";
33
34const props = defineProps<{
35 /** Name of the record being deleted. */
36 name: string;
37 /** OD Ticket link field that ties tickets to this record. */
38 linkField: "customer" | "contact";
39 /** Confirmation copy shown above the checkbox. */
40 message: string;
41 title?: string;
42 /** Async delete handler; the button stays in a loading state until it settles. */
43 onDelete: (payload: { deleteLinkedTickets: boolean }) => Promise<void> | void;
44}>();
45
46const open = defineModel<boolean>({ default: false });
47
48const resource = createResource({
49 url: "frappe.client.get_count",
50 params: {
51 doctype: "OD Ticket",
52 filters: { [props.linkField]: props.name },
53 },
54 auto: true,
55});
56
57const count = computed<number>(() => {
58 if (resource.loading) return 0;
59 return resource.data ?? 0;
60});
61
62const deleteLinkedTickets = ref(false);
63const isDeleting = ref(false);
64
65const dialogTitle = computed(() => props.title ?? __("Delete"));
66
67async function confirmDelete() {
68 if (isDeleting.value) return;
69 isDeleting.value = true;
70 try {
71 await props.onDelete({ deleteLinkedTickets: deleteLinkedTickets.value });
72 open.value = false;
73 } catch {
74 // Keep the dialog open on failure; the handler surfaces the error.
75 } finally {
76 isDeleting.value = false;
77 }
78}
79
80watch(
81 open,
82 (isOpen) => {
83 if (isOpen) {
84 resource.reload();
85 }
86 },
87 { immediate: true }
88);
89</script>
90