diff --git a/components/ComposeEmail.tsx b/components/ComposeEmail.tsx
index 188b52d1..eb08d6a4 100644
--- a/components/ComposeEmail.tsx
+++ b/components/ComposeEmail.tsx
@@ -10,6 +10,8 @@ import { decodeComposeContent, encodeComposeContent } from '@/lib/compose-mime-d
import { Email } from '@/app/courrier/page';
import mime from 'mime';
import { simpleParser } from 'mailparser';
+import { decodeEmail, cleanHtml } from '@/lib/mail-parser-wrapper';
+import DOMPurify from 'dompurify';
interface ComposeEmailProps {
showCompose: boolean;
@@ -126,124 +128,107 @@ export default function ComposeEmail({
// Format the reply/forward content
const type = replyTo ? 'reply' : 'forward';
- // Use simple, reliable formatting for the quoted content
- const formatEmailAddresses = (addresses: any) => {
- if (!addresses) return 'Unknown';
- if (typeof addresses === 'string') return addresses;
- if (Array.isArray(addresses)) {
- return addresses.map(addr => addr.name || addr.address).join(', ');
- }
- return String(addresses);
- };
-
- // Extract plain text content for reliable display
- let emailContent = '';
try {
- // Parse the original email to get clean content
- const response = await fetch('/api/parse-email', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ email: emailToProcess.content }),
- });
+ // Parse the email to get headers and content - using the same function as panel 3
+ const decoded = await decodeEmail(emailToProcess.content);
- if (response.ok) {
- const data = await response.json();
- emailContent = data.text || '';
- // If no text content, try to extract from HTML
- if (!emailContent && data.html) {
- // Create a temporary div to extract text from HTML
- const tempDiv = document.createElement('div');
- tempDiv.innerHTML = data.html;
- emailContent = tempDiv.textContent || tempDiv.innerText || '';
+ // Format the content based on reply type
+ const quotedContent = type === 'forward' ? `
+
+ ---------- Forwarded message ---------
+ From: ${decoded.from || 'Unknown Sender'}
+ Date: ${decoded.date ? decoded.date.toLocaleString() : new Date().toLocaleString()}
+ Subject: ${decoded.subject || 'No Subject'}
+ To: ${decoded.to || ''}
+ ${decoded.cc ? `Cc: ${decoded.cc}
` : ''}
+
+
+ ${decoded.html ? DOMPurify.sanitize(decoded.html) : (decoded.text ? `
${decoded.text}` : 'No content available')}
+
+ ` : `
+
+ On ${decoded.date ? decoded.date.toLocaleString() : new Date().toLocaleString()}, ${decoded.from || 'Unknown Sender'} wrote:
+
+
+ ${decoded.html ? DOMPurify.sanitize(decoded.html) : (decoded.text ? `
${decoded.text}` : 'No content available')}
+
+ `;
+
+ // Set the content in the compose area with proper structure
+ const formattedContent = `
+
+ `;
+
+ if (composeBodyRef.current) {
+ composeBodyRef.current.innerHTML = formattedContent;
+
+ // Place cursor at the beginning before the quoted content
+ const selection = window.getSelection();
+ const range = document.createRange();
+ const firstDiv = composeBodyRef.current.querySelector('.cursor-position');
+ if (firstDiv) {
+ range.setStart(firstDiv, 0);
+ range.collapse(true);
+ selection?.removeAllRanges();
+ selection?.addRange(range);
+ (firstDiv as HTMLElement).focus();
}
+
+ // After setting the HTML content, add event listeners for scrolling
+ const messageContents = composeBodyRef.current.querySelectorAll('.message-content');
+ messageContents.forEach(container => {
+ // Make sure the container is properly styled for scrolling
+ (container as HTMLElement).style.maxHeight = '300px';
+ (container as HTMLElement).style.overflowY = 'auto';
+ (container as HTMLElement).style.border = '1px solid #e5e7eb';
+ (container as HTMLElement).style.borderRadius = '4px';
+ (container as HTMLElement).style.padding = '10px';
+
+ // Ensure wheel events are properly handled
+ if (!(container as HTMLElement).hasAttribute('data-scroll-handler-attached')) {
+ container.addEventListener('wheel', (e: Event) => {
+ const wheelEvent = e as WheelEvent;
+ const target = e.currentTarget as HTMLElement;
+
+ // Check if we're at the boundary of the scrollable area
+ const isAtBottom = target.scrollHeight - target.scrollTop <= target.clientHeight + 1;
+ const isAtTop = target.scrollTop <= 0;
+
+ // Only prevent default if we're not at the boundaries in the direction of scrolling
+ if ((wheelEvent.deltaY > 0 && !isAtBottom) || (wheelEvent.deltaY < 0 && !isAtTop)) {
+ e.stopPropagation();
+ e.preventDefault(); // Prevent the parent container from scrolling
+ }
+ }, { passive: false }); // Important for preventDefault to work
+
+ // Mark this element as having a scroll handler attached
+ (container as HTMLElement).setAttribute('data-scroll-handler-attached', 'true');
+ }
+ });
+
+ // Update compose state
+ setComposeBody(formattedContent);
+ setLocalContent(formattedContent);
+ console.log('[DEBUG] Successfully set compose content with scrollable message area');
}
} catch (error) {
console.error('[DEBUG] Error parsing email:', error);
// Fallback to simple content extraction
- emailContent = emailToProcess.content.replace(/<[^>]*>/g, '');
- }
-
- // Format the content based on reply type
- const quotedContent = type === 'forward' ? `
-
- ---------- Forwarded message ---------
- From: ${formatEmailAddresses(emailToProcess.from) || 'Unknown Sender'}
- Date: ${new Date(emailToProcess.date || Date.now()).toLocaleString()}
- Subject: ${emailToProcess.subject || 'No Subject'}
- To: ${formatEmailAddresses(emailToProcess.to) || ''}
- ${emailToProcess.cc ? `Cc: ${formatEmailAddresses(emailToProcess.cc)}
` : ''}
-
-
- ` : `
-
- On ${new Date(emailToProcess.date || Date.now()).toLocaleString()}, ${formatEmailAddresses(emailToProcess.from) || 'Unknown Sender'} wrote:
-
-
- `;
-
- // Set the content in the compose area with proper structure
- const formattedContent = `
-
- `;
-
- if (composeBodyRef.current) {
- composeBodyRef.current.innerHTML = formattedContent;
-
- // Place cursor at the beginning before the quoted content
- const selection = window.getSelection();
- const range = document.createRange();
- const firstDiv = composeBodyRef.current.querySelector('.cursor-position');
- if (firstDiv) {
- range.setStart(firstDiv, 0);
- range.collapse(true);
- selection?.removeAllRanges();
- selection?.addRange(range);
- (firstDiv as HTMLElement).focus();
- }
-
- // After setting the HTML content, add event listeners for scrolling
- const messageContents = composeBodyRef.current.querySelectorAll('.message-content');
- messageContents.forEach(container => {
- // Make sure the container is properly styled for scrolling
- (container as HTMLElement).style.maxHeight = '300px';
- (container as HTMLElement).style.overflowY = 'auto';
- (container as HTMLElement).style.border = '1px solid #e5e7eb';
- (container as HTMLElement).style.borderRadius = '4px';
- (container as HTMLElement).style.padding = '10px';
-
- // Ensure wheel events are properly handled
- if (!(container as HTMLElement).hasAttribute('data-scroll-handler-attached')) {
- container.addEventListener('wheel', (e: Event) => {
- const wheelEvent = e as WheelEvent;
- const target = e.currentTarget as HTMLElement;
-
- // Check if we're at the boundary of the scrollable area
- const isAtBottom = target.scrollHeight - target.scrollTop <= target.clientHeight + 1;
- const isAtTop = target.scrollTop <= 0;
-
- // Only prevent default if we're not at the boundaries in the direction of scrolling
- if ((wheelEvent.deltaY > 0 && !isAtBottom) || (wheelEvent.deltaY < 0 && !isAtTop)) {
- e.stopPropagation();
- e.preventDefault(); // Prevent the parent container from scrolling
- }
- }, { passive: false }); // Important for preventDefault to work
-
- // Mark this element as having a scroll handler attached
- (container as HTMLElement).setAttribute('data-scroll-handler-attached', 'true');
- }
- });
-
- // Update compose state
- setComposeBody(formattedContent);
- setLocalContent(formattedContent);
- console.log('[DEBUG] Successfully set compose content with scrollable message area');
+ const fallbackContent = emailToProcess.content.replace(/<[^>]*>/g, '');
+ composeBodyRef.current.innerHTML = `
+
+
+
Error loading original message.
+
+ Technical details: ${error instanceof Error ? error.message : 'Unknown error'}
+
+
+ `;
+ setComposeBody(fallbackContent);
+ setLocalContent(fallbackContent);
}
} catch (error) {
console.error('[DEBUG] Error initializing compose content:', error);