courrier refactor rebuild 2

This commit is contained in:
alma 2025-04-27 10:02:33 +02:00
parent c993fe738e
commit 1c4b38ec8f
2 changed files with 653 additions and 165 deletions

View File

@ -97,6 +97,61 @@ export default function CourrierPage() {
const [showLoginNeeded, setShowLoginNeeded] = useState(false);
const [sidebarOpen, setSidebarOpen] = useState(true);
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
const [accountsDropdownOpen, setAccountsDropdownOpen] = useState(false);
const [currentView, setCurrentView] = useState('INBOX');
const [unreadCount, setUnreadCount] = useState(0);
const [loading, setLoading] = useState(false);
// Mock accounts for the sidebar
const [accounts, setAccounts] = useState<Account[]>([
{ id: 0, name: 'All', email: '', color: 'bg-gray-500' },
{ id: 1, name: 'Mail', email: 'user@example.com', color: 'bg-blue-500', folders: mailboxes }
]);
const [selectedAccount, setSelectedAccount] = useState<Account | null>(null);
// Update account folders when mailboxes change
useEffect(() => {
setAccounts(prev => {
const updated = [...prev];
if (updated[1]) {
updated[1].folders = mailboxes;
}
return updated;
});
}, [mailboxes]);
// Calculate unread count (this would be replaced with actual data in production)
useEffect(() => {
// Example: counting unread emails in the inbox
const unreadInInbox = emails.filter(email => !email.read && currentFolder === 'INBOX').length;
setUnreadCount(unreadInInbox);
}, [emails, currentFolder]);
// Helper to get folder icons
const getFolderIcon = (folder: string) => {
const folderLower = folder.toLowerCase();
if (folderLower.includes('inbox')) {
return Inbox;
} else if (folderLower.includes('sent')) {
return Send;
} else if (folderLower.includes('trash')) {
return Trash;
} else if (folderLower.includes('archive')) {
return Archive;
} else if (folderLower.includes('draft')) {
return Edit;
} else if (folderLower.includes('spam') || folderLower.includes('junk')) {
return AlertOctagon;
} else {
return Folder;
}
};
// Helper to format folder names
const formatFolderName = (folder: string) => {
return folder.charAt(0).toUpperCase() + folder.slice(1).toLowerCase();
};
// Check for more emails
const hasMoreEmails = page < totalPages;
@ -160,6 +215,12 @@ export default function CourrierPage() {
setComposeType('new');
setShowComposeModal(true);
};
// Handle mailbox change
const handleMailboxChange = (folder: string) => {
changeFolder(folder);
setCurrentView(folder);
};
// Handle sending email
const handleSendEmail = async (emailData: EmailData) => {
@ -171,6 +232,30 @@ export default function CourrierPage() {
await deleteEmails(selectedEmailIds);
setShowDeleteConfirm(false);
};
// Render sidebar navigation
const renderSidebarNav = () => (
<nav className="p-3">
<ul className="space-y-0.5 px-2">
{mailboxes.map((folder) => (
<li key={folder}>
<Button
variant={currentFolder === folder ? 'secondary' : 'ghost'}
className={`w-full justify-start py-2 ${
currentFolder === folder ? 'bg-gray-100 text-gray-900' : 'text-gray-600 hover:text-gray-900'
}`}
onClick={() => handleMailboxChange(folder)}
>
<div className="flex items-center">
{React.createElement(getFolderIcon(folder), { className: "h-4 w-4" })}
<span className="ml-2">{formatFolderName(folder)}</span>
</div>
</Button>
</li>
))}
</ul>
</nav>
);
// Check login on mount
useEffect(() => {
@ -190,10 +275,181 @@ export default function CourrierPage() {
};
return (
<div className="flex h-screen flex-col">
{/* Loading Fix for development */}
<>
<SimplifiedLoadingFix />
{/* Main layout */}
<main className="w-full h-screen bg-black">
<div className="w-full h-full px-4 pt-12 pb-4">
<div className="flex h-full bg-carnet-bg">
{/* Sidebar */}
<div className={`${sidebarOpen ? 'w-60' : 'w-16'} bg-white/95 backdrop-blur-sm border-r border-gray-100 flex flex-col transition-all duration-300 ease-in-out
${mobileSidebarOpen ? 'fixed inset-y-0 left-0 z-40' : 'hidden'} md:block`}>
{/* Courrier Title */}
<div className="p-3 border-b border-gray-100">
<div className="flex items-center gap-2">
<Mail className="h-6 w-6 text-gray-600" />
<span className="text-xl font-semibold text-gray-900">COURRIER</span>
</div>
</div>
{/* Compose button and refresh button */}
<div className="p-2 border-b border-gray-100 flex items-center gap-2">
<Button
className="flex-1 bg-blue-600 text-white rounded-lg hover:bg-blue-700 flex items-center justify-center transition-all py-1.5 text-sm"
onClick={handleComposeNew}
>
<div className="flex items-center gap-2">
<PlusIcon className="h-3.5 w-3.5" />
<span>Compose</span>
</div>
</Button>
<Button
variant="ghost"
size="icon"
className="h-9 w-9 text-gray-400 hover:text-gray-600"
onClick={() => {
setLoading(true);
loadEmails().finally(() => setLoading(false));
}}
>
<RefreshCw className={`h-4 w-4 ${loading ? 'animate-spin' : ''}`} />
</Button>
</div>
{/* Accounts Section */}
<div className="p-3 border-b border-gray-100">
<Button
variant="ghost"
className="w-full justify-between mb-2 text-sm font-medium text-gray-500"
onClick={() => setAccountsDropdownOpen(!accountsDropdownOpen)}
>
<span>Accounts</span>
{accountsDropdownOpen ? <ChevronUp className="h-4 w-4" /> : <ChevronDown className="h-4 w-4" />}
</Button>
{accountsDropdownOpen && (
<div className="space-y-1 pl-2">
{accounts.map(account => (
<div key={account.id} className="relative group">
<Button
variant="ghost"
className="w-full justify-between px-2 py-1.5 text-sm group"
onClick={() => setSelectedAccount(account)}
>
<div className="flex items-center gap-2">
<div className={`w-2.5 h-2.5 rounded-full ${account.color}`}></div>
<span className="font-medium text-gray-700">{account.name}</span>
</div>
</Button>
{/* Show folders for email accounts (not for "All" account) without the "Folders" header */}
{account.id !== 0 && (
<div className="pl-4 mt-1 mb-2 space-y-0.5 border-l border-gray-200">
{account.folders && account.folders.length > 0 ? (
account.folders.map((folder) => (
<Button
key={folder}
variant="ghost"
className={`w-full justify-start py-1 px-2 text-xs ${
currentView === folder ? 'bg-gray-100 text-gray-900' : 'text-gray-600 hover:text-gray-900'
}`}
onClick={(e) => {
e.stopPropagation();
handleMailboxChange(folder);
}}
>
<div className="flex items-center justify-between w-full gap-1.5">
<div className="flex items-center gap-1.5">
{React.createElement(getFolderIcon(folder), { className: "h-3.5 w-3.5" })}
<span className="truncate">{folder}</span>
</div>
{folder === 'INBOX' && unreadCount > 0 && (
<span className="ml-auto bg-blue-600 text-white text-xs px-1.5 py-0.5 rounded-full text-[10px]">
{unreadCount}
</span>
)}
</div>
</Button>
))
) : (
<div className="px-2 py-2">
<div className="flex flex-col space-y-2">
{/* Create placeholder folder items with shimmer effect */}
{Array.from({ length: 5 }).map((_, index) => (
<div key={index} className="flex items-center gap-1.5 animate-pulse">
<div className="h-3.5 w-3.5 bg-gray-200 rounded-sm"></div>
<div className="h-3 w-24 bg-gray-200 rounded"></div>
</div>
))}
</div>
</div>
)}
</div>
)}
</div>
))}
</div>
)}
</div>
{/* Navigation */}
{renderSidebarNav()}
</div>
{/* Email List and Content View */}
<div className="flex-1 flex overflow-hidden">
{/* Email List */}
<EmailList
emails={emails}
selectedEmailIds={selectedEmailIds}
selectedEmail={selectedEmail}
currentFolder={currentFolder}
isLoading={isLoading}
totalEmails={emails.length}
hasMoreEmails={hasMoreEmails}
onSelectEmail={handleEmailSelect}
onToggleSelect={toggleEmailSelection}
onToggleSelectAll={toggleSelectAll}
onBulkAction={handleBulkAction}
onToggleStarred={toggleStarred}
onLoadMore={handleLoadMore}
onSearch={searchEmails}
/>
{/* Email Content View */}
<div className="flex-1 bg-white/95 backdrop-blur-sm flex flex-col">
{selectedEmail ? (
<EmailDetailView
email={selectedEmail}
onBack={() => handleEmailSelect('')}
onReply={handleReply}
onReplyAll={handleReplyAll}
onForward={handleForward}
onToggleStar={() => toggleStarred(selectedEmail.id)}
/>
) : (
<div className="flex-1 flex flex-col items-center justify-center text-center p-8">
<Mail className="h-12 w-12 text-gray-300 mb-4" />
<h3 className="text-lg font-medium text-gray-900 mb-1">Select an email to read</h3>
<p className="text-sm text-gray-500 max-w-sm">
Choose an email from the list or compose a new message to get started.
</p>
<Button
className="mt-6 bg-blue-600 hover:bg-blue-700"
onClick={handleComposeNew}
>
<PlusIcon className="mr-2 h-4 w-4" />
Compose New
</Button>
</div>
)}
</div>
</div>
</div>
</div>
</main>
{/* Login needed alert */}
<LoginNeededAlert
show={showLoginNeeded}
@ -201,95 +457,17 @@ export default function CourrierPage() {
onClose={() => setShowLoginNeeded(false)}
/>
{/* Main Content */}
<div className="flex flex-1 overflow-hidden">
{/* Sidebar (Desktop) */}
{sidebarOpen && (
<aside className="hidden md:flex md:w-64 bg-gray-50 border-r border-gray-200 flex-col">
{/* Account switching and compose button */}
<div className="px-4 py-3 border-b border-gray-200">
<Button
className="w-full bg-blue-600 hover:bg-blue-700"
onClick={handleComposeNew}
>
<PlusIcon className="mr-2 h-4 w-4" />
Compose
</Button>
</div>
{/* Folder Navigation */}
<EmailSidebarContent
mailboxes={mailboxes}
currentFolder={currentFolder}
onFolderChange={changeFolder}
/>
</aside>
)}
{/* Email List and Content View */}
<div className="flex-1 flex">
{/* Email List */}
<EmailList
emails={emails}
selectedEmailIds={selectedEmailIds}
selectedEmail={selectedEmail}
currentFolder={currentFolder}
isLoading={isLoading}
totalEmails={emails.length}
hasMoreEmails={hasMoreEmails}
onSelectEmail={handleEmailSelect}
onToggleSelect={toggleEmailSelection}
onToggleSelectAll={toggleSelectAll}
onBulkAction={handleBulkAction}
onToggleStarred={toggleStarred}
onLoadMore={handleLoadMore}
onSearch={searchEmails}
/>
{/* Email Content View */}
<div className="flex-1 bg-white/95 backdrop-blur-sm flex flex-col">
{selectedEmail ? (
<EmailDetailView
email={selectedEmail}
onBack={() => handleEmailSelect('')}
onReply={handleReply}
onReplyAll={handleReplyAll}
onForward={handleForward}
onToggleStar={() => toggleStarred(selectedEmail.id)}
/>
) : (
<div className="flex-1 flex flex-col items-center justify-center text-center p-8">
<Mail className="h-12 w-12 text-gray-300 mb-4" />
<h3 className="text-lg font-medium text-gray-900 mb-1">Select an email to read</h3>
<p className="text-sm text-gray-500 max-w-sm">
Choose an email from the list or compose a new message to get started.
</p>
<Button
className="mt-6 bg-blue-600 hover:bg-blue-700"
onClick={handleComposeNew}
>
<PlusIcon className="mr-2 h-4 w-4" />
Compose New
</Button>
</div>
)}
</div>
</div>
</div>
{/* Compose Modal */}
<Dialog open={showComposeModal} onOpenChange={setShowComposeModal}>
<DialogContent className="max-w-4xl p-0">
<ComposeEmail
initialEmail={selectedEmail}
type={composeType}
onClose={() => setShowComposeModal(false)}
onSend={async (emailData: EmailData) => {
await sendEmail(emailData);
}}
/>
</DialogContent>
</Dialog>
{showComposeModal && (
<ComposeEmail
initialEmail={selectedEmail}
type={composeType}
onClose={() => setShowComposeModal(false)}
onSend={async (emailData: EmailData) => {
await sendEmail(emailData);
}}
/>
)}
{/* Delete Confirmation Dialog */}
<DeleteConfirmDialog
@ -298,6 +476,6 @@ export default function CourrierPage() {
onConfirm={handleDeleteConfirm}
onCancel={() => setShowDeleteConfirm(false)}
/>
</div>
</>
);
}

View File

@ -239,40 +239,196 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
};
return (
<Card className="w-full max-w-3xl mx-auto flex flex-col min-h-[60vh] max-h-[80vh]">
<ComposeEmailHeader
type={type}
onClose={onClose}
/>
<div className="flex-1 overflow-y-auto">
<ComposeEmailForm
to={to}
setTo={setTo}
cc={cc}
setCc={setCc}
bcc={bcc}
setBcc={setBcc}
subject={subject}
setSubject={setSubject}
emailContent={emailContent}
setEmailContent={setEmailContent}
showCc={showCc}
setShowCc={setShowCc}
showBcc={showBcc}
setShowBcc={setShowBcc}
attachments={attachments}
onAttachmentAdd={handleAttachmentAdd}
onAttachmentRemove={handleAttachmentRemove}
/>
<div className="fixed inset-0 bg-gray-600/30 backdrop-blur-sm z-50 flex items-center justify-center">
<div className="w-full max-w-2xl h-[90vh] bg-white rounded-xl shadow-xl flex flex-col mx-4">
{/* Modal Header */}
<div className="flex-none flex items-center justify-between px-6 py-3 border-b border-gray-200">
<h3 className="text-lg font-semibold text-gray-900">
{type === 'reply' ? 'Reply' : type === 'forward' ? 'Forward' : type === 'reply-all' ? 'Reply All' : 'New Message'}
</h3>
<Button
variant="ghost"
size="icon"
className="hover:bg-gray-100 rounded-full"
onClick={onClose}
>
<X className="h-5 w-5 text-gray-500" />
</Button>
</div>
{/* Modal Body */}
<div className="flex-1 overflow-hidden">
<div className="h-full flex flex-col p-6 space-y-4 overflow-y-auto">
{/* To Field */}
<div className="flex-none">
<Label htmlFor="to" className="block text-sm font-medium text-gray-700">To</Label>
<Input
id="to"
value={to}
onChange={(e) => setTo(e.target.value)}
placeholder="recipient@example.com"
className="w-full mt-1 bg-white border-gray-300 text-gray-900"
/>
</div>
{/* CC/BCC Toggle Buttons */}
<div className="flex-none flex items-center gap-4">
<button
type="button"
className="text-blue-600 hover:text-blue-700 text-sm font-medium"
onClick={() => setShowCc(!showCc)}
>
{showCc ? 'Hide Cc' : 'Add Cc'}
</button>
<button
type="button"
className="text-blue-600 hover:text-blue-700 text-sm font-medium"
onClick={() => setShowBcc(!showBcc)}
>
{showBcc ? 'Hide Bcc' : 'Add Bcc'}
</button>
</div>
{/* CC Field */}
{showCc && (
<div className="flex-none">
<Label htmlFor="cc" className="block text-sm font-medium text-gray-700">Cc</Label>
<Input
id="cc"
value={cc}
onChange={(e) => setCc(e.target.value)}
placeholder="cc@example.com"
className="w-full mt-1 bg-white border-gray-300 text-gray-900"
/>
</div>
)}
{/* BCC Field */}
{showBcc && (
<div className="flex-none">
<Label htmlFor="bcc" className="block text-sm font-medium text-gray-700">Bcc</Label>
<Input
id="bcc"
value={bcc}
onChange={(e) => setBcc(e.target.value)}
placeholder="bcc@example.com"
className="w-full mt-1 bg-white border-gray-300 text-gray-900"
/>
</div>
)}
{/* Subject Field */}
<div className="flex-none">
<Label htmlFor="subject" className="block text-sm font-medium text-gray-700">Subject</Label>
<Input
id="subject"
value={subject}
onChange={(e) => setSubject(e.target.value)}
placeholder="Enter subject"
className="w-full mt-1 bg-white border-gray-300 text-gray-900"
/>
</div>
{/* Message Body */}
<div className="flex-1 min-h-[200px] flex flex-col">
<Label htmlFor="message" className="flex-none block text-sm font-medium text-gray-700 mb-2">Message</Label>
<Textarea
value={emailContent}
onChange={(e) => setEmailContent(e.target.value)}
placeholder="Write your message here..."
className="flex-1 w-full bg-white border border-gray-300 rounded-md p-4 text-black overflow-y-auto focus:outline-none focus:ring-1 focus:ring-blue-500"
style={{
minHeight: '200px',
maxHeight: 'calc(100vh - 400px)',
resize: 'none'
}}
/>
</div>
{/* Attachments */}
{attachments.length > 0 && (
<div className="border rounded-md p-3 mt-4">
<h3 className="text-sm font-medium mb-2 text-gray-700">Attachments</h3>
<div className="space-y-2">
{attachments.map((file, index) => (
<div key={index} className="flex items-center justify-between text-sm border rounded p-2">
<span className="truncate max-w-[200px] text-gray-800">{file.name}</span>
<Button
variant="ghost"
size="sm"
onClick={() => handleAttachmentRemove(index)}
className="h-6 w-6 p-0 text-gray-500 hover:text-gray-700"
>
<X className="h-4 w-4" />
</Button>
</div>
))}
</div>
</div>
)}
</div>
</div>
{/* Modal Footer */}
<div className="flex-none flex items-center justify-between px-6 py-3 border-t border-gray-200 bg-white">
<div className="flex items-center gap-2">
{/* File Input for Attachments */}
<input
type="file"
id="file-attachment"
className="hidden"
multiple
onChange={(e) => {
if (e.target.files && e.target.files.length > 0) {
handleAttachmentAdd(e.target.files);
}
}}
/>
<label htmlFor="file-attachment">
<Button
variant="outline"
size="icon"
className="rounded-full bg-white hover:bg-gray-100 border-gray-300"
onClick={(e) => {
e.preventDefault();
document.getElementById('file-attachment')?.click();
}}
>
<Paperclip className="h-4 w-4 text-gray-600" />
</Button>
</label>
{sending && <span className="text-xs text-gray-500 ml-2">Preparing attachment...</span>}
</div>
<div className="flex items-center gap-3">
<Button
variant="ghost"
className="text-gray-600 hover:text-gray-700 hover:bg-gray-100"
onClick={onClose}
disabled={sending}
>
Cancel
</Button>
<Button
className="bg-blue-600 text-white hover:bg-blue-700"
onClick={handleSend}
disabled={sending}
>
{sending ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Sending...
</>
) : (
<>
<SendHorizontal className="mr-2 h-4 w-4" />
Send
</>
)}
</Button>
</div>
</div>
</div>
<ComposeEmailFooter
sending={sending}
onSend={handleSend}
onCancel={onClose}
/>
</Card>
</div>
);
}
@ -369,47 +525,201 @@ function LegacyAdapter({
if (!showCompose) return null;
return (
<Card className="w-full max-w-3xl mx-auto flex flex-col min-h-[60vh] max-h-[80vh]">
<ComposeEmailHeader
type={determineType()}
onClose={() => {
if (onCancel) onCancel();
setShowCompose(false);
}}
/>
<div className="flex-1 overflow-y-auto">
<ComposeEmailForm
to={composeTo}
setTo={setComposeTo}
cc={composeCc}
setCc={setComposeCc}
bcc={composeBcc}
setBcc={setComposeBcc}
subject={composeSubject}
setSubject={setComposeSubject}
emailContent={composeBody}
setEmailContent={setComposeBody}
showCc={showCc}
setShowCc={setShowCc}
showBcc={showBcc}
setShowBcc={setShowBcc}
attachments={convertAttachments()}
onAttachmentAdd={handleFileSelection}
onAttachmentRemove={(index) => {
setAttachments(attachments.filter((_, i) => i !== index));
}}
/>
<div className="fixed inset-0 bg-gray-600/30 backdrop-blur-sm z-50 flex items-center justify-center">
<div className="w-full max-w-2xl h-[90vh] bg-white rounded-xl shadow-xl flex flex-col mx-4">
{/* Modal Header */}
<div className="flex-none flex items-center justify-between px-6 py-3 border-b border-gray-200">
<h3 className="text-lg font-semibold text-gray-900">
{determineType() === 'reply' ? 'Reply' : determineType() === 'forward' ? 'Forward' : determineType() === 'reply-all' ? 'Reply All' : 'New Message'}
</h3>
<Button
variant="ghost"
size="icon"
className="hover:bg-gray-100 rounded-full"
onClick={() => {
if (onCancel) onCancel();
setShowCompose(false);
}}
>
<X className="h-5 w-5 text-gray-500" />
</Button>
</div>
{/* Modal Body */}
<div className="flex-1 overflow-hidden">
<div className="h-full flex flex-col p-6 space-y-4 overflow-y-auto">
{/* To Field */}
<div className="flex-none">
<Label htmlFor="to" className="block text-sm font-medium text-gray-700">To</Label>
<Input
id="to"
value={composeTo}
onChange={(e) => setComposeTo(e.target.value)}
placeholder="recipient@example.com"
className="w-full mt-1 bg-white border-gray-300 text-gray-900"
/>
</div>
{/* CC/BCC Toggle Buttons */}
<div className="flex-none flex items-center gap-4">
<button
type="button"
className="text-blue-600 hover:text-blue-700 text-sm font-medium"
onClick={() => setShowCc(!showCc)}
>
{showCc ? 'Hide Cc' : 'Add Cc'}
</button>
<button
type="button"
className="text-blue-600 hover:text-blue-700 text-sm font-medium"
onClick={() => setShowBcc(!showBcc)}
>
{showBcc ? 'Hide Bcc' : 'Add Bcc'}
</button>
</div>
{/* CC Field */}
{showCc && (
<div className="flex-none">
<Label htmlFor="cc" className="block text-sm font-medium text-gray-700">Cc</Label>
<Input
id="cc"
value={composeCc}
onChange={(e) => setComposeCc(e.target.value)}
placeholder="cc@example.com"
className="w-full mt-1 bg-white border-gray-300 text-gray-900"
/>
</div>
)}
{/* BCC Field */}
{showBcc && (
<div className="flex-none">
<Label htmlFor="bcc" className="block text-sm font-medium text-gray-700">Bcc</Label>
<Input
id="bcc"
value={composeBcc}
onChange={(e) => setComposeBcc(e.target.value)}
placeholder="bcc@example.com"
className="w-full mt-1 bg-white border-gray-300 text-gray-900"
/>
</div>
)}
{/* Subject Field */}
<div className="flex-none">
<Label htmlFor="subject" className="block text-sm font-medium text-gray-700">Subject</Label>
<Input
id="subject"
value={composeSubject}
onChange={(e) => setComposeSubject(e.target.value)}
placeholder="Enter subject"
className="w-full mt-1 bg-white border-gray-300 text-gray-900"
/>
</div>
{/* Message Body */}
<div className="flex-1 min-h-[200px] flex flex-col">
<Label htmlFor="message" className="flex-none block text-sm font-medium text-gray-700 mb-2">Message</Label>
<Textarea
value={composeBody}
onChange={(e) => setComposeBody(e.target.value)}
placeholder="Write your message here..."
className="flex-1 w-full bg-white border border-gray-300 rounded-md p-4 text-black overflow-y-auto focus:outline-none focus:ring-1 focus:ring-blue-500"
style={{
minHeight: '200px',
maxHeight: 'calc(100vh - 400px)',
resize: 'none'
}}
/>
</div>
{/* Attachments */}
{attachments.length > 0 && (
<div className="border rounded-md p-3 mt-4">
<h3 className="text-sm font-medium mb-2 text-gray-700">Attachments</h3>
<div className="space-y-2">
{attachments.map((file, index) => (
<div key={index} className="flex items-center justify-between text-sm border rounded p-2">
<span className="truncate max-w-[200px] text-gray-800">{file.name || file.filename}</span>
<Button
variant="ghost"
size="sm"
onClick={() => setAttachments(attachments.filter((_, i) => i !== index))}
className="h-6 w-6 p-0 text-gray-500 hover:text-gray-700"
>
<X className="h-4 w-4" />
</Button>
</div>
))}
</div>
</div>
)}
</div>
</div>
{/* Modal Footer */}
<div className="flex-none flex items-center justify-between px-6 py-3 border-t border-gray-200 bg-white">
<div className="flex items-center gap-2">
{/* File Input for Attachments */}
<input
type="file"
id="file-attachment-legacy"
className="hidden"
multiple
onChange={(e) => {
if (e.target.files && e.target.files.length > 0) {
handleFileSelection(e.target.files);
}
}}
/>
<label htmlFor="file-attachment-legacy">
<Button
variant="outline"
size="icon"
className="rounded-full bg-white hover:bg-gray-100 border-gray-300"
onClick={(e) => {
e.preventDefault();
document.getElementById('file-attachment-legacy')?.click();
}}
>
<Paperclip className="h-4 w-4 text-gray-600" />
</Button>
</label>
{sending && <span className="text-xs text-gray-500 ml-2">Preparing attachment...</span>}
</div>
<div className="flex items-center gap-3">
<Button
variant="ghost"
className="text-gray-600 hover:text-gray-700 hover:bg-gray-100"
onClick={() => {
if (onCancel) onCancel();
setShowCompose(false);
}}
disabled={sending}
>
Cancel
</Button>
<Button
className="bg-blue-600 text-white hover:bg-blue-700"
onClick={handleLegacySend}
disabled={sending}
>
{sending ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Sending...
</>
) : (
<>
<SendHorizontal className="mr-2 h-4 w-4" />
Send
</>
)}
</Button>
</div>
</div>
</div>
<ComposeEmailFooter
sending={sending}
onSend={handleLegacySend}
onCancel={() => {
if (onCancel) onCancel();
setShowCompose(false);
}}
/>
</Card>
</div>
);
}