From a82fb22b9311d66b21659d79a3bdce0d3247249a Mon Sep 17 00:00:00 2001 From: alma Date: Wed, 30 Apr 2025 22:25:48 +0200 Subject: [PATCH] courrier preview --- components/email/EmailPanel.tsx | 54 +++++++++++++- components/email/EmailPreview.tsx | 45 ++++++++++-- lib/utils/email-adapters.ts | 113 ++++++++++++++++++++++++------ lib/utils/email-utils.ts | 30 +++++--- 4 files changed, 203 insertions(+), 39 deletions(-) diff --git a/components/email/EmailPanel.tsx b/components/email/EmailPanel.tsx index aa7e9789..40496056 100644 --- a/components/email/EmailPanel.tsx +++ b/components/email/EmailPanel.tsx @@ -86,7 +86,18 @@ export default function EmailPanel({ 'text' in email.content && 'direction' in email.content) { console.log('EmailPanel: Email already in standardized format'); - return email as EmailMessage; + + // Normalize address format before returning + const normalizedEmail = { + ...email, + // Ensure from, to, cc are strings as expected by the EmailMessage interface + from: normalizeAddress(email.from), + to: normalizeAddress(email.to), + cc: email.cc ? normalizeAddress(email.cc) : undefined, + bcc: email.bcc ? normalizeAddress(email.bcc) : undefined + }; + + return normalizedEmail as EmailMessage; } // Use the adapter utility to convert to the standardized format @@ -103,8 +114,8 @@ export default function EmailPanel({ return { id: email.id || 'unknown', subject: email.subject || 'Error displaying email', - from: email.from || '', - to: email.to || '', + from: normalizeAddress(email.from) || '', + to: normalizeAddress(email.to) || '', date: email.date || new Date().toISOString(), flags: [], content: { @@ -234,4 +245,41 @@ export default function EmailPanel({ )} ); +} + +// Helper function to normalize address to string format +function normalizeAddress(address: any): string { + if (!address) return ''; + + // If already a string, return as is + if (typeof address === 'string') { + return address; + } + + // If array of EmailAddress objects + if (Array.isArray(address)) { + return address.map(addr => { + if (typeof addr === 'object' && addr !== null) { + // Handle EmailAddress object + if ('name' in addr && 'address' in addr) { + return addr.name && addr.name !== addr.address + ? `${addr.name} <${addr.address}>` + : addr.address; + } + } + return String(addr || ''); + }).join(', '); + } + + // Handle single EmailAddress object + if (typeof address === 'object' && address !== null) { + if ('name' in address && 'address' in address) { + return address.name && address.name !== address.address + ? `${address.name} <${address.address}>` + : address.address; + } + } + + // Fallback + return String(address); } \ No newline at end of file diff --git a/components/email/EmailPreview.tsx b/components/email/EmailPreview.tsx index 920dc009..b08d7fd4 100644 --- a/components/email/EmailPreview.tsx +++ b/components/email/EmailPreview.tsx @@ -30,6 +30,19 @@ export default function EmailPreview({ email, loading = false, onReply }: EmailP console.log('EmailPreview: Input email type:', typeof email); console.log('EmailPreview: Input email properties:', Object.keys(email)); + // Check if from field is an array or string and log it + if (email.from) { + console.log('EmailPreview: From field type:', Array.isArray(email.from) ? + 'array' : typeof email.from); + + if (Array.isArray(email.from)) { + console.log('EmailPreview: From array length:', email.from.length); + if (email.from.length > 0) { + console.log('EmailPreview: First from item type:', typeof email.from[0]); + } + } + } + if (email.content) { console.log('EmailPreview: Content type:', typeof email.content); if (typeof email.content === 'object') { @@ -59,6 +72,8 @@ export default function EmailPreview({ email, loading = false, onReply }: EmailP id: adapted.id, subject: adapted.subject, from: adapted.from, + fromType: typeof adapted.from, + isFromArray: Array.isArray(adapted.from), content: adapted.content ? { isHtml: adapted.content.isHtml, direction: adapted.content.direction, @@ -124,10 +139,32 @@ export default function EmailPreview({ email, loading = false, onReply }: EmailP // Debug output for content structure console.log('EmailPreview: Standardized Email Content:', standardizedEmail.content); - // Extract sender from string (name ) - const senderInfo = standardizedEmail.from.match(/^(?:"?([^"]*)"?\s)?]+@[^\s>]+)>?$/); - const senderName = senderInfo ? senderInfo[1] || senderInfo[2] : standardizedEmail.from; - const senderEmail = senderInfo ? senderInfo[2] : standardizedEmail.from; + // Extract sender from various possible formats - handle both string and array formats + let senderName = ''; + let senderEmail = ''; + + // Handle 'from' field which might be a string or an array of EmailAddress objects + if (standardizedEmail.from) { + if (Array.isArray(standardizedEmail.from)) { + // If it's an array of EmailAddress objects + if (standardizedEmail.from.length > 0) { + const sender = standardizedEmail.from[0]; + if (typeof sender === 'object') { + senderName = sender.name || sender.address || ''; + senderEmail = sender.address || ''; + } else { + // Handle case where array contains strings + senderName = String(sender); + senderEmail = String(sender); + } + } + } else if (typeof standardizedEmail.from === 'string') { + // If it's a string, try to extract name and email with regex + const senderInfo = standardizedEmail.from.match(/^(?:"?([^"]*)"?\s)?]+@[^\s>]+)>?$/); + senderName = senderInfo ? senderInfo[1] || senderInfo[2] : standardizedEmail.from; + senderEmail = senderInfo ? senderInfo[2] : standardizedEmail.from; + } + } // Check for attachments const hasAttachments = standardizedEmail.attachments && standardizedEmail.attachments.length > 0; diff --git a/lib/utils/email-adapters.ts b/lib/utils/email-adapters.ts index 1a177a78..6ae7ecfa 100644 --- a/lib/utils/email-adapters.ts +++ b/lib/utils/email-adapters.ts @@ -13,10 +13,51 @@ export function adaptLegacyEmail(email: LegacyEmailMessage): EmailMessage { const content: EmailContent = normalizeContent(email); // Convert email addresses to string format as required by EmailMessage interface - const from = formatAddressesToString(normalizeAddresses(email.from)); - const to = formatAddressesToString(normalizeAddresses(email.to)); - const cc = email.cc ? formatAddressesToString(normalizeAddresses(email.cc)) : undefined; - const bcc = email.bcc ? formatAddressesToString(normalizeAddresses(email.bcc)) : undefined; + // Handle both array and string formats for email fields + let from: string; + let to: string; + let cc: string | undefined; + let bcc: string | undefined; + + // Handle 'from' field + if (Array.isArray(email.from)) { + from = formatAddressesToString(normalizeAddresses(email.from)); + } else if (typeof email.from === 'object' && 'address' in email.from) { + from = formatAddressesToString([email.from as EmailAddress]); + } else { + from = String(email.from || ''); + } + + // Handle 'to' field + if (Array.isArray(email.to)) { + to = formatAddressesToString(normalizeAddresses(email.to)); + } else if (typeof email.to === 'object' && 'address' in email.to) { + to = formatAddressesToString([email.to as EmailAddress]); + } else { + to = String(email.to || ''); + } + + // Handle optional 'cc' field + if (email.cc) { + if (Array.isArray(email.cc)) { + cc = formatAddressesToString(normalizeAddresses(email.cc)); + } else if (typeof email.cc === 'object' && 'address' in email.cc) { + cc = formatAddressesToString([email.cc as EmailAddress]); + } else { + cc = String(email.cc); + } + } + + // Handle optional 'bcc' field + if (email.bcc) { + if (Array.isArray(email.bcc)) { + bcc = formatAddressesToString(normalizeAddresses(email.bcc)); + } else if (typeof email.bcc === 'object' && 'address' in email.bcc) { + bcc = formatAddressesToString([email.bcc as EmailAddress]); + } else { + bcc = String(email.bcc); + } + } // Convert flags if needed const flags: string[] = normalizeFlags(email.flags); @@ -200,25 +241,7 @@ function normalizeAddresses(addresses: string | EmailAddress[] | undefined): Ema return []; } - if (Array.isArray(addresses)) { - // If already in EmailAddress format, return as is - if (addresses.length > 0 && typeof addresses[0] === 'object') { - return addresses as EmailAddress[]; - } - - // Otherwise convert string elements to EmailAddress objects - return addresses.map((addr: any) => { - if (typeof addr === 'string') { - return { - name: addr.split('@')[0] || '', - address: addr - }; - } - return addr; - }); - } - - // Handle single address as string + // Handle string if (typeof addresses === 'string') { // Check if format is "Name " const match = addresses.match(/^([^<]+)<([^>]+)>$/); @@ -229,12 +252,56 @@ function normalizeAddresses(addresses: string | EmailAddress[] | undefined): Ema }]; } + // Simple email address return [{ name: addresses.split('@')[0] || '', address: addresses }]; } + // Handle array + if (Array.isArray(addresses)) { + // If already in EmailAddress format, return as is + if (addresses.length > 0 && typeof addresses[0] === 'object' && 'address' in addresses[0]) { + return addresses as EmailAddress[]; + } + + // Otherwise convert string elements to EmailAddress objects + return addresses.map((addr: any) => { + if (typeof addr === 'string') { + // Check if format is "Name " + const match = addr.match(/^([^<]+)<([^>]+)>$/); + if (match) { + return { + name: match[1].trim(), + address: match[2].trim() + }; + } + + return { + name: addr.split('@')[0] || '', + address: addr + }; + } + + // If it's already an object with address property + if (typeof addr === 'object' && addr !== null && 'address' in addr) { + return { + name: addr.name || addr.address.split('@')[0] || '', + address: addr.address + }; + } + + // Fallback for unexpected formats + return { + name: '', + address: String(addr || '') + }; + }); + } + + // Unexpected type - return empty array + console.warn(`Unexpected addresses format: ${typeof addresses}`, addresses); return []; } diff --git a/lib/utils/email-utils.ts b/lib/utils/email-utils.ts index 81e6847d..70a3a18d 100644 --- a/lib/utils/email-utils.ts +++ b/lib/utils/email-utils.ts @@ -12,9 +12,10 @@ import DOMPurify from 'isomorphic-dompurify'; import { EmailMessage, EmailContent, - EmailAddress + EmailAddress, + LegacyEmailMessage } from '@/types/email'; -import { adaptLegacyEmail } from './email-adapters'; +import { adaptLegacyEmail } from '@/lib/utils/email-adapters'; import { decodeInfomaniakEmail, adaptMimeEmail, isMimeFormat } from './email-mime-decoder'; // Reset any existing hooks to start clean @@ -48,15 +49,26 @@ export function detectTextDirection(text: string): 'ltr' | 'rtl' { /** * Format email addresses for display + * Can handle both array of EmailAddress objects or a string */ -export function formatEmailAddresses(addresses: EmailAddress[]): string { - if (!addresses || addresses.length === 0) return ''; +export function formatEmailAddresses(addresses: EmailAddress[] | string | undefined): string { + if (!addresses) return ''; - return addresses.map(addr => - addr.name && addr.name !== addr.address - ? `${addr.name} <${addr.address}>` - : addr.address - ).join(', '); + // If already a string, return as is + if (typeof addresses === 'string') { + return addresses; + } + + // If array, format each address + if (Array.isArray(addresses) && addresses.length > 0) { + return addresses.map(addr => + addr.name && addr.name !== addr.address + ? `${addr.name} <${addr.address}>` + : addr.address + ).join(', '); + } + + return ''; } /**