Skip to content

Commit

Permalink
Merge pull request #44 from krantheman/feat-send-mail
Browse files Browse the repository at this point in the history
feat: upgrade send mail dialog
  • Loading branch information
krantheman authored Jan 10, 2025
2 parents 1df4d7f + f0b10f9 commit ca5dc9a
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 56 deletions.
2 changes: 1 addition & 1 deletion frontend/src/components/HeaderActions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import { Button } from 'frappe-ui'
import { SquarePen } from 'lucide-vue-next'
import SendMail from '@/components/Modals/SendMail.vue'
import { ref, defineEmits } from 'vue'
import { ref } from 'vue'
const emit = defineEmits(['reloadMails'])
Expand Down
162 changes: 109 additions & 53 deletions frontend/src/components/Modals/SendMail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -96,52 +96,87 @@
/>
</template>
<template v-slot:bottom>
<div class="flex flex-col gap-2">
<div class="flex flex-wrap gap-2">
<!-- <AttachmentItem
v-for="a in attachments"
:key="a.file_url"
:label="a.file_name"`
>
<template #suffix>
<FeatherIcon
class="h-3.5"
name="x"
@click.stop="removeAttachment(a)"
/>
</template>
</AttachmentItem> -->
</div>
<div class="flex justify-between gap-2 overflow-hidden border-t py-2.5">
<div class="flex gap-1 items-center overflow-x-auto">
<!-- <TextEditorFixedMenu :buttons="textEditorMenuButtons" /> -->
<EmojiPicker
v-model="emoji"
v-slot="{ togglePopover }"
@update:modelValue="() => appendEmoji()"
<FileUploader
:upload-args="{
doctype: 'Outgoing Mail',
docname: mailID,
private: true,
}"
:validateFile="
async () => {
if (!mailID) await createDraftMail.submit()
}
"
@success="attachments.fetch()"
>
<template #default="{ file, progress, uploading, openFileSelector }">
<!-- Attachments -->
<div
v-if="mailID"
class="flex flex-col gap-2 mb-2 text-gray-700 text-sm"
>
<div v-if="uploading" class="bg-gray-100 rounded p-2.5">
<div class="flex items-center mb-1.5">
<span class="font-medium mr-1">
{{ file.name }}
</span>
<span class="font-extralight">
({{ formatBytes(file.size) }})
</span>
</div>
<Progress :value="progress" />
</div>
<div
v-for="(file, index) in attachments.data"
:key="index"
class="bg-gray-100 rounded p-2.5 flex items-center cursor-pointer"
>
<Button variant="ghost" @click="togglePopover()">
<template #icon>
<Laugh class="h-4 w-4" />
</template>
</Button>
</EmojiPicker>
<FileUploader @success="(f) => attachments.push(f)">
<template #default="{ openFileSelector }">
<Button variant="ghost" @click="openFileSelector()">
<span class="font-medium mr-1">
{{ file.file_name || file.name }}
</span>
<span class="font-extralight">
({{ formatBytes(file.file_size) }})
</span>
<FeatherIcon
class="h-3.5 w-3.5 ml-auto"
name="x"
@click="removeAttachment.submit({ name: file.name })"
/>
</div>
</div>

<div
class="flex justify-between gap-2 overflow-hidden border-t py-2.5"
>
<!-- Text Editor Buttons -->
<div class="flex gap-1 items-center overflow-x-auto">
<TextEditorFixedMenu :buttons="textEditorMenuButtons" />
<EmojiPicker
v-model="emoji"
v-slot="{ togglePopover }"
@update:modelValue="() => appendEmoji()"
>
<Button variant="ghost" @click="togglePopover()">
<template #icon>
<Paperclip class="h-4" />
<Laugh class="h-4 w-4" />
</template>
</Button>
</template>
</FileUploader>
</div>
<div class="mt-2 flex items-center justify-end space-x-2 sm:mt-0">
<Button :label="__('Discard')" @click="discardMail" />
<Button @click="send" variant="solid" :label="__('Send')" />
</EmojiPicker>
<Button variant="ghost" @click="openFileSelector()">
<template #icon>
<Paperclip class="h-4" />
</template>
</Button>
</div>

<!-- Send & Discard -->
<div class="flex items-center justify-end space-x-2 sm:mt-0">
<Button :label="__('Discard')" @click="discardMail" />
<Button @click="send" variant="solid" :label="__('Send')" />
</div>
</div>
</div>
</div>
</template>
</FileUploader>
</template>
</TextEditor>
</template>
Expand All @@ -150,13 +185,15 @@
<script setup>
import {
Dialog,
FeatherIcon,
TextEditor,
createResource,
createDocumentResource,
FileUploader,
TextEditorFixedMenu,
TextInput,
Button,
Progress,
} from 'frappe-ui'
import { reactive, watch, inject, ref, nextTick, computed } from 'vue'
import { useDebounceFn } from '@vueuse/core'
Expand All @@ -165,11 +202,10 @@ import Link from '@/components/Controls/Link.vue'
import EmojiPicker from '@/components/EmojiPicker.vue'
import MultiselectInput from '@/components/Controls/MultiselectInput.vue'
import { EditorContent } from '@tiptap/vue-3'
import { validateEmail } from '@/utils'
import { validateEmail, formatBytes } from '@/utils'
import { userStore } from '@/stores/user'
const user = inject('$user')
const attachments = defineModel('attachments')
const show = defineModel()
const mailID = ref(null)
const textEditor = ref(null)
Expand Down Expand Up @@ -291,7 +327,7 @@ const createDraftMail = createResource({
const updateDraftMail = createResource({
url: 'mail.api.mail.update_draft_mail',
makeParams(values) {
makeParams() {
return {
mail_id: mailID.value,
from_: `${user.data?.full_name} <${mail.from}>`,
Expand All @@ -308,7 +344,7 @@ const updateDraftMail = createResource({
// TODO: delete using documentresource directly
const deleteDraftMail = createResource({
url: 'frappe.client.delete',
makeParams(values) {
makeParams() {
return {
doctype: 'Outgoing Mail',
name: mailID.value,
Expand All @@ -320,6 +356,27 @@ const deleteDraftMail = createResource({
},
})
const attachments = createResource({
url: 'mail.api.mail.get_attachments',
makeParams() {
return {
dt: 'Outgoing Mail',
dn: mailID.value,
}
},
})
const removeAttachment = createResource({
url: 'frappe.client.delete',
method: 'DELETE',
makeParams(values) {
return { doctype: 'File', name: values.name }
},
onSuccess() {
attachments.fetch()
},
})
const getDraftMail = (name) =>
createDocumentResource({
doctype: 'Outgoing Mail',
Expand All @@ -339,6 +396,7 @@ const getDraftMail = (name) =>
else mailDetails[recipientType] = [recipient.email]
}
mailID.value = name
attachments.fetch()
Object.assign(mail, mailDetails)
if (mailDetails.cc) cc.value = true
if (mailDetails.bcc) bcc.value = true
Expand Down Expand Up @@ -378,20 +436,18 @@ const textEditorMenuButtons = [
'Separator',
'Bold',
'Italic',
'Separator',
'Bullet List',
'Numbered List',
'FontColor',
'Separator',
'Align Left',
'Align Center',
'Align Right',
'FontColor',
'Separator',
'Image',
'Video',
'Bullet List',
'Numbered List',
'Separator',
// todo: fix inline image upload
// 'Image',
'Link',
'Blockquote',
'Code',
'Horizontal Rule',
[
'InsertTable',
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/UserDropdown.vue
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ import { userStore } from '@/stores/user'
const { logout, branding } = sessionStore()
const { userResource } = userStore()
const { isLoggedIn } = sessionStore()
let { isLoggedIn } = sessionStore()
const showSettings = ref(false)
const props = defineProps({
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,14 @@ export function validateEmail(email) {
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
return regExp.test(email)
}

export function formatBytes(bytes) {
if (!+bytes) return '0 Bytes'

const k = 1024
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']

const i = Math.floor(Math.log(bytes) / Math.log(k))

return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))}${sizes[i]}`
}
9 changes: 9 additions & 0 deletions mail/api/mail.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,3 +420,12 @@ def update_draft_mail(

if do_submit:
doc.submit()


@frappe.whitelist()
def get_attachments(dt: str, dn: str):
return frappe.get_all(
"File",
fields=["name", "file_name", "file_url", "file_size"],
filters={"attached_to_name": dn, "attached_to_doctype": dt},
)
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ readme = "README.md"
dynamic = ["version"]
dependencies = [
# "frappe~=15.0.0" # Installed and managed by bench.
"uuid-utils~=0.6.1",
"dkimpy~=1.1.5",
]

Expand Down

0 comments on commit ca5dc9a

Please sign in to comment.