courrier refactor
This commit is contained in:
parent
a30198cb2b
commit
4af36d63f9
@ -5,7 +5,7 @@ import { useRouter } from 'next/navigation';
|
|||||||
import {
|
import {
|
||||||
Mail, Loader2, AlertCircle,
|
Mail, Loader2, AlertCircle,
|
||||||
ChevronLeft, ChevronRight, Reply, ReplyAll, Forward,
|
ChevronLeft, ChevronRight, Reply, ReplyAll, Forward,
|
||||||
Star, FolderOpen
|
Star, FolderOpen, Plus as PlusIcon, RefreshCw, ChevronUp, ChevronDown
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { Dialog, DialogContent } from '@/components/ui/dialog';
|
import { Dialog, DialogContent } from '@/components/ui/dialog';
|
||||||
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
|
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
|
||||||
@ -48,6 +48,14 @@ function SimplifiedLoadingFix() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Account {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
color: string;
|
||||||
|
folders?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
export default function CourrierPage() {
|
export default function CourrierPage() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
@ -85,6 +93,29 @@ export default function CourrierPage() {
|
|||||||
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
|
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
|
||||||
const [showLoginNeeded, setShowLoginNeeded] = useState(false);
|
const [showLoginNeeded, setShowLoginNeeded] = useState(false);
|
||||||
|
|
||||||
|
// States to match the provided implementation
|
||||||
|
const [sidebarOpen, setSidebarOpen] = useState(true);
|
||||||
|
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
|
||||||
|
const [isReplying, setIsReplying] = useState(false);
|
||||||
|
const [isForwarding, setIsForwarding] = useState(false);
|
||||||
|
const [accountsDropdownOpen, setAccountsDropdownOpen] = useState(false);
|
||||||
|
const [showCompose, setShowCompose] = useState(false);
|
||||||
|
const [composeTo, setComposeTo] = useState('');
|
||||||
|
const [composeCc, setComposeCc] = useState('');
|
||||||
|
const [composeBcc, setComposeBcc] = useState('');
|
||||||
|
const [composeSubject, setComposeSubject] = useState('');
|
||||||
|
const [composeBody, setComposeBody] = useState('');
|
||||||
|
const [showCc, setShowCc] = useState(false);
|
||||||
|
const [showBcc, setShowBcc] = useState(false);
|
||||||
|
const [attachments, setAttachments] = useState<any[]>([]);
|
||||||
|
|
||||||
|
// Mock accounts
|
||||||
|
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' }
|
||||||
|
]);
|
||||||
|
const [selectedAccount, setSelectedAccount] = useState<Account | null>(null);
|
||||||
|
|
||||||
// Check for more emails
|
// Check for more emails
|
||||||
const hasMoreEmails = page < totalPages;
|
const hasMoreEmails = page < totalPages;
|
||||||
|
|
||||||
@ -131,38 +162,69 @@ export default function CourrierPage() {
|
|||||||
const formattedEmail = formatEmailForAction(selectedEmail, type);
|
const formattedEmail = formatEmailForAction(selectedEmail, type);
|
||||||
if (!formattedEmail) return;
|
if (!formattedEmail) return;
|
||||||
|
|
||||||
setComposeData({
|
setComposeTo(formattedEmail.to || '');
|
||||||
to: formattedEmail.to,
|
setComposeCc(formattedEmail.cc || '');
|
||||||
cc: formattedEmail.cc,
|
setComposeSubject(formattedEmail.subject || '');
|
||||||
subject: formattedEmail.subject,
|
setComposeBody(formattedEmail.body || '');
|
||||||
body: formattedEmail.body,
|
|
||||||
});
|
|
||||||
|
|
||||||
setComposeType(type);
|
if (type === 'forward') {
|
||||||
setShowComposeModal(true);
|
setIsForwarding(true);
|
||||||
|
} else {
|
||||||
|
setIsReplying(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
setShowCompose(true);
|
||||||
|
setShowCc(type === 'reply-all');
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle compose new email
|
// Handle compose new email
|
||||||
const handleComposeNew = () => {
|
const handleComposeNew = () => {
|
||||||
setComposeData({
|
setComposeTo('');
|
||||||
to: '',
|
setComposeCc('');
|
||||||
subject: '',
|
setComposeBcc('');
|
||||||
body: '',
|
setComposeSubject('');
|
||||||
});
|
setComposeBody('');
|
||||||
setComposeType('new');
|
setShowCc(false);
|
||||||
setShowComposeModal(true);
|
setShowBcc(false);
|
||||||
|
setIsReplying(false);
|
||||||
|
setIsForwarding(false);
|
||||||
|
setShowCompose(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle sending email
|
// Handle sending email
|
||||||
const handleSend = async (emailData: EmailData) => {
|
const handleSend = async () => {
|
||||||
await sendEmail(emailData);
|
if (!composeTo) {
|
||||||
|
alert('Please specify at least one recipient');
|
||||||
setShowComposeModal(false);
|
return;
|
||||||
setComposeData(null);
|
}
|
||||||
|
|
||||||
// Refresh the Sent folder if we're currently viewing it
|
try {
|
||||||
if (currentFolder.toLowerCase() === 'sent') {
|
await sendEmail({
|
||||||
loadEmails();
|
to: composeTo,
|
||||||
|
cc: composeCc,
|
||||||
|
bcc: composeBcc,
|
||||||
|
subject: composeSubject,
|
||||||
|
body: composeBody,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Clear compose form and close modal
|
||||||
|
setComposeTo('');
|
||||||
|
setComposeCc('');
|
||||||
|
setComposeBcc('');
|
||||||
|
setComposeSubject('');
|
||||||
|
setComposeBody('');
|
||||||
|
setAttachments([]);
|
||||||
|
setShowCompose(false);
|
||||||
|
setIsReplying(false);
|
||||||
|
setIsForwarding(false);
|
||||||
|
|
||||||
|
// Refresh the Sent folder if we're currently viewing it
|
||||||
|
if (currentFolder.toLowerCase() === 'sent') {
|
||||||
|
loadEmails();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error sending email:', error);
|
||||||
|
alert('Failed to send email. Please try again.');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -189,6 +251,163 @@ export default function CourrierPage() {
|
|||||||
router.push('/courrier/login');
|
router.push('/courrier/login');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handle mailbox change
|
||||||
|
const handleMailboxChange = (newMailbox: string) => {
|
||||||
|
changeFolder(newMailbox);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Format date for display
|
||||||
|
const formatDate = (dateString: string) => {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
const now = new Date();
|
||||||
|
|
||||||
|
if (date.toDateString() === now.toDateString()) {
|
||||||
|
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
||||||
|
} else {
|
||||||
|
return date.toLocaleDateString([], { month: 'short', day: 'numeric' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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">
|
||||||
|
{getFolderIcon(folder)}
|
||||||
|
<span className="ml-2">{formatFolderName(folder)}</span>
|
||||||
|
</div>
|
||||||
|
</Button>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
);
|
||||||
|
|
||||||
|
// Helper to format folder names
|
||||||
|
const formatFolderName = (folder: string) => {
|
||||||
|
return folder.charAt(0).toUpperCase() + folder.slice(1).toLowerCase();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper to get folder icons
|
||||||
|
const getFolderIcon = (folder: string) => {
|
||||||
|
const folderLower = folder.toLowerCase();
|
||||||
|
|
||||||
|
if (folderLower.includes('inbox')) {
|
||||||
|
return <Mail className="h-4 w-4" />;
|
||||||
|
} else if (folderLower.includes('sent')) {
|
||||||
|
return <Mail className="h-4 w-4" />;
|
||||||
|
} else if (folderLower.includes('trash')) {
|
||||||
|
return <Mail className="h-4 w-4" />;
|
||||||
|
} else {
|
||||||
|
return <Mail className="h-4 w-4" />;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Email list wrapper with preview panel
|
||||||
|
const renderEmailListWrapper = () => (
|
||||||
|
<div className="flex-1 flex overflow-hidden">
|
||||||
|
{/* Email list panel */}
|
||||||
|
<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}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Preview panel - will automatically take remaining space */}
|
||||||
|
<div className="flex-1 bg-white/95 backdrop-blur-sm flex flex-col">
|
||||||
|
{selectedEmail ? (
|
||||||
|
<>
|
||||||
|
{/* Email actions header */}
|
||||||
|
<div className="flex-none px-4 py-3 border-b border-gray-100">
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<div className="flex items-center gap-2 min-w-0 flex-1">
|
||||||
|
<div className="min-w-0 max-w-[500px]">
|
||||||
|
<h2 className="text-lg font-semibold text-gray-900 truncate">
|
||||||
|
{selectedEmail.subject || '(No subject)'}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2 flex-shrink-0">
|
||||||
|
<div className="flex items-center border-l border-gray-200 pl-4">
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
className="text-gray-600 hover:text-gray-900 px-2 py-1"
|
||||||
|
onClick={() => handleReplyOrForward('reply')}
|
||||||
|
>
|
||||||
|
Reply
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
className="text-gray-600 hover:text-gray-900 px-2 py-1"
|
||||||
|
onClick={() => handleReplyOrForward('reply-all')}
|
||||||
|
>
|
||||||
|
Reply All
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
className="text-gray-600 hover:text-gray-900 px-2 py-1"
|
||||||
|
onClick={() => handleReplyOrForward('forward')}
|
||||||
|
>
|
||||||
|
Forward
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Email content with scroll area */}
|
||||||
|
<ScrollArea className="flex-1">
|
||||||
|
<EmailContent email={selectedEmail} />
|
||||||
|
</ScrollArea>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className="flex flex-col items-center justify-center h-full">
|
||||||
|
<Mail className="h-12 w-12 text-gray-400 mb-4" />
|
||||||
|
<p className="text-gray-500">Select an email to view its contents</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
// Delete confirmation dialog
|
||||||
|
const renderDeleteConfirmDialog = () => (
|
||||||
|
<AlertDialog open={showDeleteConfirm} onOpenChange={setShowDeleteConfirm}>
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>Delete Emails</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription>
|
||||||
|
Are you sure you want to delete {selectedEmailIds.length} selected email{selectedEmailIds.length > 1 ? 's' : ''}? This action cannot be undone.
|
||||||
|
</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||||
|
<AlertDialogAction onClick={handleDeleteConfirm}>Delete</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
|
);
|
||||||
|
|
||||||
// If there's a critical error, show error dialog
|
// If there's a critical error, show error dialog
|
||||||
if (error && !isLoading && emails.length === 0 && !showLoginNeeded) {
|
if (error && !isLoading && emails.length === 0 && !showLoginNeeded) {
|
||||||
return (
|
return (
|
||||||
@ -202,39 +421,8 @@ export default function CourrierPage() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a properly formatted email message from composeData for the ComposeEmail component
|
|
||||||
const createEmailMessage = () => {
|
|
||||||
if (!composeData) return null;
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: 'temp-id',
|
|
||||||
messageId: '',
|
|
||||||
subject: composeData.subject || '',
|
|
||||||
from: [{ name: '', address: '' }],
|
|
||||||
to: [{ name: '', address: composeData.to || '' }],
|
|
||||||
cc: composeData.cc ? [{ name: '', address: composeData.cc }] : [],
|
|
||||||
bcc: composeData.bcc ? [{ name: '', address: composeData.bcc }] : [],
|
|
||||||
date: new Date(),
|
|
||||||
content: composeData.body || '',
|
|
||||||
html: composeData.body || '',
|
|
||||||
hasAttachments: false
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Format date for display
|
|
||||||
const formatDate = (dateString: string) => {
|
|
||||||
const date = new Date(dateString);
|
|
||||||
const now = new Date();
|
|
||||||
|
|
||||||
if (date.toDateString() === now.toDateString()) {
|
|
||||||
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
||||||
} else {
|
|
||||||
return date.toLocaleDateString([], { month: 'short', day: 'numeric' });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-screen">
|
<>
|
||||||
<SimplifiedLoadingFix />
|
<SimplifiedLoadingFix />
|
||||||
|
|
||||||
{/* Login required dialog */}
|
{/* Login required dialog */}
|
||||||
@ -253,137 +441,143 @@ export default function CourrierPage() {
|
|||||||
</AlertDialogContent>
|
</AlertDialogContent>
|
||||||
</AlertDialog>
|
</AlertDialog>
|
||||||
|
|
||||||
{/* Delete confirmation dialog */}
|
{/* Main layout */}
|
||||||
<AlertDialog open={showDeleteConfirm} onOpenChange={setShowDeleteConfirm}>
|
<main className="w-full h-screen bg-black">
|
||||||
<AlertDialogContent>
|
<div className="w-full h-full px-4 pt-12 pb-4">
|
||||||
<AlertDialogHeader>
|
<div className="flex h-full bg-carnet-bg">
|
||||||
<AlertDialogTitle>Confirm Deletion</AlertDialogTitle>
|
{/* Sidebar */}
|
||||||
<AlertDialogDescription>
|
<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
|
||||||
Are you sure you want to delete {selectedEmailIds.length} {selectedEmailIds.length === 1 ? 'email' : 'emails'}?
|
${mobileSidebarOpen ? 'fixed inset-y-0 left-0 z-40' : 'hidden'} md:block`}>
|
||||||
This action cannot be undone.
|
{/* Courrier Title */}
|
||||||
</AlertDialogDescription>
|
<div className="p-3 border-b border-gray-100">
|
||||||
</AlertDialogHeader>
|
<div className="flex items-center gap-2">
|
||||||
<AlertDialogFooter>
|
<Mail className="h-6 w-6 text-gray-600" />
|
||||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
<span className="text-xl font-semibold text-gray-900">COURRIER</span>
|
||||||
<AlertDialogAction
|
|
||||||
onClick={handleDeleteConfirm}
|
|
||||||
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
|
||||||
>
|
|
||||||
Delete
|
|
||||||
</AlertDialogAction>
|
|
||||||
</AlertDialogFooter>
|
|
||||||
</AlertDialogContent>
|
|
||||||
</AlertDialog>
|
|
||||||
|
|
||||||
{/* Compose email dialog */}
|
|
||||||
<Dialog open={showComposeModal} onOpenChange={setShowComposeModal}>
|
|
||||||
<DialogContent className="sm:max-w-[800px] h-[80vh] p-0">
|
|
||||||
<ComposeEmail
|
|
||||||
initialEmail={createEmailMessage()}
|
|
||||||
type={composeType}
|
|
||||||
onClose={() => setShowComposeModal(false)}
|
|
||||||
onSend={handleSend}
|
|
||||||
/>
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
|
|
||||||
{/* Main email interface */}
|
|
||||||
<div className="h-full flex flex-col">
|
|
||||||
{/* Email header */}
|
|
||||||
<EmailHeader
|
|
||||||
onSearch={searchEmails}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Main content area - fixed-width sidebar and list panel layout */}
|
|
||||||
<div className="flex-1 flex overflow-hidden">
|
|
||||||
{/* Sidebar - fixed width 64px */}
|
|
||||||
<div className="w-64 flex-shrink-0">
|
|
||||||
<EmailSidebar
|
|
||||||
currentFolder={currentFolder}
|
|
||||||
folders={mailboxes}
|
|
||||||
onFolderChange={changeFolder}
|
|
||||||
onRefresh={() => loadEmails(false)}
|
|
||||||
onCompose={handleComposeNew}
|
|
||||||
isLoading={isLoading}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Email list - fixed width 320px */}
|
|
||||||
<div className="w-[320px] flex-shrink-0">
|
|
||||||
<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}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Email content - takes remaining space */}
|
|
||||||
<div className="flex-1 h-full overflow-hidden flex flex-col">
|
|
||||||
{selectedEmail ? (
|
|
||||||
<>
|
|
||||||
{/* Email actions header */}
|
|
||||||
<div className="flex-none px-4 py-3 border-b border-gray-100">
|
|
||||||
<div className="flex items-center gap-4">
|
|
||||||
<div className="flex items-center gap-2 min-w-0 flex-1">
|
|
||||||
<div className="min-w-0 max-w-[500px]">
|
|
||||||
<h2 className="text-lg font-semibold text-gray-900 truncate">
|
|
||||||
{selectedEmail.subject || '(No subject)'}
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-2 flex-shrink-0">
|
|
||||||
<div className="flex items-center border-l border-gray-200 pl-4">
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
className="text-gray-600 hover:text-gray-900 px-2 py-1"
|
|
||||||
onClick={() => handleReplyOrForward('reply')}
|
|
||||||
>
|
|
||||||
Reply
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
className="text-gray-600 hover:text-gray-900 px-2 py-1"
|
|
||||||
onClick={() => handleReplyOrForward('reply-all')}
|
|
||||||
>
|
|
||||||
Reply All
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
className="text-gray-600 hover:text-gray-900 px-2 py-1"
|
|
||||||
onClick={() => handleReplyOrForward('forward')}
|
|
||||||
>
|
|
||||||
Forward
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Email content with avatar and proper scroll area */}
|
|
||||||
<ScrollArea className="flex-1">
|
|
||||||
<EmailContent email={selectedEmail} />
|
|
||||||
</ScrollArea>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<div className="flex flex-col items-center justify-center h-full">
|
|
||||||
<Mail className="h-12 w-12 text-gray-400 mb-4" />
|
|
||||||
<p className="text-gray-500">Select an email to view its contents</p>
|
|
||||||
</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={() => {
|
||||||
|
setShowCompose(true);
|
||||||
|
setComposeTo('');
|
||||||
|
setComposeCc('');
|
||||||
|
setComposeBcc('');
|
||||||
|
setComposeSubject('');
|
||||||
|
setComposeBody('');
|
||||||
|
setShowCc(false);
|
||||||
|
setShowBcc(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<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"
|
||||||
|
onClick={() => handleMailboxChange('INBOX')}
|
||||||
|
className="text-gray-600 hover:text-gray-900 hover:bg-gray-100"
|
||||||
|
>
|
||||||
|
<RefreshCw className="h-4 w-4" />
|
||||||
|
</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 flex-col items-start">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className={`w-2.5 h-2.5 rounded-full ${account.color}`}></div>
|
||||||
|
<span className="font-medium">{account.name}</span>
|
||||||
|
</div>
|
||||||
|
<span className="text-xs text-gray-500 ml-4">{account.email}</span>
|
||||||
|
</div>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Navigation */}
|
||||||
|
{renderSidebarNav()}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Main content area */}
|
||||||
|
<div className="flex-1 flex overflow-hidden">
|
||||||
|
{/* Email list panel */}
|
||||||
|
{renderEmailListWrapper()}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</main>
|
||||||
</div>
|
|
||||||
|
{/* Compose Email Modal */}
|
||||||
|
<ComposeEmail
|
||||||
|
showCompose={showCompose}
|
||||||
|
setShowCompose={setShowCompose}
|
||||||
|
composeTo={composeTo}
|
||||||
|
setComposeTo={setComposeTo}
|
||||||
|
composeCc={composeCc}
|
||||||
|
setComposeCc={setComposeCc}
|
||||||
|
composeBcc={composeBcc}
|
||||||
|
setComposeBcc={setComposeBcc}
|
||||||
|
composeSubject={composeSubject}
|
||||||
|
setComposeSubject={setComposeSubject}
|
||||||
|
composeBody={composeBody}
|
||||||
|
setComposeBody={setComposeBody}
|
||||||
|
showCc={showCc}
|
||||||
|
setShowCc={setShowCc}
|
||||||
|
showBcc={showBcc}
|
||||||
|
setShowBcc={setShowBcc}
|
||||||
|
attachments={attachments}
|
||||||
|
setAttachments={setAttachments}
|
||||||
|
handleSend={handleSend}
|
||||||
|
replyTo={isReplying ? selectedEmail : null}
|
||||||
|
forwardFrom={isForwarding ? selectedEmail : null}
|
||||||
|
onSend={async (email: EmailData) => {
|
||||||
|
console.log('Email sent:', email);
|
||||||
|
setShowCompose(false);
|
||||||
|
setIsReplying(false);
|
||||||
|
setIsForwarding(false);
|
||||||
|
return Promise.resolve();
|
||||||
|
}}
|
||||||
|
onCancel={() => {
|
||||||
|
setShowCompose(false);
|
||||||
|
setComposeTo('');
|
||||||
|
setComposeCc('');
|
||||||
|
setComposeBcc('');
|
||||||
|
setComposeSubject('');
|
||||||
|
setComposeBody('');
|
||||||
|
setShowCc(false);
|
||||||
|
setShowBcc(false);
|
||||||
|
setAttachments([]);
|
||||||
|
setIsReplying(false);
|
||||||
|
setIsForwarding(false);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{renderDeleteConfirmDialog()}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user