'use client'; import { useState, useRef, useEffect } from 'react'; import { X, Paperclip, ChevronDown, ChevronUp, SendHorizontal, Loader2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Textarea } from '@/components/ui/textarea'; import DOMPurify from 'isomorphic-dompurify'; import { Label } from '@/components/ui/label'; // Import sub-components import ComposeEmailHeader from './ComposeEmailHeader'; import RichEmailEditor from './RichEmailEditor'; // Import from the centralized utils import { formatReplyEmail, formatForwardedEmail, formatEmailAddresses } from '@/lib/utils/email-utils'; import { EmailMessage, EmailAddress } from '@/types/email'; /** * CENTRAL EMAIL COMPOSER COMPONENT * * This is the unified, centralized email composer component used throughout the application. * It handles new emails, replies, and forwards with proper text direction. * * All code that needs to compose emails should import this component from: * @/components/email/ComposeEmail */ // Define interface for the modern props 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; attachments?: Array<{ name: string; content: string; type: string; }>; }) => Promise; } export default function ComposeEmail(props: ComposeEmailProps) { const { initialEmail, type = 'new', onClose, onSend } = 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 [quotedContent, setQuotedContent] = useState(''); const [showCc, setShowCc] = useState(false); const [showBcc, setShowBcc] = useState(false); const [sending, setSending] = useState(false); 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 the quoted content (original email) setQuotedContent(formatted.content.html || formatted.content.text); // Start with empty content for the reply setEmailContent(''); } else if (type === 'forward') { // Get formatted data for forward const formatted = formatForwardedEmail(initialEmail); // Set subject setSubject(formatted.subject); // Set the quoted content (original email) setQuotedContent(formatted.content.html || formatted.content.text); // Start with empty content for the forward setEmailContent(''); // If the original email has attachments, we should 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]); // 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 { // Combine the new content with the quoted content const fullContent = type !== 'new' ? `${emailContent}
${quotedContent}
` : emailContent; await onSend({ to, cc: cc || undefined, bcc: bcc || undefined, subject, body: fullContent, 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); } }; // Focus and scroll to top when opened useEffect(() => { setTimeout(() => { if (editorRef.current) { editorRef.current.focus(); // Scroll to top const scrollElements = [ editorRef.current, document.querySelector('.overflow-y-auto'), document.querySelector('.compose-email-body') ]; scrollElements.forEach(el => { if (el instanceof HTMLElement) { el.scrollTop = 0; } }); } }, 100); }, []); return (
{/* To Field */}
setTo(e.target.value)} placeholder="recipient@example.com" className="w-full mt-1 bg-white border-gray-300 text-gray-900" />
{/* CC/BCC Toggle Buttons */}
{/* CC Field */} {showCc && (
setCc(e.target.value)} placeholder="cc@example.com" className="w-full mt-1 bg-white border-gray-300 text-gray-900" />
)} {/* BCC Field */} {showBcc && (
setBcc(e.target.value)} placeholder="bcc@example.com" className="w-full mt-1 bg-white border-gray-300 text-gray-900" />
)} {/* Subject Field */}
setSubject(e.target.value)} placeholder="Enter subject" className="w-full mt-1 bg-white border-gray-300 text-gray-900" />
{/* Message Body - Simplified Editor */}
{/* Simple editor for new content */}
setEmailContent(e.currentTarget.innerHTML)} /> {/* Quoted content from original email */} {quotedContent && (
)}
{/* Attachments */} {attachments.length > 0 && (

Attachments

{attachments.map((file, index) => (
{file.name}
))}
)}
{/* Modal Footer - now inside the main modal container and visually attached */}
{/* File Input for Attachments */} { if (e.target.files && e.target.files.length > 0) { handleAttachmentAdd(e.target.files); } }} /> {sending && Preparing attachment...}
{/* Styles for email display */}
); }