mail page ui correction maj compose 9

This commit is contained in:
alma 2025-04-16 12:28:54 +02:00
parent eca8d1ee01
commit c2395e51d1

View File

@ -47,6 +47,13 @@ interface Email {
category: string;
}
interface Attachment {
name: string;
type: string;
content: string;
encoding: string;
}
// Improved MIME Decoder Implementation for Infomaniak
function extractBoundary(headers: string): string | null {
const boundaryMatch = headers.match(/boundary="?([^"\r\n;]+)"?/i) ||
@ -451,7 +458,7 @@ export default function MailPage() {
const [itemToDelete, setItemToDelete] = useState<number | null>(null);
const [showCc, setShowCc] = useState(false);
const [contentLoading, setContentLoading] = useState(false);
const [attachments, setAttachments] = useState<File[]>([]);
const [attachments, setAttachments] = useState<Attachment[]>([]);
// Move getSelectedEmail inside the component
const getSelectedEmail = () => {
@ -621,7 +628,7 @@ export default function MailPage() {
}
};
// Handle reply
// Handle reply with MIME encoding
const handleReply = async (type: 'reply' | 'replyAll' | 'forward') => {
const selectedEmailData = getSelectedEmail();
if (!selectedEmailData) return;
@ -629,25 +636,158 @@ export default function MailPage() {
setShowCompose(true);
const subject = `${type === 'forward' ? 'Fwd: ' : 'Re: '}${selectedEmailData.subject}`;
let to = '';
let cc = '';
let content = '';
// Parse the original email content using MIME decoder
const parsedEmail = parseFullEmail(selectedEmailData.body);
const decodedBody = parsedEmail.text || parsedEmail.html || selectedEmailData.body;
// Format the date properly
const emailDate = new Date(selectedEmailData.date).toLocaleString('en-US', {
weekday: 'short',
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
hour12: true
});
switch (type) {
case 'reply':
to = selectedEmailData.from;
content = `\n\nOn ${new Date(selectedEmailData.date).toLocaleString()}, ${selectedEmailData.fromName} wrote:\n> ${selectedEmailData.body.split('\n').join('\n> ')}`;
content = `\n\nOn ${emailDate}, ${selectedEmailData.fromName} wrote:\n> ${decodedBody.split('\n').join('\n> ')}`;
break;
case 'replyAll':
to = selectedEmailData.from;
content = `\n\nOn ${new Date(selectedEmailData.date).toLocaleString()}, ${selectedEmailData.fromName} wrote:\n> ${selectedEmailData.body.split('\n').join('\n> ')}`;
// Extract CC addresses from the original email, excluding our own address
const originalCc = selectedEmailData.cc || '';
const ourEmail = accounts.find(acc => acc.id === selectedEmailData.accountId)?.email || '';
const ccAddresses = originalCc
.split(',')
.map(addr => addr.trim())
.filter(addr => addr !== ourEmail && addr !== selectedEmailData.from);
cc = ccAddresses.join(', ');
content = `\n\nOn ${emailDate}, ${selectedEmailData.fromName} wrote:\n> ${decodedBody.split('\n').join('\n> ')}`;
break;
case 'forward':
content = `\n\n---------- Forwarded message ----------\nFrom: ${selectedEmailData.fromName} <${selectedEmailData.from}>\nDate: ${new Date(selectedEmailData.date).toLocaleString()}\nSubject: ${selectedEmailData.subject}\n\n${selectedEmailData.body}`;
// Include original attachments if any
const attachmentInfo = parsedEmail.attachments.length > 0
? '\n\n-------- Attachments --------\n' +
parsedEmail.attachments.map(att => att.filename).join('\n')
: '';
content = `\n\n---------- Forwarded message ----------\n` +
`From: ${selectedEmailData.fromName} <${selectedEmailData.from}>\n` +
`Date: ${emailDate}\n` +
`Subject: ${selectedEmailData.subject}\n` +
`To: ${selectedEmailData.to}\n` +
(selectedEmailData.cc ? `Cc: ${selectedEmailData.cc}\n` : '') +
`\n\n${decodedBody}${attachmentInfo}`;
break;
}
// Set the form state
setComposeSubject(subject);
setComposeTo(to);
setComposeBody(cleanEmailContent(content));
setComposeCc(cc);
setComposeBody(content);
// Show CC field if there are CC recipients
if (cc) {
setShowCc(true);
}
// Handle attachments for forwarded emails
if (type === 'forward' && parsedEmail.attachments.length > 0) {
// You'll need to implement attachment handling here
// This could involve creating File objects from the attachment data
// or storing the attachment information to be processed when sending
handleForwardedAttachments(parsedEmail.attachments);
}
};
// Handle forwarded attachments
const handleForwardedAttachments = (attachments: Array<{
filename: string;
contentType: string;
encoding: string;
content: string;
}>) => {
// Store attachment information in state
setAttachments(attachments.map(att => ({
name: att.filename,
type: att.contentType,
content: att.content,
encoding: att.encoding
})));
};
// Modified send function to handle MIME encoding
const handleSend = async () => {
try {
// Create multipart message
const boundary = `----=_Part_${Date.now()}`;
let mimeContent = [
`Content-Type: multipart/mixed; boundary="${boundary}"`,
'',
`--${boundary}`,
'Content-Type: text/plain; charset=utf-8',
'Content-Transfer-Encoding: 7bit',
'',
composeBody,
''
];
// Add attachments if any
if (attachments.length > 0) {
for (const attachment of attachments) {
mimeContent = mimeContent.concat([
`--${boundary}`,
`Content-Type: ${attachment.type}`,
`Content-Transfer-Encoding: base64`,
`Content-Disposition: attachment; filename="${attachment.name}"`,
'',
attachment.content,
''
]);
}
}
// Close the multipart message
mimeContent.push(`--${boundary}--`);
// Send the email with MIME content
await fetch('/api/mail/send', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
to: composeTo,
cc: composeCc,
bcc: composeBcc,
subject: composeSubject,
body: mimeContent.join('\r\n'),
attachments: attachments
})
});
// Clear the form
setShowCompose(false);
setComposeTo('');
setComposeCc('');
setComposeBcc('');
setComposeSubject('');
setComposeBody('');
setShowCc(false);
setShowBcc(false);
setAttachments([]);
} catch (error) {
console.error('Error sending email:', error);
}
};
const handleBulkDelete = () => {
@ -695,7 +835,12 @@ export default function MailPage() {
const handleFileAttachment = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.files) {
setAttachments(Array.from(e.target.files));
setAttachments(Array.from(e.target.files).map(file => ({
name: file.name,
type: file.type,
content: URL.createObjectURL(file),
encoding: 'base64'
})));
}
};
@ -1231,32 +1376,7 @@ export default function MailPage() {
</Button>
<Button
className="bg-blue-600 text-white hover:bg-blue-700"
onClick={async () => {
try {
await fetch('/api/mail/send', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
to: composeTo,
cc: composeCc,
bcc: composeBcc,
subject: composeSubject,
body: composeBody
})
});
setShowCompose(false);
// Clear form
setComposeTo('');
setComposeCc('');
setComposeBcc('');
setComposeSubject('');
setComposeBody('');
setShowCc(false);
setShowBcc(false);
} catch (error) {
console.error('Error sending email:', error);
}
}}
onClick={handleSend}
>
Send
</Button>