courrier clean 2
This commit is contained in:
parent
ddf72cc4f0
commit
e3b946f7e9
@ -11,6 +11,13 @@ import { Input } from '@/components/ui/input';
|
|||||||
import { Card, CardContent, CardHeader, CardTitle, CardFooter } from '@/components/ui/card';
|
import { Card, CardContent, CardHeader, CardTitle, CardFooter } from '@/components/ui/card';
|
||||||
import DOMPurify from 'isomorphic-dompurify';
|
import DOMPurify from 'isomorphic-dompurify';
|
||||||
|
|
||||||
|
// Import the new email formatter utilities
|
||||||
|
import {
|
||||||
|
formatForwardedEmail,
|
||||||
|
formatReplyEmail,
|
||||||
|
EmailMessage as FormatterEmailMessage
|
||||||
|
} from '@/lib/utils/email-formatter';
|
||||||
|
|
||||||
// Define EmailMessage interface locally instead of importing from server-only file
|
// Define EmailMessage interface locally instead of importing from server-only file
|
||||||
interface EmailAddress {
|
interface EmailAddress {
|
||||||
name: string;
|
name: string;
|
||||||
@ -44,124 +51,6 @@ interface EmailMessage {
|
|||||||
contentFetched?: boolean;
|
contentFetched?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simplified formatEmailForReplyOrForward that doesn't rely on server code
|
|
||||||
function formatEmailForReplyOrForward(
|
|
||||||
email: EmailMessage,
|
|
||||||
type: 'reply' | 'reply-all' | 'forward'
|
|
||||||
): {
|
|
||||||
to: string;
|
|
||||||
cc?: string;
|
|
||||||
subject: string;
|
|
||||||
body: string;
|
|
||||||
} {
|
|
||||||
// Format subject
|
|
||||||
let subject = email.subject || '';
|
|
||||||
if (type === 'reply' || type === 'reply-all') {
|
|
||||||
if (!subject.startsWith('Re:')) {
|
|
||||||
subject = `Re: ${subject}`;
|
|
||||||
}
|
|
||||||
} else if (type === 'forward') {
|
|
||||||
if (!subject.startsWith('Fwd:')) {
|
|
||||||
subject = `Fwd: ${subject}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create quote header
|
|
||||||
const date = typeof email.date === 'string'
|
|
||||||
? new Date(email.date)
|
|
||||||
: email.date;
|
|
||||||
|
|
||||||
const formattedDate = date.toLocaleString('en-US', {
|
|
||||||
weekday: 'short',
|
|
||||||
year: 'numeric',
|
|
||||||
month: 'short',
|
|
||||||
day: 'numeric',
|
|
||||||
hour: '2-digit',
|
|
||||||
minute: '2-digit'
|
|
||||||
});
|
|
||||||
|
|
||||||
const sender = email.from[0];
|
|
||||||
const fromText = sender?.name
|
|
||||||
? `${sender.name} <${sender.address}>`
|
|
||||||
: sender?.address || 'Unknown sender';
|
|
||||||
|
|
||||||
const quoteHeader = `<div style="font-weight: 500;">On ${formattedDate}, ${fromText} wrote:</div>`;
|
|
||||||
|
|
||||||
// Format content
|
|
||||||
const quotedContent = email.html || email.content || email.text || '';
|
|
||||||
|
|
||||||
// Format recipients
|
|
||||||
let to = '';
|
|
||||||
let cc = '';
|
|
||||||
|
|
||||||
if (type === 'reply') {
|
|
||||||
// Reply to sender only
|
|
||||||
to = email.from.map(addr => `${addr.name} <${addr.address}>`).join(', ');
|
|
||||||
} else if (type === 'reply-all') {
|
|
||||||
// Reply to sender and all recipients
|
|
||||||
to = email.from.map(addr => `${addr.name} <${addr.address}>`).join(', ');
|
|
||||||
|
|
||||||
// Add all original recipients to CC
|
|
||||||
const allRecipients = [
|
|
||||||
...(email.to || []),
|
|
||||||
...(email.cc || [])
|
|
||||||
];
|
|
||||||
|
|
||||||
cc = allRecipients
|
|
||||||
.map(addr => `${addr.name} <${addr.address}>`)
|
|
||||||
.join(', ');
|
|
||||||
} else if (type === 'forward') {
|
|
||||||
// Forward doesn't set recipients
|
|
||||||
to = '';
|
|
||||||
|
|
||||||
// Format forward differently
|
|
||||||
const formattedDate = typeof email.date === 'string'
|
|
||||||
? new Date(email.date).toLocaleString()
|
|
||||||
: email.date.toLocaleString();
|
|
||||||
|
|
||||||
const fromText = email.from.map(f => f.name ? `${f.name} <${f.address}>` : f.address).join(', ');
|
|
||||||
const toText = email.to.map(t => t.name ? `${t.name} <${t.address}>` : t.address).join(', ');
|
|
||||||
|
|
||||||
return {
|
|
||||||
to: '',
|
|
||||||
subject,
|
|
||||||
body: `
|
|
||||||
<div class="forwarded-message" style="margin-top: 20px;">
|
|
||||||
<div style="background-color: #f5f5f5; border-left: 3px solid #ddd; padding: 12px; margin-bottom: 15px; border-radius: 4px;">
|
|
||||||
<p style="margin: 0 0 8px 0; font-weight: 500; color: #555; font-size: 14px;">---------- Forwarded message ---------</p>
|
|
||||||
<p style="margin: 0 0 6px 0; font-size: 13px;"><span style="font-weight: 600; color: #444;">From:</span> ${fromText}</p>
|
|
||||||
<p style="margin: 0 0 6px 0; font-size: 13px;"><span style="font-weight: 600; color: #444;">Date:</span> ${formattedDate}</p>
|
|
||||||
<p style="margin: 0 0 6px 0; font-size: 13px;"><span style="font-weight: 600; color: #444;">Subject:</span> ${email.subject || ''}</p>
|
|
||||||
<p style="margin: 0 0 6px 0; font-size: 13px;"><span style="font-weight: 600; color: #444;">To:</span> ${toText}</p>
|
|
||||||
</div>
|
|
||||||
<div class="forwarded-content" style="border-left: 2px solid #ddd; padding-left: 15px; color: #333;">
|
|
||||||
${quotedContent ? quotedContent : '<p>No content available</p>'}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format body with improved styling for replies
|
|
||||||
const body = `
|
|
||||||
<div class="reply-body">
|
|
||||||
<br/>
|
|
||||||
<div class="quote-header" style="color: #555; font-size: 13px; margin: 20px 0 10px 0;">${quoteHeader}</div>
|
|
||||||
<blockquote style="margin: 0; padding: 10px 0 10px 15px; border-left: 3px solid #ddd; color: #555; background-color: #f8f8f8; border-radius: 4px;">
|
|
||||||
<div class="quoted-content" style="font-size: 13px;">
|
|
||||||
${quotedContent}
|
|
||||||
</div>
|
|
||||||
</blockquote>
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
return {
|
|
||||||
to,
|
|
||||||
cc: cc || undefined,
|
|
||||||
subject,
|
|
||||||
body
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Legacy interface for backward compatibility with old ComposeEmail component
|
// Legacy interface for backward compatibility with old ComposeEmail component
|
||||||
interface LegacyComposeEmailProps {
|
interface LegacyComposeEmailProps {
|
||||||
showCompose: boolean;
|
showCompose: boolean;
|
||||||
@ -270,99 +159,70 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
|
|||||||
// Initialize the form when replying to or forwarding an email
|
// Initialize the form when replying to or forwarding an email
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (initialEmail && type !== 'new') {
|
if (initialEmail && type !== 'new') {
|
||||||
// For all types of emails, format with a consistent approach
|
try {
|
||||||
let formattedContent = '';
|
const formatterEmail: FormatterEmailMessage = {
|
||||||
|
id: initialEmail.id,
|
||||||
if (type === 'forward') {
|
messageId: initialEmail.messageId,
|
||||||
// Format subject with Fwd: prefix if needed
|
subject: initialEmail.subject,
|
||||||
const subjectBase = initialEmail.subject || '(No subject)';
|
from: initialEmail.from || [],
|
||||||
const subjectRegex = /^(Fwd|FW|Forward):\s*/i;
|
to: initialEmail.to || [],
|
||||||
const subject = subjectRegex.test(subjectBase)
|
cc: initialEmail.cc || [],
|
||||||
? subjectBase
|
bcc: initialEmail.bcc || [],
|
||||||
: `Fwd: ${subjectBase}`;
|
date: initialEmail.date,
|
||||||
|
content: initialEmail.content,
|
||||||
setSubject(subject);
|
html: initialEmail.html,
|
||||||
|
text: initialEmail.text,
|
||||||
// Format forwarded content
|
hasAttachments: initialEmail.hasAttachments || false
|
||||||
const fromString = initialEmail.from?.map(addr =>
|
};
|
||||||
addr.name ? `${addr.name} <${addr.address}>` : addr.address
|
|
||||||
).join(', ') || '';
|
if (type === 'forward') {
|
||||||
|
// For forwarding, use the dedicated formatter
|
||||||
const toString = initialEmail.to?.map(addr =>
|
const { subject, content } = formatForwardedEmail(formatterEmail);
|
||||||
addr.name ? `${addr.name} <${addr.address}>` : addr.address
|
setSubject(subject);
|
||||||
).join(', ') || '';
|
setBody(content);
|
||||||
|
setUserMessage(content);
|
||||||
const dateString = typeof initialEmail.date === 'string'
|
} else {
|
||||||
? new Date(initialEmail.date).toLocaleString()
|
// For reply/reply-all, use the reply formatter
|
||||||
: initialEmail.date.toLocaleString();
|
const { to, cc, subject, content } = formatReplyEmail(formatterEmail, type as 'reply' | 'reply-all');
|
||||||
|
setTo(to);
|
||||||
// Preprocess original content to avoid direction issues
|
if (cc) {
|
||||||
const originalContent = preprocessEmailContent(
|
setCc(cc);
|
||||||
initialEmail.content || initialEmail.html || initialEmail.text || ''
|
setShowCc(true);
|
||||||
);
|
}
|
||||||
|
setSubject(subject);
|
||||||
formattedContent = `
|
setBody(content);
|
||||||
<br><br>
|
setUserMessage(content);
|
||||||
<div style="border-top: 1px solid #ccc; margin-top: 20px; padding-top: 10px; direction: ltr; text-align: left;">
|
|
||||||
<div style="font-family: Arial, sans-serif; color: #333;">
|
|
||||||
<div style="margin-bottom: 15px;">
|
|
||||||
<div style="direction: ltr; text-align: left;">---------- Forwarded message ---------</div>
|
|
||||||
<div style="direction: ltr; text-align: left;"><b>From:</b> ${fromString}</div>
|
|
||||||
<div style="direction: ltr; text-align: left;"><b>Date:</b> ${dateString}</div>
|
|
||||||
<div style="direction: ltr; text-align: left;"><b>Subject:</b> ${initialEmail.subject || ''}</div>
|
|
||||||
<div style="direction: ltr; text-align: left;"><b>To:</b> ${toString}</div>
|
|
||||||
</div>
|
|
||||||
<div style="direction: ltr; text-align: left;">${originalContent}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
} else {
|
|
||||||
// For reply/reply-all
|
|
||||||
const formattedEmail = formatEmailForReplyOrForward(initialEmail, type as 'reply' | 'reply-all');
|
|
||||||
|
|
||||||
setTo(formattedEmail.to);
|
|
||||||
|
|
||||||
if (formattedEmail.cc) {
|
|
||||||
setCc(formattedEmail.cc);
|
|
||||||
setShowCc(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setSubject(formattedEmail.subject);
|
// Focus editor after initializing
|
||||||
|
setTimeout(() => {
|
||||||
// Process content to fix direction issues
|
if (editorRef.current) {
|
||||||
formattedContent = preprocessEmailContent(formattedEmail.body);
|
editorRef.current.focus();
|
||||||
}
|
|
||||||
|
|
||||||
// Set the entire content as one editable area
|
|
||||||
// Force LTR direction for quoted content
|
|
||||||
setBody(formattedContent);
|
|
||||||
setUserMessage(formattedContent);
|
|
||||||
|
|
||||||
// Focus editor after initializing
|
|
||||||
setTimeout(() => {
|
|
||||||
if (editorRef.current) {
|
|
||||||
editorRef.current.focus();
|
|
||||||
editorRef.current.dir = isRTL ? 'rtl' : 'ltr';
|
|
||||||
|
|
||||||
// Place cursor at the beginning of the content
|
|
||||||
const selection = window.getSelection();
|
|
||||||
if (selection) {
|
|
||||||
const range = document.createRange();
|
|
||||||
|
|
||||||
// Find the first text node or element node
|
// Place cursor at the beginning
|
||||||
let firstNode = editorRef.current.firstChild;
|
const selection = window.getSelection();
|
||||||
if (firstNode) {
|
if (selection) {
|
||||||
range.setStart(firstNode, 0);
|
try {
|
||||||
range.collapse(true);
|
const range = document.createRange();
|
||||||
|
|
||||||
selection.removeAllRanges();
|
if (editorRef.current.firstChild) {
|
||||||
selection.addRange(range);
|
range.setStart(editorRef.current.firstChild, 0);
|
||||||
|
range.collapse(true);
|
||||||
|
|
||||||
|
selection.removeAllRanges();
|
||||||
|
selection.addRange(range);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error positioning cursor:', e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}, 100);
|
||||||
}, 100);
|
} catch (error) {
|
||||||
|
console.error('Error formatting email:', error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [initialEmail, type, isRTL]);
|
}, [initialEmail, type]);
|
||||||
|
|
||||||
// Format date for the forwarded message header
|
// Format date for the forwarded message header
|
||||||
const formatDate = (date: Date | null): string => {
|
const formatDate = (date: Date | null): string => {
|
||||||
@ -401,43 +261,6 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
|
|||||||
).join(', ');
|
).join(', ');
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initialize forwarded email with clear structure and style preservation
|
|
||||||
const initializeForwardedEmail = async () => {
|
|
||||||
console.log('Starting initializeForwardedEmail');
|
|
||||||
if (!initialEmail) {
|
|
||||||
console.error('No email available for forwarding');
|
|
||||||
setBody('<div style="color: #666; font-style: italic;">No email available for forwarding</div>');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Format subject with Fwd: prefix if needed
|
|
||||||
const subjectBase = initialEmail.subject || '(No subject)';
|
|
||||||
const subjectRegex = /^(Fwd|FW|Forward):\s*/i;
|
|
||||||
const subject = subjectRegex.test(subjectBase)
|
|
||||||
? subjectBase
|
|
||||||
: `Fwd: ${subjectBase}`;
|
|
||||||
|
|
||||||
setSubject(subject);
|
|
||||||
|
|
||||||
// For forwarded emails, we'll use a completely different approach
|
|
||||||
// Just save the original HTML content and use it directly
|
|
||||||
// This preserves all formatting without trying to parse it
|
|
||||||
|
|
||||||
// Set message parts for the editor
|
|
||||||
const content = initialEmail.content || initialEmail.html || initialEmail.text || '';
|
|
||||||
setOriginalContent(content);
|
|
||||||
setUserMessage(''); // Start with empty user message
|
|
||||||
setBody(''); // Will be constructed when sending
|
|
||||||
|
|
||||||
// Log for debugging
|
|
||||||
console.log('Set originalContent:', content.substring(0, 100) + '...');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error formatting forwarded email:', error);
|
|
||||||
setBody('<div style="color: #666; font-style: italic;">Error formatting forwarded email content</div>');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handle attachment selection
|
// Handle attachment selection
|
||||||
const handleAttachmentClick = () => {
|
const handleAttachmentClick = () => {
|
||||||
attachmentInputRef.current?.click();
|
attachmentInputRef.current?.click();
|
||||||
|
|||||||
208
lib/utils/email-formatter.ts
Normal file
208
lib/utils/email-formatter.ts
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
/**
|
||||||
|
* Utilities for email formatting with proper text direction handling
|
||||||
|
*/
|
||||||
|
|
||||||
|
import DOMPurify from 'isomorphic-dompurify';
|
||||||
|
|
||||||
|
// Interface definitions
|
||||||
|
export interface EmailAddress {
|
||||||
|
name: string;
|
||||||
|
address: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EmailMessage {
|
||||||
|
id: string;
|
||||||
|
messageId?: string;
|
||||||
|
subject: string;
|
||||||
|
from: EmailAddress[];
|
||||||
|
to: EmailAddress[];
|
||||||
|
cc?: EmailAddress[];
|
||||||
|
bcc?: EmailAddress[];
|
||||||
|
date: Date | string;
|
||||||
|
flags?: {
|
||||||
|
seen: boolean;
|
||||||
|
flagged: boolean;
|
||||||
|
answered: boolean;
|
||||||
|
deleted: boolean;
|
||||||
|
draft: boolean;
|
||||||
|
};
|
||||||
|
preview?: string;
|
||||||
|
content?: string;
|
||||||
|
html?: string;
|
||||||
|
text?: string;
|
||||||
|
hasAttachments?: boolean;
|
||||||
|
attachments?: any[];
|
||||||
|
folder?: string;
|
||||||
|
size?: number;
|
||||||
|
contentFetched?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format email addresses for display
|
||||||
|
*/
|
||||||
|
export function formatEmailAddresses(addresses: EmailAddress[]): string {
|
||||||
|
if (!addresses || addresses.length === 0) return '';
|
||||||
|
|
||||||
|
return addresses.map(addr =>
|
||||||
|
addr.name && addr.name !== addr.address
|
||||||
|
? `${addr.name} <${addr.address}>`
|
||||||
|
: addr.address
|
||||||
|
).join(', ');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format date for display
|
||||||
|
*/
|
||||||
|
export function formatEmailDate(date: Date | string | undefined): string {
|
||||||
|
if (!date) return '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const dateObj = typeof date === 'string' ? new Date(date) : date;
|
||||||
|
return dateObj.toLocaleString('en-US', {
|
||||||
|
weekday: 'short',
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'short',
|
||||||
|
day: 'numeric',
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit'
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
return typeof date === 'string' ? date : date.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean HTML content to prevent RTL/LTR issues
|
||||||
|
*/
|
||||||
|
export function cleanHtmlContent(content: string): string {
|
||||||
|
if (!content) return '';
|
||||||
|
|
||||||
|
// First sanitize the HTML
|
||||||
|
const sanitized = DOMPurify.sanitize(content);
|
||||||
|
|
||||||
|
// Process content to ensure consistent direction
|
||||||
|
let processed = sanitized;
|
||||||
|
|
||||||
|
// Replace RTL attributes with LTR
|
||||||
|
processed = processed.replace(/dir\s*=\s*["']rtl["']/gi, 'dir="ltr"');
|
||||||
|
processed = processed.replace(/style\s*=\s*["']([^"']*)direction\s*:\s*rtl;?([^"']*)["']/gi,
|
||||||
|
(match, before, after) => `style="${before}direction: ltr;${after}"`);
|
||||||
|
|
||||||
|
return processed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format an email for forwarding
|
||||||
|
*/
|
||||||
|
export function formatForwardedEmail(email: EmailMessage): {
|
||||||
|
subject: string;
|
||||||
|
content: string;
|
||||||
|
} {
|
||||||
|
// Format subject with Fwd: prefix if needed
|
||||||
|
const subjectBase = email.subject || '(No subject)';
|
||||||
|
const subject = subjectBase.match(/^(Fwd|FW|Forward):/i)
|
||||||
|
? subjectBase
|
||||||
|
: `Fwd: ${subjectBase}`;
|
||||||
|
|
||||||
|
// Get sender and recipient information
|
||||||
|
const fromString = formatEmailAddresses(email.from || []);
|
||||||
|
const toString = formatEmailAddresses(email.to || []);
|
||||||
|
const dateString = formatEmailDate(email.date);
|
||||||
|
|
||||||
|
// Get and clean original content
|
||||||
|
const originalContent = cleanHtmlContent(email.content || email.html || email.text || '');
|
||||||
|
|
||||||
|
// Create formatted content with explicit LTR formatting
|
||||||
|
const content = `
|
||||||
|
<div style="min-height: 20px;"></div>
|
||||||
|
<div style="border-top: 1px solid #ccc; margin-top: 10px; padding-top: 10px; direction: ltr; text-align: left;" dir="ltr">
|
||||||
|
<div style="font-family: Arial, sans-serif; color: #333; direction: ltr; text-align: left;" dir="ltr">
|
||||||
|
<div style="margin-bottom: 15px; direction: ltr; text-align: left;" dir="ltr">
|
||||||
|
<div style="direction: ltr; text-align: left;" dir="ltr">---------- Forwarded message ---------</div>
|
||||||
|
<div style="direction: ltr; text-align: left;" dir="ltr"><b>From:</b> ${fromString}</div>
|
||||||
|
<div style="direction: ltr; text-align: left;" dir="ltr"><b>Date:</b> ${dateString}</div>
|
||||||
|
<div style="direction: ltr; text-align: left;" dir="ltr"><b>Subject:</b> ${email.subject || ''}</div>
|
||||||
|
<div style="direction: ltr; text-align: left;" dir="ltr"><b>To:</b> ${toString}</div>
|
||||||
|
</div>
|
||||||
|
<div style="direction: ltr; text-align: left;" dir="ltr" class="email-original-content">
|
||||||
|
${originalContent}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return { subject, content };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format an email for reply or reply-all
|
||||||
|
*/
|
||||||
|
export function formatReplyEmail(email: EmailMessage, type: 'reply' | 'reply-all'): {
|
||||||
|
to: string;
|
||||||
|
cc?: string;
|
||||||
|
subject: string;
|
||||||
|
content: string;
|
||||||
|
} {
|
||||||
|
// Format subject with Re: prefix if needed
|
||||||
|
const subjectBase = email.subject || '(No subject)';
|
||||||
|
const subject = subjectBase.match(/^Re:/i)
|
||||||
|
? subjectBase
|
||||||
|
: `Re: ${subjectBase}`;
|
||||||
|
|
||||||
|
// Get sender information for quote header
|
||||||
|
const sender = email.from[0];
|
||||||
|
const fromText = sender?.name
|
||||||
|
? `${sender.name} <${sender.address}>`
|
||||||
|
: sender?.address || 'Unknown sender';
|
||||||
|
|
||||||
|
// Format date for quote header
|
||||||
|
const date = typeof email.date === 'string' ? new Date(email.date) : email.date;
|
||||||
|
const formattedDate = date.toLocaleString('en-US', {
|
||||||
|
weekday: 'short',
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'short',
|
||||||
|
day: 'numeric',
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create quote header
|
||||||
|
const quoteHeader = `<div style="font-weight: 500; direction: ltr; text-align: left;" dir="ltr">On ${formattedDate}, ${fromText} wrote:</div>`;
|
||||||
|
|
||||||
|
// Get and clean original content
|
||||||
|
const quotedContent = cleanHtmlContent(email.html || email.content || email.text || '');
|
||||||
|
|
||||||
|
// Format recipients
|
||||||
|
let to = formatEmailAddresses(email.from || []);
|
||||||
|
let cc = '';
|
||||||
|
|
||||||
|
if (type === 'reply-all') {
|
||||||
|
// For reply-all, add all original recipients to CC
|
||||||
|
const allRecipients = [
|
||||||
|
...(email.to || []),
|
||||||
|
...(email.cc || [])
|
||||||
|
];
|
||||||
|
|
||||||
|
cc = formatEmailAddresses(allRecipients);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format content with explicit LTR for quoted parts
|
||||||
|
const content = `
|
||||||
|
<div style="min-height: 20px;"></div>
|
||||||
|
<div class="reply-body" style="direction: ltr; text-align: left;" dir="ltr">
|
||||||
|
<div class="quote-header" style="color: #555; font-size: 13px; margin: 20px 0 10px 0; direction: ltr; text-align: left;" dir="ltr">${quoteHeader}</div>
|
||||||
|
<blockquote style="margin: 0; padding: 10px 0 10px 15px; border-left: 3px solid #ddd; color: #555; background-color: #f8f8f8; border-radius: 4px; direction: ltr; text-align: left;" dir="ltr">
|
||||||
|
<div class="quoted-content" style="font-size: 13px; direction: ltr; text-align: left;" dir="ltr">
|
||||||
|
${quotedContent}
|
||||||
|
</div>
|
||||||
|
</blockquote>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
to,
|
||||||
|
cc: cc || undefined,
|
||||||
|
subject,
|
||||||
|
content
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user