panel 2 courier api restore

This commit is contained in:
alma 2025-04-25 21:58:57 +02:00
parent 78c8823a01
commit 6eb06a5dc2
2 changed files with 99 additions and 81 deletions

View File

@ -135,24 +135,17 @@ function EmailContent({ email }: { email: Email }) {
if (mounted) { if (mounted) {
// Update the email content with the fetched full content // Update the email content with the fetched full content
email.content = fullContent.content; email.content = fullContent.content;
email.contentFetched = true;
// Render the content // Render the content - call ourselves again now that we have content
const sanitizedHtml = DOMPurify.sanitize(fullContent.content); setDebugInfo('Content fetched from API, reprocessing');
setContent( loadContent();
<div return;
className="email-content prose prose-sm max-w-none dark:prose-invert"
dangerouslySetInnerHTML={{ __html: sanitizedHtml }}
/>
);
setDebugInfo('Rendered fetched HTML content');
setError(null);
setIsLoading(false);
} }
return;
} }
// Use existing content if available // Use existing content if available
console.log('Using existing content for email'); console.log('Processing content for email:', email.id);
const formattedEmail = email.content.trim(); const formattedEmail = email.content.trim();
if (!formattedEmail) { if (!formattedEmail) {
@ -165,23 +158,13 @@ function EmailContent({ email }: { email: Email }) {
return; return;
} }
// Check if content is already HTML try {
if (formattedEmail.startsWith('<') && formattedEmail.endsWith('>')) { // Always try to use the mail parser first for consistency
// Content is likely HTML, sanitize and display directly console.log('Parsing email content with mailparser');
const sanitizedHtml = DOMPurify.sanitize(formattedEmail);
setContent(
<div
className="email-content prose prose-sm max-w-none dark:prose-invert"
dangerouslySetInnerHTML={{ __html: sanitizedHtml }}
/>
);
setDebugInfo('Rendered existing HTML content');
} else {
// Use mailparser for more complex formats
console.log('Parsing email content');
const parsedEmail = await decodeEmail(formattedEmail); const parsedEmail = await decodeEmail(formattedEmail);
if (parsedEmail.html) { if (parsedEmail.html) {
console.log('Using HTML content from parser');
const sanitizedHtml = DOMPurify.sanitize(parsedEmail.html); const sanitizedHtml = DOMPurify.sanitize(parsedEmail.html);
setContent( setContent(
<div <div
@ -191,6 +174,7 @@ function EmailContent({ email }: { email: Email }) {
); );
setDebugInfo('Rendered HTML content from parser'); setDebugInfo('Rendered HTML content from parser');
} else if (parsedEmail.text) { } else if (parsedEmail.text) {
console.log('Using text content from parser');
setContent( setContent(
<div className="email-content whitespace-pre-wrap"> <div className="email-content whitespace-pre-wrap">
{parsedEmail.text} {parsedEmail.text}
@ -198,9 +182,36 @@ function EmailContent({ email }: { email: Email }) {
); );
setDebugInfo('Rendered text content from parser'); setDebugInfo('Rendered text content from parser');
} else { } else {
setContent(<div className="text-gray-500">No displayable content available</div>); // Fallback to direct display if parser didn't give us anything
setDebugInfo('No HTML or text content in parsed email'); if (formattedEmail.startsWith('<') && formattedEmail.endsWith('>')) {
// Content is likely HTML, sanitize and display directly
const sanitizedHtml = DOMPurify.sanitize(formattedEmail);
setContent(
<div
className="email-content prose prose-sm max-w-none dark:prose-invert"
dangerouslySetInnerHTML={{ __html: sanitizedHtml }}
/>
);
setDebugInfo('Rendered raw HTML content');
} else {
// Just display as text
setContent(
<div className="email-content whitespace-pre-wrap">
{formattedEmail}
</div>
);
setDebugInfo('Rendered raw text content');
}
} }
} catch (parseError) {
console.error('Error parsing email with mailparser:', parseError);
// Fallback to direct display if parser fails
if (formattedEmail.startsWith('<') && formattedEmail.endsWith('>')) {
// Content is likely HTML, sanitize and display directly
const sanitizedHtml = DOMPurify.sanitize(formattedEmail);
setContent(
<div
className="email-content prose prose-sm max-w-none dark:prose-invert"
} }
setError(null); setError(null);

View File

@ -159,9 +159,17 @@ export default function ComposeEmail({
// Now proceed with the usual decoding // Now proceed with the usual decoding
const type = replyTo ? 'reply' : 'forward'; const type = replyTo ? 'reply' : 'forward';
// ========== MATCH PANEL 3 CONTENT HANDLING ==========
try { try {
// Parse the email to get headers and content - using the same function as panel 3 // Get the actual email content - similar to panel 3
const decoded = await decodeEmail(emailToProcess.content); const formattedEmail = emailToProcess.content.trim();
if (!formattedEmail) {
throw new Error("Email content is empty");
}
// Parse the email just like panel 3
const decoded = await decodeEmail(formattedEmail);
console.log('[DEBUG] Decoded email for compose:', { console.log('[DEBUG] Decoded email for compose:', {
hasHtml: !!decoded.html, hasHtml: !!decoded.html,
hasText: !!decoded.text, hasText: !!decoded.text,
@ -169,57 +177,47 @@ export default function ComposeEmail({
subject: decoded.subject subject: decoded.subject
}); });
// This is exactly how panel 3 handles email content - simple sanitization of HTML or showing text // Get clean content similar to Panel 3
let cleanContent = ''; let cleanContent = '';
if (decoded.html) { if (decoded.html) {
// Just sanitize the HTML directly - same as panel 3 // Sanitize HTML exactly as in Panel 3
cleanContent = DOMPurify.sanitize(decoded.html); cleanContent = DOMPurify.sanitize(decoded.html);
} else if (decoded.text) { } else if (decoded.text) {
// Use whitespace-pre-wrap for text - same as panel 3 // Format text content with proper whitespace like Panel 3
cleanContent = `<div class="whitespace-pre-wrap">${decoded.text}</div>`; cleanContent = `<div class="whitespace-pre-wrap">${decoded.text}</div>`;
} else { } else {
cleanContent = '<div>No displayable content available</div>'; // Fallback to raw content if parsing failed
if (formattedEmail.startsWith('<') && formattedEmail.endsWith('>')) {
cleanContent = DOMPurify.sanitize(formattedEmail);
} else {
cleanContent = `<div class="whitespace-pre-wrap">${formattedEmail}</div>`;
}
} }
// Helper function to safely extract email information // Extract reliable metadata
const getSafeEmailInfo = (email: any) => { const from = decoded.from ||
const fromValue = email && email.from ? (emailToProcess.fromName ? `${emailToProcess.fromName} <${emailToProcess.from}>` : emailToProcess.from) ||
(typeof email.from === 'object' && email.from.text) ? email.from.text : 'Unknown Sender';
(Array.isArray(email.from) && email.from[0]) ?
(email.from[0].name || email.from[0].address) : 'Unknown Sender'
: 'Unknown Sender';
const dateValue = email && email.date ?
new Date(email.date).toLocaleString() : new Date().toLocaleString();
const subjectValue = email && email.subject ? email.subject : 'No Subject';
const toValue = email && email.to ? const date = decoded.date ?
(typeof email.to === 'object' && email.to.text) ? email.to.text : new Date(decoded.date).toLocaleString() :
(Array.isArray(email.to)) ? email.to.map((t: any) => t.address || t.name || '').filter(Boolean).join(', ') : '' (emailToProcess.date ? new Date(emailToProcess.date).toLocaleString() : new Date().toLocaleString());
: '';
const subject = decoded.subject || emailToProcess.subject || 'No Subject';
const ccValue = email && email.cc ?
(typeof email.cc === 'object' && email.cc.text) ? email.cc.text :
(Array.isArray(email.cc) && email.cc.length > 0) ?
email.cc.map((c: any) => c.address || c.name || '').filter(Boolean).join(', ') : ''
: '';
return { from: fromValue, date: dateValue, subject: subjectValue, to: toValue, cc: ccValue };
};
// Get info from both sources and combine const to = decoded.to ||
const decodedInfo = getSafeEmailInfo(decoded); (emailToProcess.to && Array.isArray(emailToProcess.to) ?
const emailInfo = getSafeEmailInfo(emailToProcess); emailToProcess.to.map((t: any) => t.address || t.name || '').filter(Boolean).join(', ') :
emailToProcess.to) ||
'';
const cc = decoded.cc ||
(emailToProcess.cc && Array.isArray(emailToProcess.cc) ?
emailToProcess.cc.map((c: any) => c.address || c.name || '').filter(Boolean).join(', ') :
emailToProcess.cc) ||
'';
// Use the most complete information available
const from = decodedInfo.from !== 'Unknown Sender' ? decodedInfo.from : emailInfo.from;
const date = decodedInfo.date;
const subject = decodedInfo.subject !== 'No Subject' ? decodedInfo.subject : emailInfo.subject;
const to = decodedInfo.to || emailInfo.to;
const cc = decodedInfo.cc || emailInfo.cc;
// Format the content based on reply type // Format the content based on reply type
const quotedContent = type === 'forward' ? ` const quotedContent = type === 'forward' ? `
<div class="forwarded-message" style="border-top: 1px solid #e5e7eb; padding-top: 20px; margin-top: 20px; color: #6b7280; font-size: 0.875rem;"> <div class="forwarded-message" style="border-top: 1px solid #e5e7eb; padding-top: 20px; margin-top: 20px; color: #6b7280; font-size: 0.875rem;">
@ -235,10 +233,10 @@ export default function ComposeEmail({
</div> </div>
` : ` ` : `
<div class="quoted-message" style="border-top: 1px solid #e5e7eb; padding-top: 20px; margin-top: 20px; color: #6b7280; font-size: 0.875rem;"> <div class="quoted-message" style="border-top: 1px solid #e5e7eb; padding-top: 20px; margin-top: 20px; color: #6b7280; font-size: 0.875rem;">
On ${decoded.date ? decoded.date.toLocaleString() : new Date().toLocaleString()}, ${decoded.from || 'Unknown Sender'} wrote: On ${date}, ${from} wrote:
</div> </div>
<div class="message-content prose prose-sm max-w-none" style="margin: 10px 0 0 10px; padding: 10px; border-left: 2px solid #e5e7eb; border: 1px solid #e5e7eb; border-radius: 4px; max-height: 300px; overflow-y: auto; color: #374151;"> <div class="message-content prose prose-sm max-w-none" style="margin: 10px 0 0 10px; padding: 10px; border-left: 2px solid #e5e7eb; border: 1px solid #e5e7eb; border-radius: 4px; max-height: 300px; overflow-y: auto; color: #374151;">
${cleanContent} ${cleanContent || '<div>No content available</div>'}
</div> </div>
`; `;
@ -303,20 +301,29 @@ export default function ComposeEmail({
console.log('[DEBUG] Successfully set compose content with scrollable message area'); console.log('[DEBUG] Successfully set compose content with scrollable message area');
} }
} catch (error) { } catch (error) {
console.error('[DEBUG] Error parsing email:', error); console.error('[DEBUG] Error parsing email for compose:', error);
// Fallback to simple content extraction
const fallbackContent = emailToProcess.content.replace(/<[^>]*>/g, ''); // Fallback to basic content display
composeBodyRef.current.innerHTML = ` const errorContent = `
<div class="compose-area" contenteditable="true"> <div class="compose-area" contenteditable="true">
<br/> <br/>
<div style="color: #ef4444;">Error loading original message.</div> <div style="color: #64748b;">
<div style="color: #64748b; font-size: 0.875rem; margin-top: 0.5rem;"> ---------- Original Message ---------<br/>
Technical details: ${error instanceof Error ? error.message : 'Unknown error'} ${emailToProcess.subject ? `Subject: ${emailToProcess.subject}<br/>` : ''}
${emailToProcess.from ? `From: ${emailToProcess.from}<br/>` : ''}
${emailToProcess.date ? `Date: ${new Date(emailToProcess.date).toLocaleString()}<br/>` : ''}
</div>
<div style="color: #64748b; border-left: 2px solid #e5e7eb; padding-left: 10px; margin: 10px 0;">
${emailToProcess.preview || 'No content available'}
</div> </div>
</div> </div>
`; `;
setComposeBody(fallbackContent);
setLocalContent(fallbackContent); if (composeBodyRef.current) {
composeBodyRef.current.innerHTML = errorContent;
setComposeBody(errorContent);
setLocalContent(errorContent);
}
} }
} catch (error) { } catch (error) {
console.error('[DEBUG] Error initializing compose content:', error); console.error('[DEBUG] Error initializing compose content:', error);