Added E-Mail Sending
This commit is contained in:
@@ -1,72 +1,83 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="p-3 mt-3 editor">
|
||||
<div v-if="editor">
|
||||
<InputGroup class="mx-3 mt-3">
|
||||
<InputGroup class="mb-3">
|
||||
<UButton
|
||||
@click="editor.chain().focus().toggleBold().run()"
|
||||
:disabled="!editor.can().chain().focus().toggleBold().run()"
|
||||
:class="{ 'is-active': editor.isActive('bold') }"
|
||||
icon="i-heroicons-bold"
|
||||
variant="outline"
|
||||
/>
|
||||
<UButton
|
||||
@click="editor.chain().focus().toggleItalic().run()"
|
||||
:disabled="!editor.can().chain().focus().toggleItalic().run()"
|
||||
:class="{ 'is-active': editor.isActive('italic') }"
|
||||
icon="i-heroicons-italic"
|
||||
variant="outline"
|
||||
/>
|
||||
<UButton
|
||||
@click="editor.chain().focus().toggleStrike().run()"
|
||||
:disabled="!editor.can().chain().focus().toggleStrike().run()"
|
||||
:class="{ 'is-active': editor.isActive('strike') }"
|
||||
icon="i-mdi-format-strikethrough"
|
||||
variant="outline"
|
||||
/>
|
||||
<UButton
|
||||
<!--<UButton
|
||||
@click="editor.chain().focus().toggleCode().run()"
|
||||
:disabled="!editor.can().chain().focus().toggleCode().run()"
|
||||
:class="{ 'is-active': editor.isActive('code') }"
|
||||
icon="i-heroicons-code-bracket"
|
||||
variant="outline"
|
||||
/>
|
||||
<!-- <UButton @click="editor.chain().focus().unsetAllMarks().run()">
|
||||
<UButton @click="editor.chain().focus().unsetAllMarks().run()">
|
||||
clear marks
|
||||
</UButton>
|
||||
<UButton @click="editor.chain().focus().clearNodes().run()">
|
||||
clear nodes
|
||||
</UButton>-->
|
||||
</UButton>
|
||||
<UButton
|
||||
@click="editor.chain().focus().setParagraph().run()"
|
||||
:class="{ 'is-active': editor.isActive('paragraph') }"
|
||||
variant="outline"
|
||||
>
|
||||
paragraph
|
||||
</UButton>
|
||||
</UButton>-->
|
||||
<UButton
|
||||
@click="editor.chain().focus().toggleHeading({ level: 1 }).run()"
|
||||
:class="{ 'is-active': editor.isActive('heading', { level: 1 }) }"
|
||||
variant="outline"
|
||||
>h1</UButton>
|
||||
<UButton
|
||||
@click="editor.chain().focus().toggleHeading({ level: 2 }).run()"
|
||||
:class="{ 'is-active': editor.isActive('heading', { level: 2 }) }"
|
||||
variant="outline"
|
||||
>h2</UButton>
|
||||
<UButton
|
||||
@click="editor.chain().focus().toggleHeading({ level: 3 }).run()"
|
||||
:class="{ 'is-active': editor.isActive('heading', { level: 3 }) }"
|
||||
variant="outline"
|
||||
>
|
||||
h3
|
||||
</UButton>
|
||||
<UButton
|
||||
@click="editor.chain().focus().toggleHeading({ level: 4 }).run()"
|
||||
:class="{ 'is-active': editor.isActive('heading', { level: 4 }) }"
|
||||
variant="outline"
|
||||
>
|
||||
h4
|
||||
</UButton>
|
||||
<UButton
|
||||
@click="editor.chain().focus().toggleHeading({ level: 5 }).run()"
|
||||
:class="{ 'is-active': editor.isActive('heading', { level: 5 }) }"
|
||||
variant="outline"
|
||||
>
|
||||
h5
|
||||
</UButton>
|
||||
<UButton
|
||||
@click="editor.chain().focus().toggleHeading({ level: 6 }).run()"
|
||||
:class="{ 'is-active': editor.isActive('heading', { level: 6 }) }"
|
||||
variant="outline"
|
||||
>
|
||||
h6
|
||||
</UButton>
|
||||
@@ -74,11 +85,13 @@
|
||||
@click="editor.chain().focus().toggleBulletList().run()"
|
||||
:class="{ 'is-active': editor.isActive('bulletList') }"
|
||||
icon="i-heroicons-list-bullet"
|
||||
variant="outline"
|
||||
/>
|
||||
<UButton
|
||||
@click="editor.chain().focus().toggleOrderedList().run()"
|
||||
:class="{ 'is-active': editor.isActive('orderedList') }"
|
||||
icon="i-mdi-format-list-numbered"
|
||||
variant="outline"
|
||||
/>
|
||||
<!-- <UButton
|
||||
@click="editor.chain().focus().toggleCodeBlock().run()"
|
||||
@@ -120,12 +133,40 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const emit = defineEmits(['updateContent'])
|
||||
|
||||
const props = defineProps({
|
||||
preloadedContent: {
|
||||
type: String,
|
||||
required:false
|
||||
}
|
||||
})
|
||||
|
||||
const {preloadedContent} = props
|
||||
|
||||
const editor = useEditor({
|
||||
content: "<p>I'm running Tiptap with Vue.js. 🎉</p>",
|
||||
extensions: [TiptapStarterKit],
|
||||
onUpdate({editor}) {
|
||||
console.log(editor.getJSON())
|
||||
console.log(editor.getHTML())
|
||||
console.log(editor.getText())
|
||||
emit('updateContent',{json: editor.getJSON(),html: editor.getHTML(), text: editor.getText()})
|
||||
},
|
||||
onCreate({editor}) {
|
||||
editor.commands.setContent(preloadedContent)
|
||||
emit('updateContent',{json: editor.getJSON(),html: editor.getHTML(), text: editor.getText()})
|
||||
}
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
unref(editor).destroy();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.editor {
|
||||
border: 1px solid #69c350;
|
||||
border-radius: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -136,33 +136,65 @@ setupPage()
|
||||
v-model="openTab"
|
||||
>
|
||||
<template #item="{item}">
|
||||
<UCard class="mt-5">
|
||||
<div v-if="item.label === 'Informationen'">
|
||||
<div v-if="item.label === 'Informationen'" class="flex flex-row mt-5">
|
||||
<div class="w-1/2 mr-5">
|
||||
<UCard>
|
||||
<Toolbar>
|
||||
<UButton
|
||||
@click="router.push(`/email/new?to=${itemInfo.email}`)"
|
||||
icon="i-heroicons-envelope"
|
||||
:disabled="!itemInfo.email"
|
||||
>
|
||||
E-Mail
|
||||
</UButton>
|
||||
</Toolbar>
|
||||
<table class="w-full">
|
||||
<tr>
|
||||
<td>Kunde: </td>
|
||||
<td><nuxt-link v-if="itemInfo.customer" :to="`/customers/show/${itemInfo.customer?.id}`">{{itemInfo?.customer?.name}}</nuxt-link></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Lieferant: </td>
|
||||
<td><nuxt-link v-if="itemInfo.vendor" :to="`/customers/show/${itemInfo.vendor?.id}`">{{itemInfo?.vendor?.name}}</nuxt-link></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>E-Mail:</td>
|
||||
<td>{{itemInfo.email}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Mobil:</td>
|
||||
<td>{{itemInfo.phoneMobile}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Festnetz:</td>
|
||||
<td>{{itemInfo.phoneHome}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Rolle:</td>
|
||||
<td>{{itemInfo.role}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Geburtstag:</td>
|
||||
<td>{{itemInfo.birthday ? dayjs(itemInfo.birthday).format("DD.MM.YYYY") : ""}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Notizen:</td>
|
||||
<td>{{itemInfo.notes}}</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<div class="text-wrap mt-3">
|
||||
<p v-if="itemInfo.customer">Kunde: <nuxt-link :to="`/customers/show/${itemInfo.customer.id}`">{{itemInfo.customer ? itemInfo.customer.name : ""}}</nuxt-link></p>
|
||||
<p v-if="itemInfo.vendor">Lieferant: <nuxt-link :to="`/vendors/show/${itemInfo.vendor.id}`">{{itemInfo.vendor ? itemInfo.vendor.name : ""}}</nuxt-link></p>
|
||||
|
||||
|
||||
<p>E-Mail: {{itemInfo.email}}</p>
|
||||
<p>Mobil: {{itemInfo.phoneMobile}}</p>
|
||||
<p>Festnetz: {{itemInfo.phoneHome}}</p>
|
||||
<p>Rolle: {{itemInfo.role}}</p>
|
||||
<p>Geburtstag: {{itemInfo.birthday ? dayjs(itemInfo.birthday).format("DD.MM.YYYY") : ""}}</p>
|
||||
<p>Notizen:<br> {{itemInfo.notes}}</p>
|
||||
</table>
|
||||
</UCard>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div v-else-if="item.label === 'Logbuch'">
|
||||
<div class="w-1/2">
|
||||
<UCard>
|
||||
<HistoryDisplay
|
||||
type="contact"
|
||||
v-if="itemInfo"
|
||||
:element-id="itemInfo.id"
|
||||
/>
|
||||
</div>
|
||||
</UCard>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</UTabs>
|
||||
<UForm
|
||||
@@ -289,5 +321,10 @@ setupPage()
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
td {
|
||||
border-bottom: 1px solid lightgrey;
|
||||
vertical-align: top;
|
||||
padding-bottom: 0.15em;
|
||||
padding-top: 0.15em;
|
||||
}
|
||||
</style>
|
||||
@@ -9,16 +9,19 @@ defineShortcuts({
|
||||
},
|
||||
})
|
||||
|
||||
const supabase = useSupabaseClient()
|
||||
|
||||
const dataStore = useDataStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const itemInfo = ref({})
|
||||
const linkedDocument =ref({})
|
||||
|
||||
const setupPage = () => {
|
||||
const setupPage = async () => {
|
||||
if(route.params) {
|
||||
if(route.params.id) itemInfo.value = dataStore.getCreatedDocumentById(Number(route.params.id))
|
||||
if(route.params.id) itemInfo.value = await useSupabaseSelectSingle("createddocuments",route.params.id,"*")
|
||||
linkedDocument.value = (await supabase.from("documents").select("id").eq("createdDocument", route.params.id).single()).data
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,9 +50,17 @@ setupPage()
|
||||
>
|
||||
Übernehmen
|
||||
</UButton>
|
||||
<UButton
|
||||
@click="router.push(`/email/new?loadDocuments=[${linkedDocument.id}]`)"
|
||||
icon="i-heroicons-envelope"
|
||||
>
|
||||
E-Mail
|
||||
</UButton>
|
||||
</template>
|
||||
</UDashboardToolbar>
|
||||
|
||||
{{linkedDocument}}
|
||||
|
||||
<object
|
||||
:data="dataStore.documents.find(i => i.createdDocument === itemInfo.id) ? dataStore.documents.find(i => i.createdDocument === itemInfo.id).url : ''"
|
||||
class="h-full"
|
||||
|
||||
279
pages/email/index.vue
Normal file
279
pages/email/index.vue
Normal file
@@ -0,0 +1,279 @@
|
||||
<script setup>
|
||||
|
||||
const supabase = useSupabaseClient()
|
||||
const dataStore = useDataStore()
|
||||
|
||||
|
||||
const selectedTab = ref(0)
|
||||
const selectedMail = ref(null)
|
||||
const selectedMailboxPath = ref("INBOX")
|
||||
const emails = ref([])
|
||||
const accountData = ref(null)
|
||||
const availableAccounts = ref(null)
|
||||
const selectedAccount = ref(null)
|
||||
const setupPage = async () => {
|
||||
availableAccounts.value = (await supabase.from("emailAccounts").select("*").contains("profiles",[dataStore.activeProfile.id])).data
|
||||
console.log(availableAccounts.value)
|
||||
|
||||
if(availableAccounts.value.length > 0) {
|
||||
selectedAccount.value = availableAccounts.value[0].id
|
||||
accountData.value = await useSupabaseSelectSingle("emailAccounts", selectedAccount.value)
|
||||
emails.value = await useSupabaseSelect("emailMessages", "*", "date", false)
|
||||
}
|
||||
}
|
||||
|
||||
const filteredMails = computed(() => {
|
||||
|
||||
let temp = emails.value.filter(i => i.mailboxPath.toLowerCase() === selectedMailboxPath.value.toLowerCase())
|
||||
|
||||
|
||||
if(selectedTab.value === 0){
|
||||
return temp
|
||||
} else {
|
||||
return temp.filter(i => !i.seen)
|
||||
}
|
||||
|
||||
|
||||
return emails.value
|
||||
})
|
||||
|
||||
const isMailPanelOpen = computed({
|
||||
get() {
|
||||
return !!selectedMail.value
|
||||
},
|
||||
set(value) {
|
||||
if (!value) {
|
||||
selectedMail.value = null
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const changeSeen = async (seen) => {
|
||||
const {data,error} = await supabase.functions.invoke('emailcontrol',{
|
||||
body: {
|
||||
method: seen ? "makeSeen" : "makeUnseen",
|
||||
emailId: selectedMail.value.id
|
||||
}
|
||||
})
|
||||
|
||||
if(data) {
|
||||
setupPage()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
setupPage()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- <UDashboardNavbar title="E-Mails">
|
||||
|
||||
</UDashboardNavbar>
|
||||
<UDashboardToolbar>
|
||||
|
||||
</UDashboardToolbar>-->
|
||||
<UDashboardPage
|
||||
v-if="selectedAccount"
|
||||
>
|
||||
<UDashboardPanel
|
||||
id="inbox"
|
||||
:width="400"
|
||||
:resizable="{ min: 300, max: 500 }"
|
||||
|
||||
>
|
||||
<UDashboardNavbar>
|
||||
<template #left>
|
||||
<USelectMenu
|
||||
v-if="accountData"
|
||||
class="w-40"
|
||||
:options="accountData.mailboxes"
|
||||
option-attribute="name"
|
||||
value-attribute="path"
|
||||
v-model="selectedMailboxPath"
|
||||
/>
|
||||
</template>
|
||||
<template #right>
|
||||
<UButton
|
||||
icon="i-heroicons-arrow-path"
|
||||
variant="ghost"
|
||||
color="gray"
|
||||
@click="setupPage"
|
||||
/>
|
||||
|
||||
<UTabs
|
||||
v-model="selectedTab"
|
||||
:items="[{label: 'All'}, {label: 'Ungelesen'}]"
|
||||
:ui="{ wrapper: '', list: { height: 'h-9', tab: { height: 'h-7', size: 'text-[13px]' } } }"
|
||||
/>
|
||||
</template>
|
||||
</UDashboardNavbar>
|
||||
|
||||
<!-- ~/components/inbox/InboxList.vue -->
|
||||
<InboxList
|
||||
v-model="selectedMail"
|
||||
:mails="filteredMails"
|
||||
@emailSelected=" !selectedMail.seen ? changeSeen(true): ''"
|
||||
/>
|
||||
</UDashboardPanel>
|
||||
<UDashboardPanel
|
||||
v-model="isMailPanelOpen"
|
||||
collapsible
|
||||
grow
|
||||
side="right"
|
||||
>
|
||||
<template v-if="selectedMail">
|
||||
<UDashboardNavbar>
|
||||
<template #toggle>
|
||||
<UDashboardNavbarToggle icon="i-heroicons-x-mark" />
|
||||
|
||||
<UDivider
|
||||
orientation="vertical"
|
||||
class="mx-1.5 lg:hidden"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #left>
|
||||
<UTooltip text="Ungelesen">
|
||||
<UButton
|
||||
icon="i-heroicons-eye-slash"
|
||||
color="gray"
|
||||
variant="ghost"
|
||||
@click="changeSeen(false)"
|
||||
/>
|
||||
</UTooltip>
|
||||
<!-- <UTooltip text="Archive">
|
||||
<UButton
|
||||
icon="i-heroicons-archive-box"
|
||||
color="gray"
|
||||
variant="ghost"
|
||||
/>
|
||||
</UTooltip>
|
||||
|
||||
<UTooltip text="Move to junk">
|
||||
<UButton
|
||||
icon="i-heroicons-archive-box-x-mark"
|
||||
color="gray"
|
||||
variant="ghost"
|
||||
/>
|
||||
</UTooltip>
|
||||
|
||||
<UDivider
|
||||
orientation="vertical"
|
||||
class="mx-1.5"
|
||||
/>
|
||||
|
||||
<UPopover :popper="{ placement: 'bottom-start' }">
|
||||
<template #default="{ open }">
|
||||
<UTooltip
|
||||
text="Snooze"
|
||||
:prevent="open"
|
||||
>
|
||||
<UButton
|
||||
icon="i-heroicons-clock"
|
||||
color="gray"
|
||||
variant="ghost"
|
||||
:class="[open && 'bg-gray-50 dark:bg-gray-800']"
|
||||
/>
|
||||
</UTooltip>
|
||||
</template>
|
||||
|
||||
<template #panel="{ close }">
|
||||
<DatePicker @close="close" />
|
||||
</template>
|
||||
</UPopover>-->
|
||||
</template>
|
||||
|
||||
<template #right>
|
||||
<UTooltip text="Reply">
|
||||
<UButton
|
||||
icon="i-heroicons-arrow-uturn-left"
|
||||
color="gray"
|
||||
variant="ghost"
|
||||
/>
|
||||
</UTooltip>
|
||||
|
||||
<UTooltip text="Forward">
|
||||
<UButton
|
||||
icon="i-heroicons-arrow-uturn-right"
|
||||
color="gray"
|
||||
variant="ghost"
|
||||
/>
|
||||
</UTooltip>
|
||||
|
||||
<!-- <UDivider
|
||||
orientation="vertical"
|
||||
class="mx-1.5"
|
||||
/>
|
||||
|
||||
<UDropdown :items="dropdownItems">
|
||||
<UButton
|
||||
icon="i-heroicons-ellipsis-vertical"
|
||||
color="gray"
|
||||
variant="ghost"
|
||||
/>
|
||||
</UDropdown>-->
|
||||
</template>
|
||||
</UDashboardNavbar>
|
||||
|
||||
<!-- ~/components/inbox/InboxMail.vue -->
|
||||
<InboxMail :mail="selectedMail" />
|
||||
</template>
|
||||
<div
|
||||
v-else
|
||||
class="flex-1 hidden lg:flex items-center justify-center"
|
||||
>
|
||||
<UIcon
|
||||
name="i-heroicons-inbox"
|
||||
class="w-32 h-32 text-gray-400 dark:text-gray-500"
|
||||
/>
|
||||
</div>
|
||||
</UDashboardPanel>
|
||||
</UDashboardPage>
|
||||
<div
|
||||
v-else
|
||||
class="flex-1 flex-col hidden lg:flex items-center justify-center"
|
||||
>
|
||||
<UIcon
|
||||
name="i-heroicons-inbox"
|
||||
class="w-32 h-32 text-gray-400 dark:text-gray-500"
|
||||
/>
|
||||
<span class="font-bold text-2xl">Kein E-Mail Account verfügbar</span>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- <UInput
|
||||
placeholder="Empfänger"
|
||||
variant="ghost"
|
||||
class="m-2"
|
||||
/>
|
||||
<UInput
|
||||
placeholder="Betreff"
|
||||
variant="ghost"
|
||||
class="m-2"
|
||||
/>
|
||||
<UInput
|
||||
placeholder="CC"
|
||||
variant="ghost"
|
||||
class="m-2"
|
||||
/>
|
||||
<UInput
|
||||
placeholder="BCC"
|
||||
variant="ghost"
|
||||
class="m-2"
|
||||
/>
|
||||
|
||||
<UDivider
|
||||
class="my-5"
|
||||
/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<Tiptap/>-->
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
279
pages/email/new.vue
Normal file
279
pages/email/new.vue
Normal file
@@ -0,0 +1,279 @@
|
||||
<script setup>
|
||||
|
||||
const supabase = useSupabaseClient()
|
||||
const dataStore = useDataStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const toast = useToast()
|
||||
|
||||
const emailData = ref({
|
||||
to:"",
|
||||
cc:"",
|
||||
bcc: "",
|
||||
subject: "",
|
||||
html: "",
|
||||
text: "",
|
||||
account: "",
|
||||
})
|
||||
|
||||
const emailAccounts = ref([])
|
||||
const preloadedContent = ref("")
|
||||
const loadedDocuments = ref([])
|
||||
const loaded = ref(false)
|
||||
const setupPage = async () => {
|
||||
emailAccounts.value = await useSupabaseSelect("emailAccounts")
|
||||
emailData.value.account = emailAccounts.value[0].id
|
||||
|
||||
preloadedContent.value = `<p></p><p></p><p></p>${dataStore.activeProfile.emailSignature}`
|
||||
|
||||
//Check Query
|
||||
if(route.query.to) emailData.value.to = route.query.to
|
||||
if(route.query.cc) emailData.value.to = route.query.cc
|
||||
if(route.query.bcc) emailData.value.to = route.query.bcc
|
||||
if(route.query.subject) emailData.value.to = route.query.subject
|
||||
|
||||
|
||||
if(route.query.loadDocuments) {
|
||||
console.log(JSON.parse(route.query.loadDocuments))
|
||||
const {data,error} = await supabase.from("documents").select('*, createdDocument(id,documentNumber,title,contact(email))').in('id',JSON.parse(route.query.loadDocuments))
|
||||
|
||||
if(error) console.log(error)
|
||||
if(data) loadedDocuments.value = data
|
||||
|
||||
console.log(loadedDocuments.value)
|
||||
|
||||
if(loadedDocuments.value.length > 0) {
|
||||
emailData.value.subject = loadedDocuments.value[0].createdDocument.title
|
||||
emailData.value.to = loadedDocuments.value[0].createdDocument.contact.email
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
loaded.value = true
|
||||
|
||||
}
|
||||
|
||||
setupPage()
|
||||
|
||||
const contentChanged = (content) => {
|
||||
emailData.value.html = content.html
|
||||
emailData.value.text = content.text
|
||||
}
|
||||
|
||||
const selectedAttachments = ref([])
|
||||
const renderAttachments = () => {
|
||||
selectedAttachments.value = Array.from(document.getElementById("inputAttachments").files).map(i => {
|
||||
return {
|
||||
filename: i.name,
|
||||
type: i.type
|
||||
}})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const toBase64 = file => new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
reader.onload = () => resolve(reader.result.split(",")[1]);
|
||||
reader.onerror = reject;
|
||||
});
|
||||
|
||||
function blobToBase64(blob) {
|
||||
return new Promise((resolve, _) => {
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = () => resolve(reader.result.split(",")[1]);
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
}
|
||||
|
||||
const sendEmail = async () => {
|
||||
loaded.value = false
|
||||
|
||||
let body = {
|
||||
...emailData.value,
|
||||
attachments: []
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
for await (const file of Array.from(document.getElementById("inputAttachments").files)) {
|
||||
body.attachments.push({
|
||||
filename: file.name,
|
||||
content: await toBase64(file),
|
||||
contentType: file.type,
|
||||
encoding: "base64",
|
||||
contentDisposition: "attachment"
|
||||
})
|
||||
}
|
||||
|
||||
for await (const doc of loadedDocuments.value) {
|
||||
|
||||
const {data,error} = await supabase.storage.from("files").download(doc.path)
|
||||
|
||||
body.attachments.push({
|
||||
filename: doc.path.split("/")[doc.path.split("/").length -1],
|
||||
content: await blobToBase64(data),
|
||||
contentType: data.type,
|
||||
encoding: "base64",
|
||||
contentDisposition: "attachment"
|
||||
})
|
||||
}
|
||||
|
||||
const { data, error } = await supabase.functions.invoke('send_email', {
|
||||
body
|
||||
})
|
||||
if(error) {
|
||||
toast.add({title: "Fehler beim Absenden der E-Mail", color: "rose"})
|
||||
|
||||
} else if(data) {
|
||||
router.push("/")
|
||||
toast.add({title: "E-Mail zum Senden eingereiht"})
|
||||
}
|
||||
|
||||
loaded.value = true
|
||||
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UProgress animation="carousel" v-if="!loaded" class="mt-5 w-2/3 mx-auto"/>
|
||||
|
||||
<div v-else>
|
||||
<UDashboardNavbar
|
||||
title="Neue E-Mail"
|
||||
>
|
||||
<template #right>
|
||||
<UButton
|
||||
@click="sendEmail"
|
||||
:disabled="!emailData.to || !emailData.subject"
|
||||
>
|
||||
Senden
|
||||
</UButton>
|
||||
</template>
|
||||
|
||||
</UDashboardNavbar>
|
||||
<UDashboardToolbar>
|
||||
<div class="flex-col flex w-full">
|
||||
<UFormGroup
|
||||
label="Absender"
|
||||
>
|
||||
<USelectMenu
|
||||
:options="emailAccounts"
|
||||
option-attribute="emailAddress"
|
||||
value-attribute="id"
|
||||
v-model="emailData.account"
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
<UInput
|
||||
class="w-full my-1"
|
||||
placeholder="Empfänger"
|
||||
variant="ghost"
|
||||
v-model="emailData.to"
|
||||
/>
|
||||
<UInput
|
||||
class="w-full my-1"
|
||||
placeholder="Kopie"
|
||||
variant="ghost"
|
||||
v-model="emailData.cc"
|
||||
/>
|
||||
<UInput
|
||||
class="w-full my-1"
|
||||
placeholder="Blindkopie"
|
||||
variant="ghost"
|
||||
v-model="emailData.bcc"
|
||||
/>
|
||||
<UInput
|
||||
placeholder="Betreff"
|
||||
class="w-full my-1"
|
||||
variant="ghost"
|
||||
v-model="emailData.subject"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</UDashboardToolbar>
|
||||
|
||||
<UDashboardPanelContent>
|
||||
<div id="parentAttachments" class="flex flex-col justify-center">
|
||||
<span class="font-medium mb-2 text-xl">Anhänge</span>
|
||||
<!-- <UIcon
|
||||
name="i-heroicons-paper-clip"
|
||||
class="mx-auto w-10 h-10"
|
||||
/>
|
||||
<span class="text-center text-2xl">Anhänge hochladen</span>-->
|
||||
<input
|
||||
id="inputAttachments"
|
||||
type="file"
|
||||
multiple
|
||||
@change="renderAttachments"
|
||||
/>
|
||||
<ul class="mx-5 mt-3">
|
||||
<li
|
||||
class="list-disc"
|
||||
v-for="file in selectedAttachments"
|
||||
> Datei - {{file.filename}}</li>
|
||||
<li
|
||||
class="list-disc"
|
||||
v-for="doc in loadedDocuments"
|
||||
>
|
||||
<span v-if="doc.createdDocument">Dokument - {{doc.createdDocument.documentNumber}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<Tiptap
|
||||
@updateContent="contentChanged"
|
||||
:preloadedContent="preloadedContent"
|
||||
/>
|
||||
</UDashboardPanelContent>
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
#parentAttachments {
|
||||
border: 1px dashed #69c350;
|
||||
border-radius: 10px;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
|
||||
#inputAttachments {
|
||||
/*
|
||||
display: none;
|
||||
*/
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
opacity: 100;/*
|
||||
width: 100%;
|
||||
height: 5%;
|
||||
position: relative;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;*/
|
||||
}
|
||||
|
||||
#inputAttachments::file-selector-button {
|
||||
background-color: white;
|
||||
border: 1px solid #69c350;
|
||||
border-radius: 5px;
|
||||
padding: 5px 10px 5px 10px;
|
||||
}
|
||||
|
||||
.fileListItem {
|
||||
border: 1px solid #69c350;
|
||||
border-radius: 5px;
|
||||
padding: .5rem;
|
||||
}
|
||||
|
||||
</style>
|
||||
Reference in New Issue
Block a user