mail page rest

This commit is contained in:
alma 2025-04-21 12:58:18 +02:00
parent 599336ed60
commit 312577bbca

View File

@ -123,10 +123,16 @@ function decodeQuotedPrintable(text: string, charset: string): string {
}
function parseFullEmail(emailRaw: string) {
console.log('=== parseFullEmail Debug ===');
console.log('Input email length:', emailRaw.length);
console.log('First 200 chars:', emailRaw.substring(0, 200));
// Check if this is a multipart message by looking for boundary definition
const boundaryMatch = emailRaw.match(/boundary="?([^"\r\n;]+)"?/i) ||
emailRaw.match(/boundary=([^\r\n;]+)/i);
console.log('Boundary found:', boundaryMatch ? boundaryMatch[1] : 'No boundary');
if (boundaryMatch) {
const boundary = boundaryMatch[1].trim();
@ -439,20 +445,21 @@ function decodeMimeContent(content: string): string {
// Add this helper function
const renderEmailContent = (email: Email) => {
console.log('=== renderEmailContent Debug ===');
console.log('Email ID:', email.id);
console.log('Subject:', email.subject);
console.log('Body length:', email.body.length);
console.log('First 200 chars of body:', email.body.substring(0, 200));
try {
console.log('=== Email Content Debug ===');
console.log('Raw email body:', email.body.substring(0, 200) + '...'); // First 200 chars
console.log('Email ID:', email.id);
console.log('Email subject:', email.subject);
const parsed = parseFullEmail(email.body) as ParsedEmailContent | ParsedEmailMetadata;
console.log('Parsed content type:', 'text' in parsed ? 'ParsedEmailContent' : 'ParsedEmailMetadata');
const parsed = parseFullEmail(email.body);
console.log('Parsed content:', {
hasText: 'text' in parsed ? !!parsed.text : false,
hasHtml: 'html' in parsed ? !!parsed.html : false,
hasAttachments: 'attachments' in parsed ? parsed.attachments?.length : 0
textPreview: 'text' in parsed ? parsed.text?.substring(0, 100) : 'No text',
htmlPreview: 'html' in parsed ? parsed.html?.substring(0, 100) : 'No HTML'
});
const content = 'text' in parsed ? parsed.text : ('html' in parsed ? parsed.html || '' : email.body);
console.log('Selected content type:', isHtml ? 'HTML' : 'Plain text');
console.log('Content preview:', content.substring(0, 100) + '...');
@ -556,7 +563,7 @@ const renderEmailContent = (email: Email) => {
);
}
} catch (e) {
console.error('Error rendering email content:', e);
console.error('Error in renderEmailContent:', e);
return (
<div className="text-sm text-gray-500">
Error rendering email content. Please try refreshing the page.
@ -1206,130 +1213,92 @@ export default function MailPage() {
}, [availableFolders]);
// Update the email list item to match header checkbox alignment
const renderEmailListItem = (email: Email) => (
<div
key={email.id}
className={`flex items-center gap-3 px-4 py-2 hover:bg-gray-50/80 cursor-pointer ${
selectedEmail?.id === email.id ? 'bg-blue-50/50' : ''
} ${!email.read ? 'bg-blue-50/20' : ''}`}
onClick={() => handleEmailSelect(email.id)}
>
<Checkbox
checked={selectedEmails.includes(email.id.toString())}
onCheckedChange={(checked) => {
const e = { target: { checked }, stopPropagation: () => {} } as React.ChangeEvent<HTMLInputElement>;
handleEmailCheckbox(e, email.id);
}}
onClick={(e) => e.stopPropagation()}
className="mt-0.5"
/>
<div className="flex-1 min-w-0">
<div className="flex items-center justify-between gap-2">
<div className="flex items-center gap-2 min-w-0">
<span className={`text-sm truncate ${!email.read ? 'font-semibold text-gray-900' : 'text-gray-600'}`}>
{currentView === 'Sent' ? email.to : (
(() => {
const fromMatch = email.from.match(/^([^<]+)\s*<([^>]+)>$/);
return fromMatch ? fromMatch[1].trim() : email.from;
})()
)}
</span>
const renderEmailListItem = (email: Email) => {
console.log('=== Email List Item Debug ===');
console.log('Email ID:', email.id);
console.log('Subject:', email.subject);
console.log('Body length:', email.body.length);
console.log('First 100 chars of body:', email.body.substring(0, 100));
const preview = generateEmailPreview(email);
console.log('Generated preview:', preview);
return (
<div
key={email.id}
className={`flex items-center gap-3 px-4 py-2 hover:bg-gray-50/80 cursor-pointer ${
selectedEmail?.id === email.id ? 'bg-blue-50/50' : ''
} ${!email.read ? 'bg-blue-50/20' : ''}`}
onClick={() => handleEmailSelect(email.id)}
>
<Checkbox
checked={selectedEmails.includes(email.id.toString())}
onCheckedChange={(checked) => {
const e = { target: { checked }, stopPropagation: () => {} } as React.ChangeEvent<HTMLInputElement>;
handleEmailCheckbox(e, email.id);
}}
onClick={(e) => e.stopPropagation()}
className="mt-0.5"
/>
<div className="flex-1 min-w-0">
<div className="flex items-center justify-between gap-2">
<div className="flex items-center gap-2 min-w-0">
<span className={`text-sm truncate ${!email.read ? 'font-semibold text-gray-900' : 'text-gray-600'}`}>
{currentView === 'Sent' ? email.to : (
(() => {
const fromMatch = email.from.match(/^([^<]+)\s*<([^>]+)>$/);
return fromMatch ? fromMatch[1].trim() : email.from;
})()
)}
</span>
</div>
<div className="flex items-center gap-2 flex-shrink-0">
<span className="text-xs text-gray-500 whitespace-nowrap">
{formatDate(email.date)}
</span>
<Button
variant="ghost"
size="icon"
className="h-6 w-6 text-gray-400 hover:text-yellow-400"
onClick={(e) => toggleStarred(email.id, e)}
>
<Star className={`h-4 w-4 ${email.starred ? 'fill-yellow-400 text-yellow-400' : ''}`} />
</Button>
</div>
</div>
<div className="flex items-center gap-2 flex-shrink-0">
<span className="text-xs text-gray-500 whitespace-nowrap">
{formatDate(email.date)}
</span>
<Button
variant="ghost"
size="icon"
className="h-6 w-6 text-gray-400 hover:text-yellow-400"
onClick={(e) => toggleStarred(email.id, e)}
>
<Star className={`h-4 w-4 ${email.starred ? 'fill-yellow-400 text-yellow-400' : ''}`} />
</Button>
<h3 className="text-sm text-gray-900 truncate">
{email.subject || '(No subject)'}
</h3>
<div className="text-xs text-gray-500 truncate">
{preview}
</div>
</div>
<h3 className="text-sm text-gray-900 truncate">
{email.subject || '(No subject)'}
</h3>
<div className="text-xs text-gray-500 truncate">
{(() => {
try {
// First try to parse the full email
const parsed = parseFullEmail(email.body);
// Get text content from parsed email
let preview = '';
if ('text' in parsed && parsed.text) {
preview = parsed.text;
} else if ('html' in parsed && parsed.html) {
// If only HTML is available, extract text content
preview = parsed.html
.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '')
.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '')
.replace(/<[^>]+>/g, ' ')
.replace(/\s+/g, ' ')
.trim();
}
// If no preview from parsed content, try direct body
if (!preview) {
preview = email.body
.replace(/<[^>]+>/g, ' ')
.replace(/&nbsp;|&zwnj;|&raquo;|&laquo;|&gt;/g, ' ')
.replace(/\s+/g, ' ')
.trim();
}
// Clean up the preview
preview = preview
.replace(/^>+/gm, '') // Remove quoted text markers
.replace(/Content-Type:[^\n]+/g, '') // Remove MIME headers
.replace(/Content-Transfer-Encoding:[^\n]+/g, '')
.replace(/--[a-zA-Z0-9]+(-[a-zA-Z0-9]+)?/g, '') // Remove MIME boundaries
.replace(/boundary=[^\n]+/g, '')
.replace(/charset=[^\n]+/g, '')
.replace(/[\r\n]+/g, ' ')
.replace(/=3D/g, '=') // Fix common email client quirks
.replace(/=20/g, ' ')
.replace(/=E2=80=99/g, "'")
.replace(/=E2=80=9C/g, '"')
.replace(/=E2=80=9D/g, '"')
.replace(/=E2=80=93/g, '')
.replace(/=E2=80=94/g, '—')
.replace(/=C2=A0/g, ' ')
.replace(/=C3=A0/g, 'à')
.replace(/=C3=A9/g, 'é')
.replace(/=C3=A8/g, 'è')
.replace(/=C3=AA/g, 'ê')
.replace(/=C3=AB/g, 'ë')
.replace(/=C3=B4/g, 'ô')
.replace(/=C3=B9/g, 'ù')
.replace(/=C3=BB/g, 'û')
.trim();
// Take first 100 characters
preview = preview.substring(0, 100);
// Try to end at a complete word
if (preview.length === 100) {
const lastSpace = preview.lastIndexOf(' ');
if (lastSpace > 80) {
preview = preview.substring(0, lastSpace);
}
preview += '...';
}
return preview || 'No preview available';
} catch (e) {
console.error('Error generating preview:', e);
return 'Error loading preview';
}
})()}
</div>
</div>
</div>
);
);
};
const generateEmailPreview = (email: Email): string => {
console.log('=== generateEmailPreview Debug ===');
console.log('Email ID:', email.id);
console.log('Subject:', email.subject);
console.log('Body length:', email.body.length);
console.log('First 200 chars of body:', email.body.substring(0, 200));
try {
const parsed = parseFullEmail(email.body);
console.log('Parsed content:', {
hasText: 'text' in parsed ? !!parsed.text : false,
hasHtml: 'html' in parsed ? !!parsed.html : false,
textPreview: 'text' in parsed ? parsed.text?.substring(0, 100) : 'No text',
htmlPreview: 'html' in parsed ? parsed.html?.substring(0, 100) : 'No HTML'
});
// ... rest of the function ...
} catch (e) {
console.error('Error in generateEmailPreview:', e);
return 'Error generating preview';
}
};
// Render the sidebar navigation
const renderSidebarNav = () => (