compose mime
This commit is contained in:
parent
da1390fb51
commit
616d52d8fb
@ -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
|
||||||
|
|||||||
@ -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>) => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user