Neah/components/email/EmailPanel.tsx

211 lines
5.6 KiB
TypeScript

'use client';
import { useState, useEffect, useMemo, useCallback } from 'react';
import EmailPreview from './EmailPreview';
import ComposeEmail from './ComposeEmail';
import { Loader2 } from 'lucide-react';
import { formatReplyEmail, EmailMessage as FormatterEmailMessage } from '@/lib/utils/email-formatter';
import { useEmailFetch } from '@/hooks/use-email-fetch';
import { debounce } from '@/lib/utils/debounce';
import { formatEmailContent } from '@/lib/utils/email-content';
// Add local EmailMessage interface
interface EmailAddress {
name: string;
address: string;
}
interface EmailMessage {
id: string;
messageId?: string;
subject: string;
from: EmailAddress[];
to: EmailAddress[];
cc?: EmailAddress[];
bcc?: EmailAddress[];
date: Date | string;
flags?: {
seen: boolean;
flagged: boolean;
answered: boolean;
deleted: boolean;
draft: boolean;
};
preview?: string;
content?: string;
html?: string;
text?: string;
hasAttachments?: boolean;
attachments?: any[];
folder?: string;
size?: number;
contentFetched?: boolean;
}
interface EmailPanelProps {
selectedEmail: {
emailId: string;
accountId: string;
folder: string;
} | null;
onSendEmail: (email: any) => void;
}
export default function EmailPanel({
selectedEmail,
onSendEmail
}: EmailPanelProps) {
// Use the new email fetch hook
const { email, loading, error, fetchEmail } = useEmailFetch({
onEmailLoaded: (email) => {
// Handle any post-load actions
console.log('Email loaded:', email.id);
},
onError: (error) => {
console.error('Error loading email:', error);
}
});
// Compose mode state
const [isComposing, setIsComposing] = useState<boolean>(false);
const [composeType, setComposeType] = useState<'new' | 'reply' | 'reply-all' | 'forward'>('new');
// Format the email content
const formattedEmail = useMemo(() => {
if (!email) {
console.log('EmailPanel: No email provided');
return null;
}
console.log('EmailPanel: Raw email:', email);
// If content is already an object with html/text, use it directly
if (email.content && typeof email.content === 'object') {
console.log('EmailPanel: Using existing content object');
return {
...email,
content: email.content.html || email.content.text || '',
html: email.content.html || email.html || '',
text: email.content.text || email.text || ''
};
}
// If content is a string, format it
if (typeof email.content === 'string') {
console.log('EmailPanel: Using direct string content');
return {
...email,
content: email.content,
html: email.html || email.content,
text: email.text || email.content
};
}
// Fallback to html/text properties
console.log('EmailPanel: Using html/text properties');
return {
...email,
content: email.html || email.text || '',
html: email.html || '',
text: email.text || ''
};
}, [email]);
// Debounced email fetch
const debouncedFetchEmail = useCallback(
debounce((emailId: string, accountId: string, folder: string) => {
fetchEmail(emailId, accountId, folder);
}, 300),
[fetchEmail]
);
// Load email content when selectedEmail changes
useEffect(() => {
if (selectedEmail) {
debouncedFetchEmail(selectedEmail.emailId, selectedEmail.accountId, selectedEmail.folder);
setIsComposing(false);
}
}, [selectedEmail, debouncedFetchEmail]);
// Handle reply/forward actions
const handleReply = (type: 'reply' | 'reply-all' | 'forward') => {
setComposeType(type);
setIsComposing(true);
};
// Handle compose mode close
const handleComposeClose = () => {
setIsComposing(false);
setComposeType('new');
};
// If no email is selected and not composing
if (!selectedEmail && !isComposing) {
return (
<div className="h-full flex items-center justify-center">
<div className="text-center text-muted-foreground">
<p>Select an email to view or</p>
<button
className="text-primary mt-2 hover:underline"
onClick={() => {
setComposeType('new');
setIsComposing(true);
}}
>
Compose a new message
</button>
</div>
</div>
);
}
// Show loading state
if (loading) {
return (
<div className="h-full flex items-center justify-center">
<div className="text-center">
<Loader2 className="h-8 w-8 animate-spin mx-auto mb-4 text-primary" />
<p>Loading email...</p>
</div>
</div>
);
}
// Show error state
if (error) {
return (
<div className="h-full flex items-center justify-center">
<div className="text-center text-destructive">
<p>{error}</p>
<button
className="text-primary mt-2 hover:underline"
onClick={() => selectedEmail && fetchEmail(selectedEmail.emailId, selectedEmail.accountId, selectedEmail.folder)}
>
Try again
</button>
</div>
</div>
);
}
// Show compose mode or email preview
return (
<div className="h-full">
{isComposing ? (
<ComposeEmail
initialEmail={formattedEmail}
type={composeType}
onClose={handleComposeClose}
onSend={onSendEmail}
/>
) : (
<div className="max-w-4xl mx-auto h-full">
<EmailPreview
email={formattedEmail}
onReply={handleReply}
/>
</div>
)}
</div>
);
}