mail page ui correction maj compose 9
This commit is contained in:
parent
eca8d1ee01
commit
c2395e51d1
@ -47,6 +47,13 @@ interface Email {
|
|||||||
category: string;
|
category: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Attachment {
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
content: string;
|
||||||
|
encoding: string;
|
||||||
|
}
|
||||||
|
|
||||||
// Improved MIME Decoder Implementation for Infomaniak
|
// Improved MIME Decoder Implementation for Infomaniak
|
||||||
function extractBoundary(headers: string): string | null {
|
function extractBoundary(headers: string): string | null {
|
||||||
const boundaryMatch = headers.match(/boundary="?([^"\r\n;]+)"?/i) ||
|
const boundaryMatch = headers.match(/boundary="?([^"\r\n;]+)"?/i) ||
|
||||||
@ -451,7 +458,7 @@ export default function MailPage() {
|
|||||||
const [itemToDelete, setItemToDelete] = useState<number | null>(null);
|
const [itemToDelete, setItemToDelete] = useState<number | null>(null);
|
||||||
const [showCc, setShowCc] = useState(false);
|
const [showCc, setShowCc] = useState(false);
|
||||||
const [contentLoading, setContentLoading] = useState(false);
|
const [contentLoading, setContentLoading] = useState(false);
|
||||||
const [attachments, setAttachments] = useState<File[]>([]);
|
const [attachments, setAttachments] = useState<Attachment[]>([]);
|
||||||
|
|
||||||
// Move getSelectedEmail inside the component
|
// Move getSelectedEmail inside the component
|
||||||
const getSelectedEmail = () => {
|
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 handleReply = async (type: 'reply' | 'replyAll' | 'forward') => {
|
||||||
const selectedEmailData = getSelectedEmail();
|
const selectedEmailData = getSelectedEmail();
|
||||||
if (!selectedEmailData) return;
|
if (!selectedEmailData) return;
|
||||||
@ -629,25 +636,158 @@ export default function MailPage() {
|
|||||||
setShowCompose(true);
|
setShowCompose(true);
|
||||||
const subject = `${type === 'forward' ? 'Fwd: ' : 'Re: '}${selectedEmailData.subject}`;
|
const subject = `${type === 'forward' ? 'Fwd: ' : 'Re: '}${selectedEmailData.subject}`;
|
||||||
let to = '';
|
let to = '';
|
||||||
|
let cc = '';
|
||||||
let content = '';
|
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) {
|
switch (type) {
|
||||||
case 'reply':
|
case 'reply':
|
||||||
to = selectedEmailData.from;
|
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;
|
break;
|
||||||
|
|
||||||
case 'replyAll':
|
case 'replyAll':
|
||||||
to = selectedEmailData.from;
|
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;
|
break;
|
||||||
|
|
||||||
case 'forward':
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the form state
|
||||||
setComposeSubject(subject);
|
setComposeSubject(subject);
|
||||||
setComposeTo(to);
|
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 = () => {
|
const handleBulkDelete = () => {
|
||||||
@ -695,7 +835,12 @@ export default function MailPage() {
|
|||||||
|
|
||||||
const handleFileAttachment = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleFileAttachment = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
if (e.target.files) {
|
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>
|
||||||
<Button
|
<Button
|
||||||
className="bg-blue-600 text-white hover:bg-blue-700"
|
className="bg-blue-600 text-white hover:bg-blue-700"
|
||||||
onClick={async () => {
|
onClick={handleSend}
|
||||||
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);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Send
|
Send
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user