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

View File

@ -159,9 +159,17 @@ export default function ComposeEmail({
// Now proceed with the usual decoding
const type = replyTo ? 'reply' : 'forward';
// ========== MATCH PANEL 3 CONTENT HANDLING ==========
try {
// Parse the email to get headers and content - using the same function as panel 3
const decoded = await decodeEmail(emailToProcess.content);
// Get the actual email content - similar to panel 3
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:', {
hasHtml: !!decoded.html,
hasText: !!decoded.text,
@ -169,56 +177,46 @@ export default function ComposeEmail({
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 = '';
if (decoded.html) {
// Just sanitize the HTML directly - same as panel 3
// Sanitize HTML exactly as in Panel 3
cleanContent = DOMPurify.sanitize(decoded.html);
} 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>`;
} 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
const getSafeEmailInfo = (email: any) => {
const fromValue = email && email.from ?
(typeof email.from === 'object' && email.from.text) ? email.from.text :
(Array.isArray(email.from) && email.from[0]) ?
(email.from[0].name || email.from[0].address) : 'Unknown Sender'
: 'Unknown Sender';
// Extract reliable metadata
const from = decoded.from ||
(emailToProcess.fromName ? `${emailToProcess.fromName} <${emailToProcess.from}>` : emailToProcess.from) ||
'Unknown Sender';
const dateValue = email && email.date ?
new Date(email.date).toLocaleString() : new Date().toLocaleString();
const date = decoded.date ?
new Date(decoded.date).toLocaleString() :
(emailToProcess.date ? new Date(emailToProcess.date).toLocaleString() : new Date().toLocaleString());
const subjectValue = email && email.subject ? email.subject : 'No Subject';
const subject = decoded.subject || emailToProcess.subject || 'No Subject';
const toValue = email && email.to ?
(typeof email.to === 'object' && email.to.text) ? email.to.text :
(Array.isArray(email.to)) ? email.to.map((t: any) => t.address || t.name || '').filter(Boolean).join(', ') : ''
: '';
const to = decoded.to ||
(emailToProcess.to && Array.isArray(emailToProcess.to) ?
emailToProcess.to.map((t: any) => t.address || t.name || '').filter(Boolean).join(', ') :
emailToProcess.to) ||
'';
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 decodedInfo = getSafeEmailInfo(decoded);
const emailInfo = getSafeEmailInfo(emailToProcess);
// 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;
const cc = decoded.cc ||
(emailToProcess.cc && Array.isArray(emailToProcess.cc) ?
emailToProcess.cc.map((c: any) => c.address || c.name || '').filter(Boolean).join(', ') :
emailToProcess.cc) ||
'';
// Format the content based on reply type
const quotedContent = type === 'forward' ? `
@ -235,10 +233,10 @@ export default function ComposeEmail({
</div>
` : `
<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 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>
`;
@ -303,20 +301,29 @@ export default function ComposeEmail({
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
const fallbackContent = emailToProcess.content.replace(/<[^>]*>/g, '');
composeBodyRef.current.innerHTML = `
console.error('[DEBUG] Error parsing email for compose:', error);
// Fallback to basic content display
const errorContent = `
<div class="compose-area" contenteditable="true">
<br/>
<div style="color: #ef4444;">Error loading original message.</div>
<div style="color: #64748b; font-size: 0.875rem; margin-top: 0.5rem;">
Technical details: ${error instanceof Error ? error.message : 'Unknown error'}
<div style="color: #64748b;">
---------- Original Message ---------<br/>
${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>
`;
setComposeBody(fallbackContent);
setLocalContent(fallbackContent);
if (composeBodyRef.current) {
composeBodyRef.current.innerHTML = errorContent;
setComposeBody(errorContent);
setLocalContent(errorContent);
}
}
} catch (error) {
console.error('[DEBUG] Error initializing compose content:', error);