mail page rest
This commit is contained in:
parent
599336ed60
commit
312577bbca
@ -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(/ |‌|»|«|>/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 = () => (
|
||||
|
||||
Loading…
Reference in New Issue
Block a user