courrier preview

This commit is contained in:
alma 2025-04-30 22:25:48 +02:00
parent 9cde8ac9d0
commit a82fb22b93
4 changed files with 203 additions and 39 deletions

View File

@ -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({
)}
</div>
);
}
// 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);
}

View File

@ -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 <email@example.com>)
const senderInfo = standardizedEmail.from.match(/^(?:"?([^"]*)"?\s)?<?([^\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>]+@[^\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;

View File

@ -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 <email@example.com>"
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 <email@example.com>"
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 [];
}

View File

@ -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 '';
}
/**