'use client'; import { useState, useRef, useEffect } from 'react'; import { X, Paperclip, SendHorizontal, Loader2, Plus, ChevronDown } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { sanitizeHtml } from '@/lib/utils/dom-sanitizer'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import RichTextEditor from '@/components/ui/rich-text-editor'; import { detectTextDirection } from '@/lib/utils/text-direction'; // Import from the centralized utils import { formatReplyEmail, formatForwardedEmail } from '@/lib/utils/email-utils'; import { EmailMessage } from '@/types/email'; /** * Email composer component * Handles new emails, replies, and forwards with a clean UI */ interface ComposeEmailProps { initialEmail?: EmailMessage | null; type?: 'new' | 'reply' | 'reply-all' | 'forward'; onClose: () => void; onSend: (emailData: { to: string; cc?: string; bcc?: string; subject: string; body: string; fromAccount?: string; attachments?: Array<{ name: string; content: string; type: string; }>; }) => Promise; accounts?: Array<{ id: string; email: string; display_name?: string; }>; } export default function ComposeEmail(props: ComposeEmailProps) { const { initialEmail, type = 'new', onClose, onSend, accounts = [] } = props; // Email form state const [to, setTo] = useState(''); const [cc, setCc] = useState(''); const [bcc, setBcc] = useState(''); const [subject, setSubject] = useState(''); const [emailContent, setEmailContent] = useState(''); const [showCc, setShowCc] = useState(false); const [showBcc, setShowBcc] = useState(false); const [sending, setSending] = useState(false); const [selectedAccount, setSelectedAccount] = useState<{ id: string; email: string; display_name?: string; } | null>(accounts.length > 0 ? accounts[0] : null); const [attachments, setAttachments] = useState>([]); const editorRef = useRef(null); // Initialize the form when replying to or forwarding an email useEffect(() => { if (initialEmail && type !== 'new') { try { // Set recipients based on type if (type === 'reply' || type === 'reply-all') { // Get formatted data for reply const formatted = formatReplyEmail(initialEmail, type); // Set the recipients setTo(formatted.to); if (formatted.cc) { setCc(formatted.cc); setShowCc(true); } // Set subject setSubject(formatted.subject); // Set content with original email const content = formatted.content.html || formatted.content.text; setEmailContent(content); } else if (type === 'forward') { // Get formatted data for forward const formatted = formatForwardedEmail(initialEmail); // Set subject setSubject(formatted.subject); // Set content with original email const content = formatted.content.html || formatted.content.text; setEmailContent(content); // If the original email has attachments, include them if (initialEmail.attachments && initialEmail.attachments.length > 0) { const formattedAttachments = initialEmail.attachments.map(att => ({ name: att.filename || 'attachment', type: att.contentType || 'application/octet-stream', content: att.content || '' })); setAttachments(formattedAttachments); } } } catch (error) { console.error('Error initializing compose form:', error); } } }, [initialEmail, type]); // Place cursor at beginning and ensure content is scrolled to top useEffect(() => { if (editorRef.current && type !== 'new') { // Small delay to ensure DOM is ready setTimeout(() => { if (editorRef.current) { // Focus the editor editorRef.current.focus(); // Put cursor at the beginning const selection = window.getSelection(); const range = document.createRange(); range.setStart(editorRef.current, 0); range.collapse(true); selection?.removeAllRanges(); selection?.addRange(range); // Also make sure editor container is scrolled to top editorRef.current.scrollTop = 0; // Find parent scrollable containers and scroll them to top let parent = editorRef.current.parentElement; while (parent) { if (parent.classList.contains('overflow-y-auto')) { parent.scrollTop = 0; } parent = parent.parentElement; } } }, 100); } }, [emailContent, type]); // Handle file attachments const handleAttachmentAdd = async (files: FileList) => { const newAttachments = Array.from(files).map(file => ({ name: file.name, type: file.type, content: URL.createObjectURL(file) })); setAttachments(prev => [...prev, ...newAttachments]); }; const handleAttachmentRemove = (index: number) => { setAttachments(prev => prev.filter((_, i) => i !== index)); }; // Handle sending email const handleSend = async () => { if (!to) { alert('Please specify at least one recipient'); return; } setSending(true); try { await onSend({ to, cc: cc || undefined, bcc: bcc || undefined, subject, body: emailContent, fromAccount: selectedAccount?.id, attachments }); // Reset form and close onClose(); } catch (error) { console.error('Error sending email:', error); alert('Failed to send email. Please try again.'); } finally { setSending(false); } }; // Get compose title based on type const getComposeTitle = () => { switch(type) { case 'reply': return 'Reply'; case 'reply-all': return 'Reply All'; case 'forward': return 'Forward'; default: return 'New Message'; } }; return (
{/* Header */}

{getComposeTitle()}

{/* Email Form */}
{/* From */}
From: Select account {accounts.length > 0 ? ( accounts.map(account => ( setSelectedAccount(account)} className="cursor-pointer" > {account.display_name ? `${account.display_name} <${account.email}>` : account.email} )) ) : ( No accounts available )}
{/* Recipients */}
To: setTo(e.target.value)} placeholder="recipient@example.com" className="flex-1 border-0 shadow-none focus-visible:ring-0 px-0 h-8 bg-white text-gray-800" />
{showCc && (
Cc: setCc(e.target.value)} placeholder="cc@example.com" className="flex-1 border-0 shadow-none focus-visible:ring-0 px-0 h-8 bg-white text-gray-800" />
)} {showBcc && (
Bcc: setBcc(e.target.value)} placeholder="bcc@example.com" className="flex-1 border-0 shadow-none focus-visible:ring-0 px-0 h-8 bg-white text-gray-800" />
)} {/* CC/BCC Toggle Links */}
{!showCc && ( )} {!showBcc && ( )}
{/* Subject */}
Subject: setSubject(e.target.value)} placeholder="Subject" className="flex-1 border-0 shadow-none focus-visible:ring-0 px-0 h-8 bg-white text-gray-800" />
{/* Message Body */} { // Store the content setEmailContent(html); // But don't update direction on every keystroke // The RichTextEditor will handle direction changes internally }} className="min-h-[320px] border rounded-md bg-white text-gray-800 flex-1" placeholder="Write your message here..." /> {/* Attachments */} {attachments.length > 0 && (
Attachments:
{attachments.map((file, index) => (
{file.name}
))}
)}
{/* Footer */}
{/* File Input for Attachments */} { if (e.target.files && e.target.files.length > 0) { handleAttachmentAdd(e.target.files); } }} />
{/* Styles for email content */}
); }