courrier preview
This commit is contained in:
parent
a82fb22b93
commit
748d0bbff4
@ -5,7 +5,7 @@ import { renderEmailContent } from '@/lib/utils/email-utils';
|
||||
import { EmailContent } from '@/types/email';
|
||||
|
||||
interface EmailContentDisplayProps {
|
||||
content: EmailContent | any;
|
||||
content: EmailContent;
|
||||
className?: string;
|
||||
showQuotedText?: boolean;
|
||||
type?: 'html' | 'text' | 'auto';
|
||||
@ -23,81 +23,26 @@ const EmailContentDisplay: React.FC<EmailContentDisplayProps> = ({
|
||||
type = 'auto',
|
||||
debug = false
|
||||
}) => {
|
||||
// Normalize the content to our standard format if needed
|
||||
const normalizedContent = useMemo(() => {
|
||||
try {
|
||||
// Handle different input types
|
||||
if (!content) {
|
||||
return {
|
||||
html: undefined,
|
||||
text: 'No content available',
|
||||
isHtml: false,
|
||||
direction: 'ltr'
|
||||
} as EmailContent;
|
||||
}
|
||||
|
||||
// If content is already in our EmailContent format
|
||||
if (content &&
|
||||
typeof content === 'object' &&
|
||||
'text' in content &&
|
||||
'isHtml' in content) {
|
||||
return content as EmailContent;
|
||||
}
|
||||
|
||||
// Special case for email message with content property
|
||||
if (content && typeof content === 'object' && content.content &&
|
||||
typeof content.content === 'object' &&
|
||||
'text' in content.content &&
|
||||
'isHtml' in content.content) {
|
||||
return content.content as EmailContent;
|
||||
}
|
||||
|
||||
// Special case for simple string content
|
||||
if (typeof content === 'string') {
|
||||
return {
|
||||
text: content,
|
||||
isHtml: content.trim().startsWith('<'),
|
||||
direction: 'ltr'
|
||||
} as EmailContent;
|
||||
}
|
||||
|
||||
// For HTML/text properties
|
||||
if (content && typeof content === 'object') {
|
||||
if (content.html || content.text) {
|
||||
return {
|
||||
html: content.html,
|
||||
text: content.text || '',
|
||||
isHtml: !!content.html,
|
||||
direction: 'ltr'
|
||||
} as EmailContent;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback
|
||||
console.warn('EmailContentDisplay: Unable to properly normalize content format');
|
||||
return {
|
||||
text: 'Content format not supported',
|
||||
isHtml: false,
|
||||
direction: 'ltr'
|
||||
} as EmailContent;
|
||||
} catch (error) {
|
||||
console.error('Error normalizing content in EmailContentDisplay:', error);
|
||||
// Ensure we have valid content to work with
|
||||
const safeContent = useMemo(() => {
|
||||
if (!content) {
|
||||
return {
|
||||
html: undefined,
|
||||
text: `Error processing email content: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
||||
text: 'No content available',
|
||||
isHtml: false,
|
||||
direction: 'ltr'
|
||||
} as EmailContent;
|
||||
}
|
||||
return content;
|
||||
}, [content]);
|
||||
|
||||
// Render the normalized content
|
||||
// Render the content with proper formatting
|
||||
const htmlContent = useMemo(() => {
|
||||
if (!normalizedContent) return '';
|
||||
if (!safeContent) return '';
|
||||
|
||||
try {
|
||||
// Override content type if specified
|
||||
let contentToRender: EmailContent = { ...normalizedContent };
|
||||
let contentToRender: EmailContent = { ...safeContent };
|
||||
|
||||
if (type === 'html' && !contentToRender.isHtml) {
|
||||
// Force HTML rendering for text content
|
||||
@ -116,10 +61,10 @@ const EmailContentDisplay: React.FC<EmailContentDisplayProps> = ({
|
||||
|
||||
return renderEmailContent(contentToRender);
|
||||
} catch (error) {
|
||||
console.error('Error rendering content in EmailContentDisplay:', error);
|
||||
console.error('Error rendering content:', error);
|
||||
return `<div class="error-message p-4 text-red-500">Error rendering email content: ${error instanceof Error ? error.message : 'Unknown error'}</div>`;
|
||||
}
|
||||
}, [normalizedContent, type]);
|
||||
}, [safeContent, type]);
|
||||
|
||||
// Apply quoted text styling if needed
|
||||
const containerStyle: CSSProperties = showQuotedText
|
||||
@ -139,14 +84,10 @@ const EmailContentDisplay: React.FC<EmailContentDisplayProps> = ({
|
||||
{/* Debug output if enabled */}
|
||||
{debug && (
|
||||
<div className="content-debug mt-4 p-2 text-xs bg-gray-100 border rounded">
|
||||
<p><strong>Content Type:</strong> {typeof content}</p>
|
||||
{typeof content === 'object' && (
|
||||
<p><strong>Keys:</strong> {Object.keys(content).join(', ')}</p>
|
||||
)}
|
||||
<p><strong>Normalized:</strong> {normalizedContent?.isHtml ? 'HTML' : 'Text'}</p>
|
||||
<p><strong>Direction:</strong> {normalizedContent?.direction}</p>
|
||||
<p><strong>Has HTML:</strong> {!!normalizedContent?.html}</p>
|
||||
<p><strong>Text Length:</strong> {normalizedContent?.text?.length || 0}</p>
|
||||
<p><strong>Content Type:</strong> {safeContent.isHtml ? 'HTML' : 'Text'}</p>
|
||||
<p><strong>Direction:</strong> {safeContent.direction}</p>
|
||||
<p><strong>Has HTML:</strong> {!!safeContent.html}</p>
|
||||
<p><strong>Text Length:</strong> {safeContent.text?.length || 0}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@ -59,73 +59,11 @@ export default function EmailPanel({
|
||||
// Convert the email to the standardized format
|
||||
const standardizedEmail = useMemo(() => {
|
||||
if (!email) {
|
||||
console.log('EmailPanel: No email provided');
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log('EmailPanel: Raw email:', email);
|
||||
console.log('EmailPanel: Raw email content type:', typeof email.content);
|
||||
|
||||
if (email.content) {
|
||||
// Log detailed content structure for debugging
|
||||
if (typeof email.content === 'object') {
|
||||
console.log('EmailPanel: Content object keys:', Object.keys(email.content));
|
||||
console.log('EmailPanel: Content has isHtml?', 'isHtml' in email.content);
|
||||
console.log('EmailPanel: Content has text?', 'text' in email.content);
|
||||
console.log('EmailPanel: Content has direction?', 'direction' in email.content);
|
||||
} else if (typeof email.content === 'string') {
|
||||
console.log('EmailPanel: Content is string, first 100 chars:', email.content.substring(0, 100));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Check if it's already in standardized format
|
||||
if (email.content &&
|
||||
typeof email.content === 'object' &&
|
||||
'isHtml' in email.content &&
|
||||
'text' in email.content &&
|
||||
'direction' in email.content) {
|
||||
console.log('EmailPanel: Email already in standardized format');
|
||||
|
||||
// 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
|
||||
console.log('EmailPanel: Adapting email to standardized format');
|
||||
const adapted = adaptLegacyEmail(email);
|
||||
|
||||
// Log adapted email for debugging
|
||||
console.log('EmailPanel: Adapted email content:', adapted.content);
|
||||
|
||||
return adapted;
|
||||
} catch (error) {
|
||||
console.error('EmailPanel: Error adapting email:', error);
|
||||
// If adaptation fails, create a minimal valid email for display
|
||||
return {
|
||||
id: email.id || 'unknown',
|
||||
subject: email.subject || 'Error displaying email',
|
||||
from: normalizeAddress(email.from) || '',
|
||||
to: normalizeAddress(email.to) || '',
|
||||
date: email.date || new Date().toISOString(),
|
||||
flags: [],
|
||||
content: {
|
||||
text: `Error processing email: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
||||
html: undefined,
|
||||
isHtml: false,
|
||||
direction: 'ltr'
|
||||
}
|
||||
} as EmailMessage;
|
||||
}
|
||||
// The useEmailFetch hook now provides fully formatted email
|
||||
return email;
|
||||
}, [email]);
|
||||
|
||||
// Debounced email fetch
|
||||
|
||||
@ -1,118 +1,24 @@
|
||||
'use client';
|
||||
|
||||
import { useRef, useMemo } from 'react';
|
||||
import { useRef } from 'react';
|
||||
import { Loader2 } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||
import { Avatar, AvatarFallback } from '@/components/ui/avatar';
|
||||
import { Card } from '@/components/ui/card';
|
||||
import { EmailMessage, EmailAddress } from '@/types/email';
|
||||
import { formatEmailAddresses, formatEmailDate } from '@/lib/utils/email-utils';
|
||||
import { adaptLegacyEmail } from '@/lib/utils/email-adapters';
|
||||
import { EmailMessage } from '@/types/email';
|
||||
import { formatEmailDate } from '@/lib/utils/email-utils';
|
||||
import EmailContentDisplay from './EmailContentDisplay';
|
||||
|
||||
interface EmailPreviewProps {
|
||||
email: EmailMessage | any;
|
||||
email: EmailMessage | null;
|
||||
loading?: boolean;
|
||||
onReply?: (type: 'reply' | 'reply-all' | 'forward') => void;
|
||||
}
|
||||
|
||||
export default function EmailPreview({ email, loading = false, onReply }: EmailPreviewProps) {
|
||||
// Add editorRef to match ComposeEmail exactly
|
||||
const editorRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Convert legacy email to standardized format if needed
|
||||
const standardizedEmail = useMemo(() => {
|
||||
if (!email) return null;
|
||||
|
||||
try {
|
||||
// Log input email details for debugging
|
||||
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') {
|
||||
console.log('EmailPreview: Content properties:', Object.keys(email.content));
|
||||
} else {
|
||||
console.log('EmailPreview: Content first 100 chars:', email.content.substring(0, 100));
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the email is already in the standardized format
|
||||
if (
|
||||
email.content &&
|
||||
typeof email.content === 'object' &&
|
||||
'isHtml' in email.content &&
|
||||
'text' in email.content
|
||||
) {
|
||||
console.log('EmailPreview: Email is already in standardized format');
|
||||
return email as EmailMessage;
|
||||
}
|
||||
|
||||
// Otherwise, adapt it
|
||||
console.log('EmailPreview: Adapting legacy email format');
|
||||
const adapted = adaptLegacyEmail(email);
|
||||
|
||||
// Log the adapted email structure for debugging
|
||||
console.log('EmailPreview: Adapted email:', {
|
||||
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,
|
||||
textLength: adapted.content.text?.length,
|
||||
htmlExists: !!adapted.content.html
|
||||
} : 'No content'
|
||||
});
|
||||
|
||||
return adapted;
|
||||
} catch (error) {
|
||||
console.error('Error adapting email:', error);
|
||||
// Instead of returning null, try to create a minimal valid email to display the error
|
||||
return {
|
||||
id: email?.id || 'error',
|
||||
subject: email?.subject || 'Error processing email',
|
||||
from: email?.from || '',
|
||||
to: email?.to || '',
|
||||
date: email?.date || new Date().toISOString(),
|
||||
flags: [],
|
||||
content: {
|
||||
text: `Error processing email: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
||||
isHtml: false,
|
||||
direction: 'ltr'
|
||||
}
|
||||
} as EmailMessage;
|
||||
}
|
||||
}, [email]);
|
||||
|
||||
// Get sender initials for avatar
|
||||
const getSenderInitials = (name: string) => {
|
||||
if (!name) return '';
|
||||
return name
|
||||
.split(" ")
|
||||
.map((n) => n?.[0] || '')
|
||||
.join("")
|
||||
.toUpperCase()
|
||||
.slice(0, 2);
|
||||
};
|
||||
|
||||
// Display loading state
|
||||
if (loading) {
|
||||
return (
|
||||
@ -126,7 +32,7 @@ export default function EmailPreview({ email, loading = false, onReply }: EmailP
|
||||
}
|
||||
|
||||
// No email selected
|
||||
if (!standardizedEmail) {
|
||||
if (!email) {
|
||||
return (
|
||||
<div className="flex items-center justify-center h-full p-6">
|
||||
<div className="text-center text-muted-foreground">
|
||||
@ -136,45 +42,37 @@ 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 various possible formats - handle both string and array formats
|
||||
// Extract sender name from email.from (which is a string in our standardized format)
|
||||
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;
|
||||
}
|
||||
if (email.from) {
|
||||
// If it's a string, try to extract name and email with regex
|
||||
const senderInfo = email.from.match(/^(?:"?([^"]*)"?\s)?<?([^\s>]+@[^\s>]+)>?$/);
|
||||
senderName = senderInfo ? senderInfo[1] || senderInfo[2] : email.from;
|
||||
senderEmail = senderInfo ? senderInfo[2] : email.from;
|
||||
}
|
||||
|
||||
// Check for attachments
|
||||
const hasAttachments = standardizedEmail.attachments && standardizedEmail.attachments.length > 0;
|
||||
const hasAttachments = email.attachments && email.attachments.length > 0;
|
||||
|
||||
// Get sender initials for avatar
|
||||
const getSenderInitials = (name: string) => {
|
||||
if (!name) return '';
|
||||
return name
|
||||
.split(" ")
|
||||
.map((n) => n?.[0] || '')
|
||||
.join("")
|
||||
.toUpperCase()
|
||||
.slice(0, 2);
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className="flex flex-col h-full overflow-hidden border-0 shadow-none">
|
||||
{/* Email header */}
|
||||
<div className="p-6 border-b">
|
||||
<div className="mb-4">
|
||||
<h2 className="text-xl font-semibold mb-4">{standardizedEmail.subject}</h2>
|
||||
<h2 className="text-xl font-semibold mb-4">{email.subject}</h2>
|
||||
|
||||
<div className="flex items-start gap-3 mb-4">
|
||||
<Avatar className="h-10 w-10">
|
||||
@ -184,16 +82,16 @@ export default function EmailPreview({ email, loading = false, onReply }: EmailP
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="font-medium">{senderName}</div>
|
||||
<span className="text-sm text-muted-foreground">{formatEmailDate(standardizedEmail.date)}</span>
|
||||
<span className="text-sm text-muted-foreground">{formatEmailDate(email.date)}</span>
|
||||
</div>
|
||||
|
||||
<div className="text-sm text-muted-foreground truncate mt-1">
|
||||
To: {standardizedEmail.to}
|
||||
To: {email.to}
|
||||
</div>
|
||||
|
||||
{standardizedEmail.cc && (
|
||||
{email.cc && (
|
||||
<div className="text-sm text-muted-foreground truncate mt-1">
|
||||
Cc: {standardizedEmail.cc}
|
||||
Cc: {email.cc}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -228,11 +126,11 @@ export default function EmailPreview({ email, loading = false, onReply }: EmailP
|
||||
</div>
|
||||
|
||||
{/* Attachments list */}
|
||||
{hasAttachments && standardizedEmail.attachments && (
|
||||
{hasAttachments && email.attachments && (
|
||||
<div className="px-6 py-3 border-b bg-muted/20">
|
||||
<h3 className="text-sm font-medium mb-2">Attachments ({standardizedEmail.attachments.length})</h3>
|
||||
<h3 className="text-sm font-medium mb-2">Attachments ({email.attachments.length})</h3>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{standardizedEmail.attachments.map((attachment, index) => (
|
||||
{email.attachments.map((attachment, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex items-center gap-2 bg-background rounded-md px-3 py-1.5 text-sm border"
|
||||
@ -251,7 +149,6 @@ export default function EmailPreview({ email, loading = false, onReply }: EmailP
|
||||
{/* Email body */}
|
||||
<ScrollArea className="flex-1">
|
||||
<div className="p-6">
|
||||
{/* Render the email content using the new standardized component */}
|
||||
<div
|
||||
ref={editorRef}
|
||||
className="email-content-container rounded-lg overflow-hidden bg-white shadow-sm"
|
||||
@ -261,38 +158,25 @@ export default function EmailPreview({ email, loading = false, onReply }: EmailP
|
||||
}}
|
||||
>
|
||||
<EmailContentDisplay
|
||||
content={standardizedEmail.content}
|
||||
content={email.content}
|
||||
type="auto"
|
||||
className="p-6"
|
||||
debug={process.env.NODE_ENV === 'development'}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Always show debugging info in development mode */}
|
||||
{/* Debugging info - simplified */}
|
||||
{process.env.NODE_ENV === 'development' && (
|
||||
<details className="mt-4 text-xs text-muted-foreground border rounded-md p-2" open>
|
||||
<details className="mt-4 text-xs text-muted-foreground border rounded-md p-2">
|
||||
<summary className="cursor-pointer">Email Debug Info</summary>
|
||||
<div className="mt-2 overflow-auto max-h-80 p-2 bg-gray-50 rounded">
|
||||
<p><strong>Email ID:</strong> {standardizedEmail.id}</p>
|
||||
<p><strong>Content Type:</strong> {standardizedEmail.content.isHtml ? 'HTML' : 'Plain Text'}</p>
|
||||
<p><strong>Text Direction:</strong> {standardizedEmail.content.direction || 'ltr'}</p>
|
||||
<p><strong>Email ID:</strong> {email.id}</p>
|
||||
<p><strong>Content Type:</strong> {email.content.isHtml ? 'HTML' : 'Plain Text'}</p>
|
||||
<p><strong>Text Direction:</strong> {email.content.direction}</p>
|
||||
<p><strong>Content Size:</strong>
|
||||
HTML: {standardizedEmail.content.html?.length || 0} chars,
|
||||
Text: {standardizedEmail.content.text?.length || 0} chars
|
||||
HTML: {email.content.html?.length || 0} chars,
|
||||
Text: {email.content.text?.length || 0} chars
|
||||
</p>
|
||||
<p><strong>Content Structure:</strong> {JSON.stringify(standardizedEmail.content, null, 2)}</p>
|
||||
<hr className="my-2" />
|
||||
<p><strong>Original Email Type:</strong> {typeof email}</p>
|
||||
<p><strong>Original Content Type:</strong> {typeof email.content}</p>
|
||||
{email && typeof email.content === 'object' && (
|
||||
<p><strong>Original Content Keys:</strong> {Object.keys(email.content).join(', ')}</p>
|
||||
)}
|
||||
{email && email.html && (
|
||||
<p><strong>Has HTML property:</strong> {email.html.length} chars</p>
|
||||
)}
|
||||
{email && email.text && (
|
||||
<p><strong>Has Text property:</strong> {email.text.length} chars</p>
|
||||
)}
|
||||
</div>
|
||||
</details>
|
||||
)}
|
||||
|
||||
@ -1,14 +1,15 @@
|
||||
import { useState, useEffect, useCallback, useRef } from 'react';
|
||||
import { useToast } from './use-toast';
|
||||
import { EmailMessage, EmailContent } from '@/types/email';
|
||||
|
||||
interface EmailFetchState {
|
||||
email: any | null;
|
||||
email: EmailMessage | null;
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
}
|
||||
|
||||
interface UseEmailFetchProps {
|
||||
onEmailLoaded?: (email: any) => void;
|
||||
onEmailLoaded?: (email: EmailMessage) => void;
|
||||
onError?: (error: string) => void;
|
||||
}
|
||||
|
||||
@ -49,20 +50,15 @@ export function useEmailFetch({ onEmailLoaded, onError }: UseEmailFetchProps = {
|
||||
return;
|
||||
}
|
||||
|
||||
// CRITICAL FIX: Always abort any previous request when fetching a new email
|
||||
// This prevents race conditions when switching accounts or folders
|
||||
// Abort any previous request
|
||||
if (abortControllerRef.current) {
|
||||
console.log(`useEmailFetch: Aborting previous request to fetch email ${emailId} from account ${accountId}`);
|
||||
abortControllerRef.current.abort();
|
||||
}
|
||||
|
||||
// Create a new abort controller for this request
|
||||
abortControllerRef.current = new AbortController();
|
||||
|
||||
setState(prev => ({ ...prev, loading: true, error: null }));
|
||||
|
||||
try {
|
||||
console.log('useEmailFetch: Fetching email with params:', { emailId, accountId, folder });
|
||||
const response = await fetch(
|
||||
`/api/courrier/${emailId}?accountId=${encodeURIComponent(accountId)}&folder=${encodeURIComponent(folder)}`,
|
||||
{
|
||||
@ -75,24 +71,24 @@ export function useEmailFetch({ onEmailLoaded, onError }: UseEmailFetchProps = {
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log('useEmailFetch: Raw API response:', JSON.stringify(data, null, 2));
|
||||
|
||||
// Use the data directly as it already has the standardized format from the server
|
||||
const transformedEmail = data;
|
||||
|
||||
console.log('useEmailFetch: Email from API ready to use:', JSON.stringify({
|
||||
id: transformedEmail.id,
|
||||
subject: transformedEmail.subject,
|
||||
contentType: typeof transformedEmail.content,
|
||||
hasIsHtml: transformedEmail.content && 'isHtml' in transformedEmail.content,
|
||||
hasDirection: transformedEmail.content && 'direction' in transformedEmail.content
|
||||
}, null, 2));
|
||||
// Create properly formatted email with all required fields
|
||||
const transformedEmail: EmailMessage = {
|
||||
...data,
|
||||
// Ensure content is properly formatted
|
||||
content: {
|
||||
text: data.content?.text || '',
|
||||
html: data.content?.html || undefined,
|
||||
isHtml: data.content?.html ? true : false,
|
||||
direction: data.content?.direction || 'ltr'
|
||||
}
|
||||
};
|
||||
|
||||
setState({ email: transformedEmail, loading: false, error: null });
|
||||
onEmailLoaded?.(transformedEmail);
|
||||
|
||||
// Mark as read if not already
|
||||
if (!transformedEmail.flags?.seen) {
|
||||
if (!transformedEmail.flags?.includes('seen')) {
|
||||
try {
|
||||
await fetch(`/api/courrier/${emailId}/mark-read`, {
|
||||
method: 'POST',
|
||||
@ -109,12 +105,11 @@ export function useEmailFetch({ onEmailLoaded, onError }: UseEmailFetchProps = {
|
||||
return;
|
||||
}
|
||||
|
||||
console.error('useEmailFetch: Error fetching email:', err);
|
||||
console.error('Error fetching email:', err);
|
||||
const errorMessage = err instanceof Error ? err.message : 'Failed to load email';
|
||||
setState(prev => ({ ...prev, loading: false, error: errorMessage }));
|
||||
onError?.(errorMessage);
|
||||
|
||||
// Show toast for user feedback
|
||||
toast({
|
||||
title: 'Error',
|
||||
description: errorMessage,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user