panel 2 courier api restore

This commit is contained in:
alma 2025-04-26 10:13:48 +02:00
parent 4405dcc18b
commit c192fb09a7

View File

@ -132,7 +132,31 @@ export default function ComposeEmail({
).join(', ');
};
// New function to initialize forwarded email using same approach as Panel 3
// Handle editor input
const handleEditorInput = (e: React.FormEvent<HTMLDivElement>) => {
// Only store the content of the editable area, not the entire HTML with CSS
// This prevents breaking complex CSS when editing
if (editorRef.current) {
// If we're in forward mode and the editor contains our wrapper structure
const editableContent = editorRef.current.querySelector('.editable-content');
if (type === 'forward' && editableContent) {
// Only update the editable portion, preserving the CSS and header
const headerSection = editorRef.current.querySelector('.forwarded-header');
const styleSection = editorRef.current.querySelector('.email-styles');
// Combine the preserved sections with the updated editable content
const updatedContent = (styleSection?.outerHTML || '') +
(headerSection?.outerHTML || '') +
editableContent.innerHTML;
setBody(updatedContent);
} else {
// For new emails or replies, we can use the entire content
setBody(e.currentTarget.innerHTML);
}
}
};
// Modified initializeForwardedEmail to separate CSS from content
const initializeForwardedEmail = async () => {
if (!initialEmail) {
console.error('No email available for forwarding');
@ -140,6 +164,7 @@ export default function ComposeEmail({
return;
}
// Helper functions remain the same
try {
setSending(true); // Use sending state to show loading
@ -153,7 +178,7 @@ export default function ComposeEmail({
// Create a forwarded message header with proper formatting
const headerContent = `
<div style="border-bottom: 1px solid #e2e2e2; margin-bottom: 15px; padding-bottom: 15px; font-family: Arial, sans-serif; color: #333;">
<div class="forwarded-header" contenteditable="false" style="border-bottom: 1px solid #e2e2e2; margin-bottom: 15px; padding-bottom: 15px; font-family: Arial, sans-serif; color: #333;">
<p style="margin: 5px 0; font-size: 14px;">---------- Forwarded message ---------</p>
<p style="margin: 5px 0; font-size: 14px;"><b>From:</b> ${formatSender(initialEmail.from)}</p>
<p style="margin: 5px 0; font-size: 14px;"><b>Date:</b> ${formatDate(initialEmail.date)}</p>
@ -161,17 +186,35 @@ export default function ComposeEmail({
<p style="margin: 5px 0; font-size: 14px;"><b>To:</b> ${formatRecipients(initialEmail.to)}</p>
</div>`;
// Use enhanced DOMPurify sanitization options similar to EmailPreview component
// This will preserve more styles and formatting from the original email
// Process content
let contentBody = '';
let styleContent = '';
// Check if email content exists
if (!initialEmail.content || initialEmail.content.trim() === '') {
contentBody = '<div style="color: #666; font-style: italic; margin-top: 10px;">No content available</div>';
contentBody = '<div class="editable-content" style="color: #666; font-style: italic; margin-top: 10px;">No content available</div>';
} else {
try {
// Use enhanced DOMPurify sanitization options directly from Panel 3
const sanitizedContent = DOMPurify.sanitize(initialEmail.content, {
// Parse content to extract styles and make content editable
const content = initialEmail.content;
// Extract style tags to preserve them
const styleRegex = /<style[^>]*>([\s\S]*?)<\/style>/gi;
const styles: string[] = [];
let styleMatch;
// Find all style tags and collect them
while ((styleMatch = styleRegex.exec(content)) !== null) {
styles.push(styleMatch[0]);
}
// Combine all styles into one non-editable section
if (styles.length > 0) {
styleContent = `<div class="email-styles" contenteditable="false">${styles.join('')}</div>`;
}
// Use DOMPurify to sanitize the rest of the HTML content
const sanitizedContent = DOMPurify.sanitize(content, {
ADD_TAGS: ['style', 'meta', 'link', 'table', 'thead', 'tbody', 'tr', 'td', 'th', 'hr', 'font', 'div', 'span', 'a', 'img', 'b', 'strong', 'i', 'em', 'u', 'br', 'p', 'ul', 'ol', 'li', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'pre', 'code', 'center', 'section', 'header', 'footer', 'article', 'nav', 'keyframes'],
ADD_ATTR: ['*', 'colspan', 'rowspan', 'cellpadding', 'cellspacing', 'border', 'bgcolor', 'width', 'height', 'align', 'valign', 'class', 'id', 'style', 'color', 'face', 'size', 'background', 'src', 'href', 'target', 'rel', 'alt', 'title', 'name', 'animation', 'animation-name', 'animation-duration', 'animation-fill-mode'],
ALLOW_UNKNOWN_PROTOCOLS: true,
@ -182,27 +225,32 @@ export default function ComposeEmail({
USE_PROFILES: { html: true, svg: false, svgFilters: false, mathMl: false },
FORCE_BODY: true
});
contentBody = sanitizedContent;
// Remove style tags from sanitized content (we'll add them back separately)
let contentWithoutStyles = sanitizedContent.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '');
// Wrap the remaining content in an editable div
contentBody = `<div class="editable-content">${contentWithoutStyles}</div>`;
} catch (e) {
console.error('Error sanitizing HTML content:', e);
contentBody = '<div style="color: #666; font-style: italic; margin-top: 10px;">Error processing original content</div>';
contentBody = '<div class="editable-content" style="color: #666; font-style: italic; margin-top: 10px;">Error processing original content</div>';
}
}
// Set the complete forwarded email with enhanced preservation of styles
setBody(headerContent + contentBody);
// Set the complete forwarded email with styles preserved separately
setBody(styleContent + headerContent + contentBody);
} catch (error) {
console.error('Error initializing forwarded email:', error);
// Still provide the headers even if there's an error with the content
const errorHeaderContent = `
<div style="border-bottom: 1px solid #e2e2e2; margin-bottom: 15px; padding-bottom: 15px; font-family: Arial, sans-serif; color: #333;">
<div class="forwarded-header" contenteditable="false" style="border-bottom: 1px solid #e2e2e2; margin-bottom: 15px; padding-bottom: 15px; font-family: Arial, sans-serif; color: #333;">
<p style="margin: 5px 0; font-size: 14px;">---------- Forwarded message ---------</p>
<p style="margin: 5px 0; font-size: 14px;"><b>From:</b> ${initialEmail.from ? formatSender(initialEmail.from) : 'Unknown'}</p>
<p style="margin: 5px 0; font-size: 14px;"><b>Date:</b> ${initialEmail.date ? formatDate(initialEmail.date) : ''}</p>
<p style="margin: 5px 0; font-size: 14px;"><b>Subject:</b> ${initialEmail.subject || ''}</p>
<p style="margin: 5px 0; font-size: 14px;"><b>To:</b> ${initialEmail.to ? formatRecipients(initialEmail.to) : ''}</p>
</div>
<div style="color: #ef4444; font-style: italic; margin-top: 10px;">Error loading forwarded content</div>`;
<div class="editable-content" style="color: #ef4444; font-style: italic; margin-top: 10px;">Error loading forwarded content</div>`;
setBody(errorHeaderContent);
} finally {
setSending(false);
@ -266,12 +314,39 @@ export default function ComposeEmail({
try {
setSending(true);
// Get the email content
let emailBody = '';
if (editorRef.current) {
// For forwarded emails, make sure to include both the style and content sections
if (type === 'forward') {
// Gather all parts: styles, header, and editable content
const styleSection = editorRef.current.querySelector('.email-styles');
const headerSection = editorRef.current.querySelector('.forwarded-header');
const editableContent = editorRef.current.querySelector('.editable-content');
// Combine all sections for the final email body
emailBody =
(styleSection?.outerHTML || '') +
(headerSection?.outerHTML || '') +
(editableContent?.innerHTML || editorRef.current.innerHTML);
// Remove contenteditable attributes as they're not needed in the sent email
emailBody = emailBody.replace(/contenteditable="[^"]*"/g, '');
} else {
// For new emails or replies, use the entire content
emailBody = editorRef.current.innerHTML;
}
} else {
// Fallback to using body state
emailBody = body;
}
await onSend({
to,
cc: cc || undefined,
bcc: bcc || undefined,
subject,
body: editorRef.current?.innerHTML || body,
body: emailBody,
attachments
});
@ -284,12 +359,6 @@ export default function ComposeEmail({
}
};
// Handle editor input
const handleEditorInput = (e: React.FormEvent<HTMLDivElement>) => {
// Store the HTML content for use in the send function
setBody(e.currentTarget.innerHTML);
};
return (
<Card className="w-full h-full flex flex-col overflow-hidden shadow-lg">
<CardHeader className="border-b py-2 px-4">