panel 2 courier

This commit is contained in:
alma 2025-04-25 11:09:24 +02:00
parent 4afe503b8d
commit 64c9b15097
2 changed files with 50 additions and 31 deletions

View File

@ -72,14 +72,23 @@ export async function GET(request: Request) {
const adjustedStart = Math.min(start, mailbox.exists); const adjustedStart = Math.min(start, mailbox.exists);
const adjustedEnd = Math.min(end, mailbox.exists); const adjustedEnd = Math.min(end, mailbox.exists);
// Fetch messages from the current folder // Fetch messages from the current folder with content
const messages = await client.fetch(`${adjustedStart}:${adjustedEnd}`, { const messages = await client.fetch(`${adjustedStart}:${adjustedEnd}`, {
envelope: true, envelope: true,
flags: true, flags: true,
bodyStructure: true bodyStructure: true,
source: true, // Get the full email source
bodyParts: ['text/plain', 'text/html'] // Get both text and HTML content
}); });
for await (const message of messages) { for await (const message of messages) {
// Get the email content
let content = '';
if (message.bodyParts) {
// Prefer HTML content if available
content = message.bodyParts.get('text/html')?.toString() || message.bodyParts.get('text/plain')?.toString() || '';
}
result.push({ result.push({
id: message.uid, id: message.uid,
from: message.envelope.from?.[0]?.address || '', from: message.envelope.from?.[0]?.address || '',
@ -91,9 +100,14 @@ export async function GET(request: Request) {
starred: message.flags.has('\\Flagged'), starred: message.flags.has('\\Flagged'),
folder: mailbox.path, folder: mailbox.path,
hasAttachments: message.bodyStructure?.type === 'multipart', hasAttachments: message.bodyStructure?.type === 'multipart',
flags: Array.from(message.flags) flags: Array.from(message.flags),
content: content,
source: message.source?.toString() || '' // Include full email source for parsing
}); });
} }
// Sort results by date, most recent first
result.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
} }
return NextResponse.json({ return NextResponse.json({

View File

@ -798,7 +798,14 @@ export default function CourrierPage() {
// Sort emails by date (most recent first) // Sort emails by date (most recent first)
const sortedEmails = useMemo(() => { const sortedEmails = useMemo(() => {
return [...emails].sort((a, b) => { return [...emails].sort((a, b) => {
return new Date(b.date).getTime() - new Date(a.date).getTime(); const dateA = new Date(a.date);
const dateB = new Date(b.date);
// First sort by date
const dateDiff = dateB.getTime() - dateA.getTime();
if (dateDiff !== 0) return dateDiff;
// If dates are equal, maintain stable order using email ID
return Number(b.id) - Number(a.id);
}); });
}, [emails]); }, [emails]);
@ -819,7 +826,7 @@ export default function CourrierPage() {
email.subject.toLowerCase().includes(query) || email.subject.toLowerCase().includes(query) ||
email.from.toLowerCase().includes(query) || email.from.toLowerCase().includes(query) ||
email.to.toLowerCase().includes(query) || email.to.toLowerCase().includes(query) ||
email.content.toLowerCase().includes(query) (email.content || '').toLowerCase().includes(query)
); );
}, [sortedEmails, searchQuery]); }, [sortedEmails, searchQuery]);
@ -1056,7 +1063,7 @@ export default function CourrierPage() {
const renderEmailListItem = (email: Email) => ( const renderEmailListItem = (email: Email) => (
<div <div
key={email.id} key={email.id}
className={`p-3 hover:bg-gray-50/50 transition-colors cursor-pointer flex items-start gap-3 ${ className={`py-2 px-3 hover:bg-gray-50/50 transition-colors cursor-pointer flex items-start gap-3 ${
selectedEmail?.id === email.id ? 'bg-gray-50/80' : '' selectedEmail?.id === email.id ? 'bg-gray-50/80' : ''
}`} }`}
onClick={() => handleEmailSelect(email.id)} onClick={() => handleEmailSelect(email.id)}
@ -1070,31 +1077,29 @@ export default function CourrierPage() {
/> />
</div> </div>
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<div className="flex items-center justify-between gap-2 mb-1"> <div className="flex items-center justify-between gap-2">
<div className="flex items-center gap-2 min-w-0"> <h3 className={`text-sm truncate ${!email.read ? 'font-semibold text-gray-900' : 'text-gray-600'}`}>
<span className={`text-sm truncate ${!email.read ? 'font-semibold text-gray-900' : 'text-gray-600'}`}> {email.subject || '(No subject)'}
</h3>
<span className="text-xs text-gray-500 whitespace-nowrap flex-shrink-0">
{formatDate(new Date(email.date))}
</span>
</div>
<div className="flex items-center gap-2 text-sm text-gray-600">
<span className="truncate">
{email.fromName || email.from} {email.fromName || email.from}
</span> </span>
{!email.read && ( {!email.read && (
<span className="w-1.5 h-1.5 bg-blue-600 rounded-full flex-shrink-0"></span> <span className="w-1.5 h-1.5 bg-blue-600 rounded-full flex-shrink-0"></span>
)} )}
</div> </div>
<span className="text-xs text-gray-500 whitespace-nowrap"> <div className="text-xs text-gray-500 line-clamp-1 mt-0.5">
{formatDate(new Date(email.date))} {email.content ? (
</span>
</div>
<h3 className={`text-sm truncate mb-0.5 ${!email.read ? 'text-gray-900' : 'text-gray-600'}`}>
{email.subject || '(No subject)'}
</h3>
<EmailPreview email={email} /> <EmailPreview email={email} />
) : (
'No content available'
)}
</div> </div>
<div className="flex-none flex items-center gap-1">
{email.starred && (
<Star className="h-4 w-4 text-yellow-400 fill-yellow-400" />
)}
{email.attachments && email.attachments.length > 0 && (
<Paperclip className="h-4 w-4 text-gray-400" />
)}
</div> </div>
</div> </div>
); );
@ -1354,13 +1359,13 @@ export default function CourrierPage() {
); );
}; };
// Update searchEmails to just set the search query since filteredEmails is computed by useMemo
const searchEmails = (query: string) => { const searchEmails = (query: string) => {
setSearchQuery(query.trim()); setSearchQuery(query);
}; };
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const query = e.target.value; searchEmails(e.target.value);
setSearchQuery(query);
}; };
const renderEmailPreview = (email: Email) => { const renderEmailPreview = (email: Email) => {