feat: Email forwarding

This commit is contained in:
iamsivin
2025-04-28 16:40:41 +05:30
parent ef6949e32d
commit 38741f9a15
15 changed files with 853 additions and 21 deletions
@@ -14,7 +14,8 @@ const fromEmail = computed(() => {
});
const toEmail = computed(() => {
return contentAttributes.value?.email?.to ?? [];
const { forwardedMessageId, toEmails, email } = contentAttributes.value;
return forwardedMessageId ? (toEmails ?? []) : (email?.to ?? []);
});
const ccEmail = computed(() => {
@@ -66,10 +67,12 @@ const showMeta = computed(() => {
<template>
<section
v-show="showMeta"
class="space-y-1 rtl:pl-9 ltr:pr-9 text-sm break-words"
:class="hasError ? 'text-n-ruby-11' : 'text-n-slate-11'"
>
<template v-if="showMeta">
<div
v-if="showMeta"
class="space-y-1 rtl:pl-9 w-full ltr:pr-9 text-sm break-words"
>
<div
v-if="fromEmail[0]"
:class="hasError ? 'text-n-ruby-11' : 'text-n-slate-12'"
@@ -81,7 +84,7 @@ const showMeta = computed(() => {
&lt;{{ fromEmail[0] }}&gt;
</template>
<template v-else>
{{ fromEmail[0] }}
{{ $t('EMAIL_HEADER.FROM') }}: {{ fromEmail[0] }}
</template>
</div>
<div v-if="toEmail.length">
@@ -99,6 +102,7 @@ const showMeta = computed(() => {
{{ $t('EMAIL_HEADER.SUBJECT') }}:
{{ subject }}
</div>
</template>
</div>
<slot />
</section>
</template>
@@ -4,23 +4,26 @@ import { Letter } from 'vue-letter';
import { allowedCssProperties } from 'lettersanitizer';
import Icon from 'next/icon/Icon.vue';
import MessageMenu from 'dashboard/components-next/message/MessageMenu.vue';
import { EmailQuoteExtractor } from './removeReply.js';
import BaseBubble from 'next/message/bubbles/Base.vue';
import FormattedContent from 'next/message/bubbles/Text/FormattedContent.vue';
import AttachmentChips from 'next/message/chips/AttachmentChips.vue';
import EmailMeta from './EmailMeta.vue';
import TranslationToggle from 'dashboard/components-next/message/TranslationToggle.vue';
import ForwardMessageForm from 'dashboard/components-next/message/forwardMessage/ForwardMessage.vue';
import { useMessageContext } from '../../provider.js';
import { MESSAGE_TYPES } from 'next/message/constants.js';
import { MESSAGE_TYPES, MESSAGE_STATUS } from 'next/message/constants.js';
import { useTranslations } from 'dashboard/composables/useTranslations';
const { content, contentAttributes, attachments, messageType } =
const { id, status, content, contentAttributes, attachments, messageType } =
useMessageContext();
const isExpandable = ref(false);
const isExpanded = ref(false);
const showQuotedMessage = ref(false);
const showForwardMessageModal = ref(false);
const renderOriginal = ref(false);
const contentContainer = useTemplateRef('contentContainer');
@@ -31,6 +34,12 @@ onMounted(() => {
const isOutgoing = computed(() => messageType.value === MESSAGE_TYPES.OUTGOING);
const isIncoming = computed(() => !isOutgoing.value);
const isForwarded = computed(() => contentAttributes.value?.forwardedMessageId);
const showMessageMenu = computed(
() => ![MESSAGE_STATUS.FAILED, MESSAGE_STATUS.PROGRESS].includes(status.value)
);
const { hasTranslations, translationContent } =
useTranslations(contentAttributes);
@@ -103,13 +112,30 @@ const handleSeeOriginal = () => {
}"
data-bubble-name="email"
>
<EmailMeta
class="p-3"
<div
class="flex items-start gap-2 justify-end"
:class="{
'border-b border-n-strong': isIncoming,
'border-b border-n-slate-8/20': isOutgoing,
}"
/>
>
<EmailMeta class="p-3 w-full flex justify-end items-start">
<div
v-if="showMessageMenu"
class="flex gap-2 skip-context-menu flex-shrink-0 items-center relative"
>
<MessageMenu @open-forward="showForwardMessageModal = true" />
<ForwardMessageForm
v-if="showForwardMessageModal"
:message="contentAttributes?.email"
:message-id="id"
class="absolute right-3 z-50 skip-context-menu top-10"
@close="showForwardMessageModal = false"
/>
</div>
</EmailMeta>
</div>
<section ref="contentContainer" class="p-3">
<div
:class="{
@@ -130,7 +156,7 @@ const handleSeeOriginal = () => {
</button>
</div>
<FormattedContent
v-if="isOutgoing && content"
v-if="isOutgoing && content && !isForwarded"
class="text-n-slate-12"
:content="messageContent"
/>