1<template>
2 <Dialog
3 v-model:open="dialogModel.show"
4 :title="__('Preview')"
5 size="2xl"
6 @after-leave="
7 () => {
8 dialogModel.ticketId = '';
9 dialogModel.preview = null;
10 }
11 "
12 >
13 <template #default>
14 <div class="space-y-4">
15 <Link
16 :value="dialogModel.ticketId"
17 :label="__('Select ticket to preview')"
18 doctype="OD Ticket"
19 class="form-control flex-1"
20 :placeholder="__('Search ticket')"
21 :show-description="true"
22 hide-clear-button
23 @change="getResponsePreview"
24 />
25
26 <div class="space-y-1.5">
27 <FormLabel :label="__('Preview')" />
28 <div class="relative pointer-events-none">
29 <Editor
30 :model-value="dialogModel.preview"
31 :extensions="extensions"
32 :editable="false"
33 >
34 <template #default>
35 <EditorContent
36 class="!prose-sm max-w-full overflow-auto min-h-[180px] max-h-80 py-1.5 px-2 rounded-4 border border-[--surface-gray-2] bg-surface-gray-2 placeholder-ink-gray-4 hover:border-outline-elevation-2 hover:bg-surface-gray-3 hover:shadow-sm focus:bg-surface-base focus:border-outline-gray-4 focus:shadow-sm focus:ring-0 focus-visible:ring-2 focus-visible:ring-outline-gray-3 text-ink-gray-8 transition-colors"
37 />
38 </template>
39 </Editor>
40 <div
41 v-if="getResponsePreviewResource.loading"
42 class="absolute top-0 end-0 flex items-center justify-center size-full rounded-5 bg-surface-gray-10/20"
43 >
44 <LoadingIndicator class="size-4" />
45 </div>
46 </div>
47 </div>
48 </div>
49 </template>
50 </Dialog>
51</template>
52
53<script setup lang="ts">
54import { Link } from "@/components";
55import { buildEditorExtensions } from "@/components/editor/config";
56import { __ } from "@/translation";
57import { RenderedSavedReply } from "@/types";
58import {
59 createListResource,
60 createResource,
61 Dialog,
62 FormLabel,
63 LoadingIndicator,
64 toast,
65} from "frappe-ui";
66import { Editor, EditorContent } from "frappe-ui/editor";
67import { watch } from "vue";
68const extensions = buildEditorExtensions();
69
70const dialogModel = defineModel<{
71 show: boolean;
72 ticketId: string;
73 savedReply: string;
74 preview: string;
75}>();
76
77const getResponsePreviewResource = createResource({
78 url: "opendesk.api.saved_replies.get_rendered_saved_reply",
79 onSuccess: (data: RenderedSavedReply) => {
80 dialogModel.value.preview = data.message;
81 },
82});
83
84const getResponsePreview = (ticketId: string) => {
85 if (!ticketId) return;
86 dialogModel.value.ticketId = ticketId;
87 dialogModel.value.preview = null;
88 getResponsePreviewResource.submit({
89 ticket_id: ticketId,
90 saved_reply_id: dialogModel.value.savedReply,
91 });
92};
93
94watch(
95 () => dialogModel.value.show,
96 (newShowValue) => {
97 if (newShowValue) {
98 createListResource({
99 doctype: "OD Ticket",
100 fields: ["name"],
101 start: 0,
102 pageLength: 1,
103 auto: true,
104 onSuccess: (data) => {
105 if (data.length === 0) {
106 toast.error(__("No tickets found to preview."));
107 return;
108 }
109 dialogModel.value.ticketId = data[0].name;
110 getResponsePreview(data[0].name);
111 },
112 });
113 }
114 }
115);
116</script>
117