Package and individual mail sender, new report, and other changes
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
@@ -43,6 +43,8 @@ const formSchema = toTypedSchema(
|
||||
value: z.string().email("E-pošta mora biti veljavna.").min(1, "E-pošta je obvezna."),
|
||||
label: z.string().optional(),
|
||||
receive_auto_mails: z.boolean().optional(),
|
||||
valid: z.boolean().default(true),
|
||||
failed: z.boolean().default(false),
|
||||
decision_ids: z.array(z.string()).optional().default([]),
|
||||
})
|
||||
);
|
||||
@@ -54,6 +56,8 @@ const form = useForm({
|
||||
value: "",
|
||||
label: "",
|
||||
receive_auto_mails: false,
|
||||
valid: true,
|
||||
failed: false,
|
||||
decision_ids: [],
|
||||
},
|
||||
});
|
||||
@@ -78,6 +82,8 @@ const resetForm = () => {
|
||||
value: "",
|
||||
label: "",
|
||||
receive_auto_mails: false,
|
||||
valid: true,
|
||||
failed: false,
|
||||
decision_ids: [],
|
||||
},
|
||||
});
|
||||
@@ -182,6 +188,8 @@ watch(
|
||||
value: email.value ?? email.email ?? email.address ?? "",
|
||||
label: email.label ?? "",
|
||||
receive_auto_mails: !!email.receive_auto_mails,
|
||||
valid: email.valid !== undefined ? !!email.valid : true,
|
||||
failed: !!email.failed,
|
||||
decision_ids: existingDecisionIds,
|
||||
});
|
||||
} else {
|
||||
@@ -272,6 +280,28 @@ const onConfirm = () => {
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<FormField v-slot="{ value, handleChange }" name="valid">
|
||||
<FormItem class="flex flex-row items-start space-x-3 space-y-0">
|
||||
<FormControl>
|
||||
<Switch :model-value="value" @update:model-value="handleChange" />
|
||||
</FormControl>
|
||||
<div class="space-y-1 leading-none">
|
||||
<FormLabel class="cursor-pointer">Veljavna</FormLabel>
|
||||
</div>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<FormField v-slot="{ value, handleChange }" name="failed">
|
||||
<FormItem class="flex flex-row items-start space-x-3 space-y-0">
|
||||
<FormControl>
|
||||
<Switch :model-value="value" @update:model-value="handleChange" />
|
||||
</FormControl>
|
||||
<div class="space-y-1 leading-none">
|
||||
<FormLabel class="cursor-pointer">Neuspešna dostava</FormLabel>
|
||||
</div>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<!-- Limit to specific decisions — only shown when receive_auto_mails is on and decisions exist -->
|
||||
<template v-if="(props.person?.client || isClientContext) && form.values.receive_auto_mails && decisionOptions.length > 0">
|
||||
<div class="flex flex-row items-start space-x-3 space-y-0">
|
||||
|
||||
@@ -0,0 +1,483 @@
|
||||
<script setup>
|
||||
import { ref, watch, computed, nextTick } from "vue";
|
||||
import axios from "axios";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/Components/ui/dialog";
|
||||
import { router, usePage } from "@inertiajs/vue3";
|
||||
import { useForm, Field as FormField } from "vee-validate";
|
||||
import { toTypedSchema } from "@vee-validate/zod";
|
||||
import * as z from "zod";
|
||||
import { FormControl, FormItem, FormLabel, FormMessage } from "@/Components/ui/form";
|
||||
import { Input } from "@/Components/ui/input";
|
||||
import { Textarea } from "@/Components/ui/textarea";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/Components/ui/select";
|
||||
import { Button } from "@/Components/ui/button";
|
||||
import { ScrollArea } from "@/Components/ui/scroll-area";
|
||||
|
||||
const props = defineProps({
|
||||
show: { type: Boolean, default: false },
|
||||
email: { type: Object, default: null },
|
||||
clientCaseUuid: { type: String, default: null },
|
||||
emailTemplates: { type: Array, default: () => [] },
|
||||
mailProfiles: { type: Array, default: () => [] },
|
||||
});
|
||||
|
||||
const emit = defineEmits(["close"]);
|
||||
|
||||
const page = usePage();
|
||||
const pageProps = computed(() => page?.props ?? {});
|
||||
|
||||
const pageEmailTemplates = computed(() => {
|
||||
const fromProps =
|
||||
Array.isArray(props.emailTemplates) && props.emailTemplates.length
|
||||
? props.emailTemplates
|
||||
: null;
|
||||
return fromProps ?? pageProps.value?.email_templates ?? [];
|
||||
});
|
||||
|
||||
const pageMailProfiles = computed(() => {
|
||||
const fromProps =
|
||||
Array.isArray(props.mailProfiles) && props.mailProfiles.length
|
||||
? props.mailProfiles
|
||||
: null;
|
||||
return fromProps ?? pageProps.value?.mail_profiles ?? [];
|
||||
});
|
||||
|
||||
// Form schema
|
||||
const formSchema = toTypedSchema(
|
||||
z.object({
|
||||
subject: z.string().min(1, "Zadeva je obvezna.").max(255),
|
||||
html_body: z.string().nullable().optional(),
|
||||
body_text: z.string().max(10000).nullable().optional(),
|
||||
template_id: z.number().nullable().optional(),
|
||||
mail_profile_id: z.number().nullable().optional(),
|
||||
contract_uuid: z.string().nullable().optional(),
|
||||
})
|
||||
);
|
||||
|
||||
const form = useForm({
|
||||
validationSchema: formSchema,
|
||||
initialValues: {
|
||||
subject: "",
|
||||
html_body: "",
|
||||
body_text: "",
|
||||
template_id: null,
|
||||
mail_profile_id: null,
|
||||
contract_uuid: null,
|
||||
},
|
||||
});
|
||||
|
||||
const processing = ref(false);
|
||||
const contractsForCase = ref([]);
|
||||
const hasBodyText = ref(false); // whether selected template uses {{body_text}}
|
||||
|
||||
// WYSIWYG iframe
|
||||
const iframeRef = ref(null);
|
||||
let iframeSyncing = false;
|
||||
|
||||
function ensureFullDoc(html) {
|
||||
if (!html) {
|
||||
return '<!doctype html><html><head><meta charset="utf-8" /></head><body></body></html>';
|
||||
}
|
||||
if (/<html[\s\S]*<\/html>/i.test(html)) return html;
|
||||
return `<!doctype html><html><head><meta charset="utf-8" /></head><body>${html}</body></html>`;
|
||||
}
|
||||
|
||||
function writeIframeDocument(html) {
|
||||
const iframe = iframeRef.value;
|
||||
if (!iframe) return;
|
||||
const doc = iframe.contentDocument;
|
||||
if (!doc) return;
|
||||
const full = ensureFullDoc(html ?? form.values.html_body ?? "");
|
||||
doc.open();
|
||||
doc.write(full);
|
||||
doc.close();
|
||||
try {
|
||||
doc.body.setAttribute("spellcheck", "false");
|
||||
} catch {}
|
||||
}
|
||||
|
||||
function initIframeEditor(html) {
|
||||
writeIframeDocument(html);
|
||||
const iframe = iframeRef.value;
|
||||
if (!iframe) return;
|
||||
const doc = iframe.contentDocument;
|
||||
if (!doc) return;
|
||||
try {
|
||||
doc.designMode = "on";
|
||||
} catch {}
|
||||
|
||||
const syncHandler = () => {
|
||||
if (iframeSyncing) return;
|
||||
try {
|
||||
iframeSyncing = true;
|
||||
const full = doc.documentElement.outerHTML;
|
||||
form.setFieldValue("html_body", full);
|
||||
} finally {
|
||||
iframeSyncing = false;
|
||||
}
|
||||
};
|
||||
|
||||
doc.removeEventListener("input", syncHandler);
|
||||
doc.removeEventListener("keyup", syncHandler);
|
||||
doc.addEventListener("input", syncHandler);
|
||||
doc.addEventListener("keyup", syncHandler);
|
||||
}
|
||||
|
||||
function iframeExec(command) {
|
||||
const iframe = iframeRef.value;
|
||||
if (!iframe) return;
|
||||
const doc = iframe.contentDocument;
|
||||
if (!doc) return;
|
||||
try {
|
||||
doc.body.focus();
|
||||
} catch {}
|
||||
try {
|
||||
doc.execCommand(command, false, null);
|
||||
} catch (e) {
|
||||
console.warn("execCommand failed", command, e);
|
||||
}
|
||||
}
|
||||
|
||||
// Load template preview from server
|
||||
const loadingPreview = ref(false);
|
||||
|
||||
const updateFromTemplate = async () => {
|
||||
if (!form.values.template_id || !props.clientCaseUuid) return;
|
||||
loadingPreview.value = true;
|
||||
try {
|
||||
const url = route("clientCase.email.preview", {
|
||||
client_case: props.clientCaseUuid,
|
||||
email_id: props.email?.id,
|
||||
});
|
||||
const { data } = await axios.post(url, {
|
||||
template_id: form.values.template_id,
|
||||
contract_uuid: form.values.contract_uuid || null,
|
||||
body_text: form.values.body_text || "",
|
||||
});
|
||||
const hadBodyText = hasBodyText.value;
|
||||
hasBodyText.value = !!data?.has_body_text;
|
||||
// Pre-fill body_text from text_template when the placeholder is present and field is empty
|
||||
if (data?.has_body_text && !hadBodyText) {
|
||||
const tpl = pageEmailTemplates.value.find((t) => t.id === form.values.template_id);
|
||||
if (tpl?.text_template && !form.values.body_text) {
|
||||
form.setFieldValue("body_text", tpl.text_template);
|
||||
}
|
||||
}
|
||||
if (data?.subject) {
|
||||
form.setFieldValue("subject", data.subject);
|
||||
}
|
||||
const html = data?.html ?? "";
|
||||
form.setFieldValue("html_body", html);
|
||||
await nextTick();
|
||||
initIframeEditor(html);
|
||||
} catch (e) {
|
||||
// ignore
|
||||
} finally {
|
||||
loadingPreview.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
() => form.values.template_id,
|
||||
() => {
|
||||
updateFromTemplate();
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => form.values.contract_uuid,
|
||||
() => {
|
||||
if (form.values.template_id) {
|
||||
updateFromTemplate();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Re-preview when body_text changes (debounce-like: only when a template is active)
|
||||
watch(
|
||||
() => form.values.body_text,
|
||||
() => {
|
||||
if (form.values.template_id && hasBodyText.value) {
|
||||
updateFromTemplate();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const loadContractsForCase = async () => {
|
||||
try {
|
||||
const url = route("clientCase.contracts.list", {
|
||||
client_case: props.clientCaseUuid,
|
||||
});
|
||||
const res = await fetch(url, {
|
||||
headers: { "X-Requested-With": "XMLHttpRequest" },
|
||||
credentials: "same-origin",
|
||||
});
|
||||
const json = await res.json();
|
||||
contractsForCase.value = Array.isArray(json?.data) ? json.data : [];
|
||||
} catch (e) {
|
||||
contractsForCase.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.show,
|
||||
async (newVal) => {
|
||||
if (newVal) {
|
||||
form.resetForm({
|
||||
values: {
|
||||
subject: "",
|
||||
html_body: "",
|
||||
body_text: "",
|
||||
template_id: null,
|
||||
mail_profile_id: pageMailProfiles.value?.[0]?.id ?? null,
|
||||
contract_uuid: null,
|
||||
},
|
||||
});
|
||||
hasBodyText.value = false;
|
||||
contractsForCase.value = [];
|
||||
await loadContractsForCase();
|
||||
// Init empty iframe
|
||||
await nextTick();
|
||||
initIframeEditor("");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const closeDialog = () => {
|
||||
emit("close");
|
||||
};
|
||||
|
||||
const onSubmit = form.handleSubmit((values) => {
|
||||
if (!props.email || !props.clientCaseUuid) return;
|
||||
processing.value = true;
|
||||
router.post(
|
||||
route("clientCase.email.send", {
|
||||
client_case: props.clientCaseUuid,
|
||||
email_id: props.email.id,
|
||||
}),
|
||||
values,
|
||||
{
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
processing.value = false;
|
||||
closeDialog();
|
||||
},
|
||||
onError: () => {
|
||||
processing.value = false;
|
||||
},
|
||||
onFinish: () => {
|
||||
processing.value = false;
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
const open = computed({
|
||||
get: () => props.show,
|
||||
set: (value) => {
|
||||
if (!value) closeDialog();
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog v-model:open="open">
|
||||
<DialogContent class="sm:max-w-2xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Pošlji e-pošto</DialogTitle>
|
||||
<DialogDescription>
|
||||
<p class="text-sm text-gray-600">
|
||||
Prejemnik:
|
||||
<span class="font-mono">{{ email?.value || email?.email || email?.address }}</span>
|
||||
</p>
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<ScrollArea class="max-h-[70vh] pr-1">
|
||||
<form @submit.prevent="onSubmit" class="space-y-4 pr-3">
|
||||
<!-- Mail profile -->
|
||||
<FormField v-slot="{ value, handleChange }" name="mail_profile_id">
|
||||
<FormItem>
|
||||
<FormLabel>E-poštni profil</FormLabel>
|
||||
<Select :model-value="value" @update:model-value="handleChange">
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="—" />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
<SelectItem :value="null">—</SelectItem>
|
||||
<SelectItem
|
||||
v-for="p in pageMailProfiles"
|
||||
:key="p.id"
|
||||
:value="p.id"
|
||||
>
|
||||
{{ p.name || "Profil #" + p.id }}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<!-- Contract -->
|
||||
<FormField v-slot="{ value, handleChange }" name="contract_uuid">
|
||||
<FormItem>
|
||||
<FormLabel>Pogodba</FormLabel>
|
||||
<Select :model-value="value" @update:model-value="handleChange">
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="—" />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
<SelectItem :value="null">—</SelectItem>
|
||||
<SelectItem
|
||||
v-for="c in contractsForCase"
|
||||
:key="c.uuid"
|
||||
:value="c.uuid"
|
||||
>
|
||||
{{ c.reference || c.uuid }}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p class="mt-1 text-xs text-gray-500">
|
||||
Izberite pogodbo za zapolnitev spremenljivk v predlogi.
|
||||
</p>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<!-- Template -->
|
||||
<FormField v-slot="{ value, handleChange }" name="template_id">
|
||||
<FormItem>
|
||||
<FormLabel>Predloga</FormLabel>
|
||||
<Select
|
||||
:model-value="value"
|
||||
@update:model-value="handleChange"
|
||||
:disabled="loadingPreview"
|
||||
>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="—" />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
<SelectItem :value="null">—</SelectItem>
|
||||
<SelectItem
|
||||
v-for="t in pageEmailTemplates"
|
||||
:key="t.id"
|
||||
:value="t.id"
|
||||
>
|
||||
{{ t.name || "Predloga #" + t.id }}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<!-- Subject -->
|
||||
<FormField v-slot="{ componentField }" name="subject">
|
||||
<FormItem>
|
||||
<FormLabel>Zadeva</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="Zadeva e-poštnega sporočila..."
|
||||
v-bind="componentField"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<!-- body_text textarea — shown only when the template uses {{body_text}} -->
|
||||
<FormField v-if="hasBodyText" v-slot="{ componentField }" name="body_text">
|
||||
<FormItem>
|
||||
<FormLabel>Besedilo sporočila</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea
|
||||
placeholder="Vnesite besedilo, ki se vstavi na mesto {{body_text}} v predlogi..."
|
||||
class="min-h-[120px] resize-y"
|
||||
v-bind="componentField"
|
||||
/>
|
||||
</FormControl>
|
||||
<p class="mt-1 text-xs text-gray-500">
|
||||
Besedilo se vstavi na oznako <code>{{body_text}}</code> v predlogi. Besedilo ne podpira spremenljivk.
|
||||
</p>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<!-- WYSIWYG body editor -->
|
||||
<div>
|
||||
<label class="text-sm font-medium leading-none">Vsebina</label>
|
||||
<!-- Toolbar -->
|
||||
<div class="flex gap-1 mt-2 mb-1 border rounded-t-md bg-gray-50 p-1">
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
class="font-bold px-2 py-1 h-7"
|
||||
title="Krepko (Ctrl+B)"
|
||||
@click="iframeExec('bold')"
|
||||
>B</Button>
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
class="italic px-2 py-1 h-7"
|
||||
title="Poševno (Ctrl+I)"
|
||||
@click="iframeExec('italic')"
|
||||
>I</Button>
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
class="underline px-2 py-1 h-7"
|
||||
title="Podčrtano (Ctrl+U)"
|
||||
@click="iframeExec('underline')"
|
||||
>U</Button>
|
||||
</div>
|
||||
<iframe
|
||||
ref="iframeRef"
|
||||
class="w-full border rounded-b-md bg-white"
|
||||
style="min-height: 240px; max-height: 360px"
|
||||
frameborder="0"
|
||||
sandbox="allow-same-origin allow-scripts"
|
||||
/>
|
||||
<p class="mt-1 text-xs text-gray-500">
|
||||
Kliknite v vsebino in začnite pisati. Izberite predlogo za samodejno zapolnitev.
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
</ScrollArea>
|
||||
|
||||
<DialogFooter>
|
||||
<Button variant="outline" @click="closeDialog" :disabled="processing">
|
||||
Prekliči
|
||||
</Button>
|
||||
<Button
|
||||
@click="onSubmit"
|
||||
:disabled="processing || !form.values.subject"
|
||||
>
|
||||
{{ processing ? "Pošiljanje..." : "Pošlji" }}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
@@ -8,14 +8,16 @@ import {
|
||||
} from "@/Components/ui/dropdown-menu";
|
||||
import { Card } from "@/Components/ui/card";
|
||||
import { Button } from "../ui/button";
|
||||
import { EllipsisVertical } from "lucide-vue-next";
|
||||
import { CircleCheckBigIcon, CircleXIcon, EllipsisVertical, MailIcon } from "lucide-vue-next";
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../ui/tooltip";
|
||||
|
||||
const props = defineProps({
|
||||
person: Object,
|
||||
edit: { type: Boolean, default: true },
|
||||
enableEmail: { type: Boolean, default: false },
|
||||
});
|
||||
|
||||
const emit = defineEmits(["add", "edit", "delete"]);
|
||||
const emit = defineEmits(["add", "edit", "delete", "email"]);
|
||||
|
||||
const getEmails = (p) => (Array.isArray(p?.emails) ? p.emails : []);
|
||||
|
||||
@@ -44,7 +46,17 @@ const handleDelete = (id, label) => emit("delete", id, label);
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="edit">
|
||||
<DropdownMenu>
|
||||
<div class="flex items-center gap-1">
|
||||
<Button
|
||||
v-if="enableEmail"
|
||||
@click="$emit('email', email)"
|
||||
title="Pošlji e-pošto"
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
>
|
||||
<MailIcon :size="18" />
|
||||
</Button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<Button variant="ghost" size="icon" title="Možnosti">
|
||||
<EllipsisVertical />
|
||||
@@ -66,11 +78,28 @@ const handleDelete = (id, label) => emit("delete", id, label);
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-1">
|
||||
<p class="font-medium text-gray-900 leading-relaxed">
|
||||
<p class="font-medium text-gray-900 leading-relaxed flex gap-1 items-center">
|
||||
{{ email?.value || email?.email || email?.address || "-" }}
|
||||
<TooltipProvider v-if="email?.valid">
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<CircleCheckBigIcon color="#3e9392" :size="18" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Veljavna</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
<TooltipProvider v-if="email?.failed">
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<CircleXIcon color="#dc2626" :size="18" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Neuspešna dostava</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</p>
|
||||
<p
|
||||
v-if="email?.note"
|
||||
|
||||
@@ -30,6 +30,7 @@ import PersonInfoPhonesTab from "./PersonInfoPhonesTab.vue";
|
||||
import PersonInfoEmailsTab from "./PersonInfoEmailsTab.vue";
|
||||
import PersonInfoTrrTab from "./PersonInfoTrrTab.vue";
|
||||
import PersonInfoSmsDialog from "./PersonInfoSmsDialog.vue";
|
||||
import PersonInfoEmailDialog from "./PersonInfoEmailDialog.vue";
|
||||
import { Badge } from "@/Components/ui/badge";
|
||||
|
||||
const props = defineProps({
|
||||
@@ -58,6 +59,9 @@ const props = defineProps({
|
||||
smsProfiles: { type: Array, default: () => [] },
|
||||
smsSenders: { type: Array, default: () => [] },
|
||||
smsTemplates: { type: Array, default: () => [] },
|
||||
enableEmail: { type: Boolean, default: false },
|
||||
emailTemplates: { type: Array, default: () => [] },
|
||||
mailProfiles: { type: Array, default: () => [] },
|
||||
});
|
||||
|
||||
// Dialog states
|
||||
@@ -91,6 +95,10 @@ const confirm = ref({
|
||||
const showSmsDialog = ref(false);
|
||||
const smsTargetPhone = ref(null);
|
||||
|
||||
// Email dialog state
|
||||
const showEmailDialog = ref(false);
|
||||
const emailTarget = ref(null);
|
||||
|
||||
// Person handlers
|
||||
const openDrawerUpdateClient = () => {
|
||||
drawerUpdatePerson.value = true;
|
||||
@@ -251,6 +259,18 @@ const closeSmsDialog = () => {
|
||||
smsTargetPhone.value = null;
|
||||
};
|
||||
|
||||
// Email dialog handlers
|
||||
const openEmailDialog = (email) => {
|
||||
if (!props.enableEmail || !props.clientCaseUuid) return;
|
||||
emailTarget.value = email;
|
||||
showEmailDialog.value = true;
|
||||
};
|
||||
|
||||
const closeEmailDialog = () => {
|
||||
showEmailDialog.value = false;
|
||||
emailTarget.value = null;
|
||||
};
|
||||
|
||||
// Tab event handlers
|
||||
const handlePersonEdit = () => openDrawerUpdateClient();
|
||||
|
||||
@@ -266,6 +286,7 @@ const handlePhoneSms = (phone) => openSmsDialog(phone);
|
||||
const handleEmailAdd = () => openDrawerAddEmail(false, 0);
|
||||
const handleEmailEdit = (id) => openDrawerAddEmail(true, id);
|
||||
const handleEmailDelete = (id, label) => openConfirm("email", id, label);
|
||||
const handleEmailSend = (email) => openEmailDialog(email);
|
||||
|
||||
const handleTrrAdd = () => openDrawerAddTrr(false, 0);
|
||||
const handleTrrEdit = (id) => openDrawerAddTrr(true, id);
|
||||
@@ -418,9 +439,11 @@ const switchToTab = (tab) => {
|
||||
<PersonInfoEmailsTab
|
||||
:person="person"
|
||||
:edit="edit"
|
||||
:enable-email="enableEmail && !!clientCaseUuid"
|
||||
@add="handleEmailAdd"
|
||||
@edit="handleEmailEdit"
|
||||
@delete="handleEmailDelete"
|
||||
@email="handleEmailSend"
|
||||
/>
|
||||
</TabsContent>
|
||||
|
||||
@@ -534,4 +557,15 @@ const switchToTab = (tab) => {
|
||||
:sms-templates="smsTemplates"
|
||||
@close="closeSmsDialog"
|
||||
/>
|
||||
|
||||
<!-- Email Dialog -->
|
||||
<PersonInfoEmailDialog
|
||||
v-if="clientCaseUuid"
|
||||
:show="showEmailDialog"
|
||||
:email="emailTarget"
|
||||
:client-case-uuid="clientCaseUuid"
|
||||
:email-templates="emailTemplates"
|
||||
:mail-profiles="mailProfiles"
|
||||
@close="closeEmailDialog"
|
||||
/>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user