courrier multi account restore compose
This commit is contained in:
parent
4770b9858e
commit
a0fcbc3b62
@ -4,32 +4,24 @@ import React, { useState } from 'react';
|
|||||||
import {
|
import {
|
||||||
Inbox, Send, Trash, Archive, Star,
|
Inbox, Send, Trash, Archive, Star,
|
||||||
File, RefreshCw, Plus, MailOpen, Settings,
|
File, RefreshCw, Plus, MailOpen, Settings,
|
||||||
ChevronDown, ChevronRight, ChevronUp, Mail, AlertCircle,
|
ChevronDown, ChevronRight, Mail
|
||||||
MoreVertical, Edit, Trash2, AlertOctagon, Folder
|
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from '@/components/ui/dropdown-menu';
|
|
||||||
import { toast } from '@/components/ui/use-toast';
|
|
||||||
|
|
||||||
interface EmailSidebarProps {
|
interface EmailSidebarProps {
|
||||||
currentFolder: string;
|
currentFolder: string;
|
||||||
currentAccount: string;
|
currentAccount: string;
|
||||||
accounts: Array<{
|
accounts: Array<{
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
|
||||||
email: string;
|
email: string;
|
||||||
color: string;
|
|
||||||
folders: string[];
|
folders: string[];
|
||||||
}>;
|
}>;
|
||||||
onFolderChange: (folder: string, accountId: string) => void;
|
onFolderChange: (folder: string, accountId: string) => void;
|
||||||
onRefresh: () => void;
|
onRefresh: () => void;
|
||||||
onCompose: () => void;
|
onCompose: () => void;
|
||||||
onAddAccount: () => void;
|
|
||||||
onEditAccount: (accountId: string) => void;
|
|
||||||
onDeleteAccount: (accountId: string) => void;
|
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,9 +32,6 @@ export default function EmailSidebar({
|
|||||||
onFolderChange,
|
onFolderChange,
|
||||||
onRefresh,
|
onRefresh,
|
||||||
onCompose,
|
onCompose,
|
||||||
onAddAccount,
|
|
||||||
onEditAccount,
|
|
||||||
onDeleteAccount,
|
|
||||||
isLoading
|
isLoading
|
||||||
}: EmailSidebarProps) {
|
}: EmailSidebarProps) {
|
||||||
const [showAccounts, setShowAccounts] = useState(true);
|
const [showAccounts, setShowAccounts] = useState(true);
|
||||||
@ -52,26 +41,42 @@ export default function EmailSidebar({
|
|||||||
const getFolderIcon = (folder: string) => {
|
const getFolderIcon = (folder: string) => {
|
||||||
const folderLower = folder.toLowerCase();
|
const folderLower = folder.toLowerCase();
|
||||||
|
|
||||||
if (folderLower.includes('inbox')) {
|
switch (folderLower) {
|
||||||
return <Inbox className="h-4 w-4 text-gray-500" />;
|
case 'inbox':
|
||||||
} else if (folderLower.includes('sent')) {
|
return <Inbox className="h-4 w-4" />;
|
||||||
return <Send className="h-4 w-4 text-gray-500" />;
|
case 'sent':
|
||||||
} else if (folderLower.includes('trash')) {
|
case 'sent items':
|
||||||
return <Trash className="h-4 w-4 text-gray-500" />;
|
return <Send className="h-4 w-4" />;
|
||||||
} else if (folderLower.includes('archive')) {
|
case 'drafts':
|
||||||
return <Archive className="h-4 w-4 text-gray-500" />;
|
return <File className="h-4 w-4" />;
|
||||||
} else if (folderLower.includes('draft')) {
|
case 'trash':
|
||||||
return <Edit className="h-4 w-4 text-gray-500" />;
|
case 'deleted':
|
||||||
} else if (folderLower.includes('spam') || folderLower.includes('junk')) {
|
case 'bin':
|
||||||
return <AlertOctagon className="h-4 w-4 text-gray-500" />;
|
return <Trash className="h-4 w-4" />;
|
||||||
} else {
|
case 'archive':
|
||||||
return <Folder className="h-4 w-4 text-gray-500" />;
|
case 'archived':
|
||||||
|
return <Archive className="h-4 w-4" />;
|
||||||
|
case 'starred':
|
||||||
|
case 'important':
|
||||||
|
return <Star className="h-4 w-4" />;
|
||||||
|
default:
|
||||||
|
return <MailOpen className="h-4 w-4" />;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper to format folder names
|
// Group folders into standard and custom
|
||||||
const formatFolderName = (folder: string) => {
|
const getStandardFolders = (folders: string[]) => {
|
||||||
return folder.charAt(0).toUpperCase() + folder.slice(1).toLowerCase();
|
const standardFolders = ['INBOX', 'Sent', 'Drafts', 'Trash', 'Archive', 'Junk'];
|
||||||
|
return standardFolders.filter(f =>
|
||||||
|
folders.includes(f) || folders.some(folder => folder.toLowerCase() === f.toLowerCase())
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCustomFolders = (folders: string[]) => {
|
||||||
|
const standardFolders = ['INBOX', 'Sent', 'Drafts', 'Trash', 'Archive', 'Junk'];
|
||||||
|
return folders.filter(f =>
|
||||||
|
!standardFolders.some(sf => sf.toLowerCase() === f.toLowerCase())
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAccountClick = (accountId: string) => {
|
const handleAccountClick = (accountId: string) => {
|
||||||
@ -97,15 +102,6 @@ export default function EmailSidebar({
|
|||||||
{/* Accounts header with toggle */}
|
{/* Accounts header with toggle */}
|
||||||
<div className="flex items-center justify-between px-2 py-2 text-sm font-medium text-gray-600">
|
<div className="flex items-center justify-between px-2 py-2 text-sm font-medium text-gray-600">
|
||||||
<span>Accounts</span>
|
<span>Accounts</span>
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
size="sm"
|
|
||||||
className="h-7 w-7 p-0 text-gray-400 hover:text-gray-600"
|
|
||||||
onClick={onAddAccount}
|
|
||||||
>
|
|
||||||
<Plus className="h-4 w-4" />
|
|
||||||
</Button>
|
|
||||||
<button
|
<button
|
||||||
onClick={() => setShowAccounts(!showAccounts)}
|
onClick={() => setShowAccounts(!showAccounts)}
|
||||||
className="text-gray-400 hover:text-gray-600"
|
className="text-gray-400 hover:text-gray-600"
|
||||||
@ -117,7 +113,6 @@ export default function EmailSidebar({
|
|||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Accounts list */}
|
{/* Accounts list */}
|
||||||
{showAccounts && (
|
{showAccounts && (
|
||||||
@ -125,73 +120,66 @@ export default function EmailSidebar({
|
|||||||
{accounts.map((account) => (
|
{accounts.map((account) => (
|
||||||
<div key={account.id} className="space-y-1">
|
<div key={account.id} className="space-y-1">
|
||||||
{/* Account button */}
|
{/* Account button */}
|
||||||
<div
|
<Button
|
||||||
className={`flex items-center w-full px-2 py-1 rounded-md cursor-pointer ${
|
variant="ghost"
|
||||||
currentAccount === account.id ? 'bg-gray-100' : ''
|
className={`w-full justify-between p-2 text-gray-600 hover:text-gray-900 hover:bg-gray-100 ${
|
||||||
|
expandedAccount === account.id ? 'bg-gray-100' : ''
|
||||||
}`}
|
}`}
|
||||||
onClick={() => handleAccountClick(account.id)}
|
onClick={() => handleAccountClick(account.id)}
|
||||||
>
|
>
|
||||||
<div className={`w-3 h-3 rounded-full ${account.color} mr-2`}></div>
|
<div className="flex items-center">
|
||||||
<span className="truncate text-gray-700 flex-1">{account.name}</span>
|
<Mail className="h-4 w-4 mr-2" />
|
||||||
|
<span className="truncate">{account.email}</span>
|
||||||
{/* More options button (⋮) */}
|
|
||||||
{account.id !== 'loading-account' && (
|
|
||||||
<DropdownMenu>
|
|
||||||
<DropdownMenuTrigger asChild>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="ml-1 text-gray-400 hover:text-gray-600 cursor-pointer flex items-center justify-center h-5 w-5"
|
|
||||||
onClick={e => e.stopPropagation()}
|
|
||||||
>
|
|
||||||
<span style={{ fontSize: '18px', lineHeight: 1 }}>⋮</span>
|
|
||||||
</button>
|
|
||||||
</DropdownMenuTrigger>
|
|
||||||
<DropdownMenuContent align="end">
|
|
||||||
<DropdownMenuItem onClick={() => onEditAccount(account.id)}>
|
|
||||||
Edit
|
|
||||||
</DropdownMenuItem>
|
|
||||||
<DropdownMenuItem onClick={() => onDeleteAccount(account.id)}>
|
|
||||||
Delete
|
|
||||||
</DropdownMenuItem>
|
|
||||||
</DropdownMenuContent>
|
|
||||||
</DropdownMenu>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Expand/collapse arrow */}
|
|
||||||
{account.id !== 'loading-account' && (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="ml-1 text-gray-400 hover:text-gray-600 cursor-pointer flex items-center justify-center h-5 w-5"
|
|
||||||
onClick={e => { e.stopPropagation(); handleAccountClick(account.id); }}
|
|
||||||
>
|
|
||||||
{expandedAccount === account.id ? <ChevronUp className="h-3 w-3" /> : <ChevronDown className="h-3 w-3" />}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
{expandedAccount === account.id ? (
|
||||||
|
<ChevronDown className="h-4 w-4" />
|
||||||
|
) : (
|
||||||
|
<ChevronRight className="h-4 w-4" />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
|
||||||
{/* Account folders - shown when account is expanded */}
|
{/* Account folders - shown when account is expanded */}
|
||||||
{expandedAccount === account.id && account.folders && account.folders.length > 0 && (
|
{expandedAccount === account.id && (
|
||||||
<div className="pl-4">
|
<div className="pl-6 space-y-1">
|
||||||
{account.folders.map((folder) => (
|
{getStandardFolders(account.folders).map((folder) => (
|
||||||
<Button
|
<Button
|
||||||
key={folder}
|
key={folder}
|
||||||
variant="ghost"
|
variant={currentFolder === folder && currentAccount === account.id ? "secondary" : "ghost"}
|
||||||
className={`w-full justify-start text-xs py-1 h-7 ${
|
className={`w-full justify-start ${
|
||||||
currentFolder === folder && currentAccount === account.id ? 'bg-gray-100' : ''
|
currentFolder === folder && currentAccount === account.id ? 'bg-gray-100 text-gray-900' : 'text-gray-600 hover:text-gray-900'
|
||||||
}`}
|
}`}
|
||||||
onClick={() => onFolderChange(folder, account.id)}
|
onClick={() => onFolderChange(folder, account.id)}
|
||||||
>
|
>
|
||||||
<div className="flex items-center w-full">
|
<div className="flex items-center w-full">
|
||||||
|
<span className="flex items-center">
|
||||||
{getFolderIcon(folder)}
|
{getFolderIcon(folder)}
|
||||||
<span className="ml-2 truncate text-gray-700">{formatFolderName(folder)}</span>
|
<span className="ml-2 capitalize">{folder.toLowerCase()}</span>
|
||||||
|
</span>
|
||||||
{folder === 'INBOX' && (
|
{folder === 'INBOX' && (
|
||||||
<span className="ml-auto bg-blue-500 text-white text-[10px] px-1.5 rounded-full">
|
<span className="ml-auto bg-blue-600 text-white text-xs px-2 py-0.5 rounded-full">
|
||||||
{/* Unread count would go here */}
|
{/* Unread count would go here */}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
|
{/* Custom folders */}
|
||||||
|
{getCustomFolders(account.folders).map(folder => (
|
||||||
|
<Button
|
||||||
|
key={folder}
|
||||||
|
variant={currentFolder === folder && currentAccount === account.id ? "secondary" : "ghost"}
|
||||||
|
className={`w-full justify-start ${
|
||||||
|
currentFolder === folder && currentAccount === account.id ? 'bg-gray-100 text-gray-900' : 'text-gray-600 hover:text-gray-900'
|
||||||
|
}`}
|
||||||
|
onClick={() => onFolderChange(folder, account.id)}
|
||||||
|
>
|
||||||
|
<div className="flex items-center">
|
||||||
|
{getFolderIcon(folder)}
|
||||||
|
<span className="ml-2 truncate">{folder}</span>
|
||||||
|
</div>
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user