compose mime

This commit is contained in:
alma 2025-04-24 19:58:21 +02:00
parent da1390fb51
commit 616d52d8fb
2 changed files with 56 additions and 83 deletions

View File

@ -509,6 +509,7 @@ export default function CourrierPage() {
// Process emails keeping exact folder names and sort by date // Process emails keeping exact folder names and sort by date
const processedEmails = (data.emails || []) const processedEmails = (data.emails || [])
.filter((email: any) => email && email.body) // Filter out emails with no body
.map((email: any) => ({ .map((email: any) => ({
id: Number(email.id), id: Number(email.id),
accountId: 1, accountId: 1,
@ -527,20 +528,20 @@ export default function CourrierPage() {
raw: email.body || '' raw: email.body || ''
})); }));
// Only update unread count if we're in the Inbox folder
if (currentView === 'INBOX') {
const unreadInboxEmails = processedEmails.filter(
(email: Email) => !email.read && email.folder === 'INBOX'
).length;
setUnreadCount(unreadInboxEmails);
}
// Sort emails by date, ensuring most recent first // Sort emails by date, ensuring most recent first
const sortedEmails = processedEmails.sort((a: Email, b: Email) => { const sortedEmails = processedEmails.sort((a: Email, b: Email) => {
const dateA = new Date(a.date).getTime(); const dateA = new Date(a.date).getTime();
const dateB = new Date(b.date).getTime(); const dateB = new Date(b.date).getTime();
return dateB - dateA; // Most recent first return dateB - dateA; // Most recent first
}); });
// Only update unread count if we're in the Inbox folder
if (currentView === 'INBOX') {
const unreadInboxEmails = sortedEmails.filter(
(email: Email) => !email.read && email.folder === 'INBOX'
).length;
setUnreadCount(unreadInboxEmails);
}
if (isLoadMore) { if (isLoadMore) {
// When loading more, merge with existing emails and re-sort // When loading more, merge with existing emails and re-sort

View File

@ -84,90 +84,62 @@ export default function ComposeEmail({
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
useEffect(() => { useEffect(() => {
const initializeContent = async () => { if (replyTo || forwardFrom) {
if (!composeBodyRef.current) return; const initializeContent = async () => {
let content = '';
if (replyTo || forwardFrom) {
setIsLoading(true);
try { try {
const originalContent = replyTo?.body || forwardFrom?.body || ''; const emailToProcess = replyTo || forwardFrom;
if (!emailToProcess?.body) {
console.error('No email body found to process');
return;
}
// Parse the original email using the API
const response = await fetch('/api/parse-email', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ email: emailToProcess.body }),
});
if (!response.ok) {
throw new Error('Failed to parse email');
}
const parsedEmail = await response.json();
const originalContent = parsedEmail.html || parsedEmail.text || '';
// Create initial content without waiting for parsing // Format the reply/forward content
content = ` const prefix = replyTo ? '\n\n' : '\n\n---------- Forwarded message ----------\n\n';
<div class="compose-area" contenteditable="true" style="min-height: 100px; padding: 10px; color: #000000;"> const quoteStyle = 'border-left: 2px solid #ccc; margin-left: 1em; padding-left: 1em;';
<br/> const formattedContent = `
<div id="reply-placeholder">Loading original message...</div> <div><br/>${prefix}</div>
<div style="${quoteStyle}">
${originalContent}
</div> </div>
`; `;
// Set initial content immediately // Set the content in the compose area
composeBodyRef.current.innerHTML = content; if (composeBodyRef.current) {
setLocalContent(content); composeBodyRef.current.innerHTML = formattedContent;
// Place cursor at the beginning
// Place cursor at the beginning const selection = window.getSelection();
const composeArea = composeBodyRef.current.querySelector('.compose-area');
if (composeArea) {
const range = document.createRange(); const range = document.createRange();
const sel = window.getSelection(); range.setStart(composeBodyRef.current.firstChild || composeBodyRef.current, 0);
range.setStart(composeArea, 0);
range.collapse(true); range.collapse(true);
sel?.removeAllRanges(); selection?.removeAllRanges();
sel?.addRange(range); selection?.addRange(range);
(composeArea as HTMLElement).focus();
}
// Now parse the email content
if (originalContent.trim()) {
const decodedContent = await decodeComposeContent(originalContent);
const quotedContent = `
${forwardFrom ? `
<div style="border-top: 1px solid #e5e7eb; padding-top: 20px; margin-top: 20px; color: #6b7280; font-size: 0.875rem;">
---------- Forwarded message ---------<br/>
From: ${forwardFrom.from}<br/>
Date: ${new Date(forwardFrom.date).toLocaleString()}<br/>
Subject: ${forwardFrom.subject}<br/>
To: ${forwardFrom.to}<br/>
${forwardFrom.cc ? `Cc: ${forwardFrom.cc}<br/>` : ''}
<br/>
${decodedContent.html || decodedContent.text || 'No content available'}
</div>
` : `
<div style="border-top: 1px solid #e5e7eb; padding-top: 20px; margin-top: 20px; color: #6b7280; font-size: 0.875rem;">
On ${new Date(replyTo?.date || '').toLocaleString()}, ${replyTo?.from} wrote:
</div>
<blockquote style="margin: 0; padding-left: 1em; border-left: 2px solid #e5e7eb; color: #6b7280;">
${decodedContent.html || decodedContent.text || 'No content available'}
</blockquote>
`}
`;
// Replace placeholder with actual content
const placeholder = composeBodyRef.current.querySelector('#reply-placeholder');
if (placeholder) {
placeholder.insertAdjacentHTML('beforebegin', quotedContent);
placeholder.remove();
}
} }
// Update compose state
setComposeBody(formattedContent);
} catch (error) { } catch (error) {
console.error('Error parsing email:', error); console.error('Error initializing compose content:', error);
const placeholder = composeBodyRef.current.querySelector('#reply-placeholder');
if (placeholder) {
placeholder.textContent = 'Error loading original message.';
}
} finally {
setIsLoading(false);
} }
} else { };
content = `<div class="compose-area" contenteditable="true" style="min-height: 100px; padding: 10px; color: #000000;"></div>`;
composeBodyRef.current.innerHTML = content; initializeContent();
setLocalContent(content); }
}
};
initializeContent();
}, [replyTo, forwardFrom]); }, [replyTo, forwardFrom]);
const handleInput = (e: React.FormEvent<HTMLDivElement>) => { const handleInput = (e: React.FormEvent<HTMLDivElement>) => {