courrier multi account restore compose
This commit is contained in:
parent
c2bb904fde
commit
5bade2283c
@ -180,15 +180,9 @@ export default function CourrierPage() {
|
||||
]);
|
||||
const [selectedAccount, setSelectedAccount] = useState<Account | null>(null);
|
||||
|
||||
// Track expanded folders for each account
|
||||
const [expandedAccounts, setExpandedAccounts] = useState<Record<string, boolean>>({});
|
||||
|
||||
// Track selected folder per account
|
||||
const [selectedFolders, setSelectedFolders] = useState<Record<string, string>>({});
|
||||
|
||||
// Track folder visibility per account
|
||||
const [visibleFolders, setVisibleFolders] = useState<Record<string, string[]>>({});
|
||||
|
||||
// Add state for modals/dialogs
|
||||
const [showEditModal, setShowEditModal] = useState(false);
|
||||
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
|
||||
@ -198,34 +192,6 @@ export default function CourrierPage() {
|
||||
const [editLoading, setEditLoading] = useState(false);
|
||||
const [deleteLoading, setDeleteLoading] = useState(false);
|
||||
|
||||
// Debug accounts state
|
||||
useEffect(() => {
|
||||
console.log('Current accounts state:', accounts);
|
||||
console.log('Expanded accounts:', expandedAccounts);
|
||||
console.log('Selected account:', selectedAccount);
|
||||
console.log('Show folders:', showFolders);
|
||||
}, [accounts, expandedAccounts, selectedAccount, showFolders]);
|
||||
|
||||
// Debug selectedAccount state
|
||||
useEffect(() => {
|
||||
console.log('Selected account changed:', selectedAccount);
|
||||
if (selectedAccount) {
|
||||
console.log('Selected account folders:', selectedAccount.folders);
|
||||
}
|
||||
}, [selectedAccount]);
|
||||
|
||||
// Add useEffect for debugging
|
||||
useEffect(() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
console.log('[DEBUG] Rendering UI with:', {
|
||||
accountsCount: accounts.length,
|
||||
selectedAccountId: selectedAccount?.id,
|
||||
showFolders,
|
||||
currentFolder
|
||||
});
|
||||
}
|
||||
}, [accounts, selectedAccount, showFolders, currentFolder]);
|
||||
|
||||
// Calculate unread count for each account and folder
|
||||
useEffect(() => {
|
||||
// Create a map to store unread counts per account and folder
|
||||
@ -440,12 +406,6 @@ export default function CourrierPage() {
|
||||
setSelectedAccount(updatedAccounts[1]);
|
||||
setShowFolders(true);
|
||||
|
||||
// Ensure folders are visible for the selected account
|
||||
setExpandedAccounts(prev => ({
|
||||
...prev,
|
||||
[updatedAccounts[1].id]: true
|
||||
}));
|
||||
|
||||
// Set initial selected folder
|
||||
setSelectedFolders(prev => ({
|
||||
...prev,
|
||||
@ -714,14 +674,9 @@ export default function CourrierPage() {
|
||||
|
||||
const handleAccountSelect = (account: Account) => {
|
||||
setSelectedAccount(account);
|
||||
setShowFolders(true);
|
||||
if (account.id !== 'loading-account') {
|
||||
setExpandedAccounts(prev => ({
|
||||
...prev,
|
||||
[account.id]: true
|
||||
}));
|
||||
handleMailboxChange('INBOX', account.id);
|
||||
}
|
||||
handleMailboxChange('INBOX', account.id);
|
||||
};
|
||||
|
||||
const handleAddAccount = async (accountData: AccountData) => {
|
||||
@ -733,24 +688,6 @@ export default function CourrierPage() {
|
||||
// }));
|
||||
};
|
||||
|
||||
// Debug folder rendering
|
||||
useEffect(() => {
|
||||
if (selectedAccount) {
|
||||
console.log('Selected account folders:', selectedAccount.folders);
|
||||
console.log('Is account expanded:', expandedAccounts[selectedAccount.id]);
|
||||
}
|
||||
}, [selectedAccount, expandedAccounts]);
|
||||
|
||||
// On page load/refresh, expand all accounts so their folders are always visible
|
||||
useEffect(() => {
|
||||
// Expand all real accounts (not loading-account) on load/refresh
|
||||
const expanded: Record<string, boolean> = {};
|
||||
accounts.forEach(a => {
|
||||
if (a.id !== 'loading-account') expanded[a.id] = true;
|
||||
});
|
||||
setExpandedAccounts(expanded);
|
||||
}, [accounts]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SimplifiedLoadingFix />
|
||||
@ -765,7 +702,6 @@ export default function CourrierPage() {
|
||||
selectedAccount={selectedAccount}
|
||||
selectedFolders={selectedFolders}
|
||||
currentFolder={currentFolder}
|
||||
expandedAccounts={expandedAccounts}
|
||||
loading={loading}
|
||||
unreadCount={unreadCount}
|
||||
showAddAccountForm={showAddAccountForm}
|
||||
@ -777,9 +713,6 @@ export default function CourrierPage() {
|
||||
}}
|
||||
onComposeNew={handleComposeNew}
|
||||
onAccountSelect={handleAccountSelect}
|
||||
onToggleExpand={(accountId, expanded) => {
|
||||
setExpandedAccounts(prev => ({ ...prev, [accountId]: expanded }));
|
||||
}}
|
||||
onShowAddAccountForm={setShowAddAccountForm}
|
||||
onAddAccount={async (formData) => {
|
||||
setLoading(true);
|
||||
|
||||
@ -16,35 +16,28 @@ import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { Label } from '@/components/ui/label';
|
||||
|
||||
interface Account {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
color: string;
|
||||
folders: string[];
|
||||
}
|
||||
import { IconArrowDown, IconCheck, IconChevronDown, IconChevronUp, IconEdit, IconMail, IconMailbox, IconPencil, IconPlus, IconRefresh, IconTrash } from '@tabler/icons-react';
|
||||
import { Account } from '../../types';
|
||||
|
||||
interface EmailSidebarProps {
|
||||
accounts: Account[];
|
||||
selectedAccount: Account | null;
|
||||
selectedFolders: Record<string, string>;
|
||||
currentFolder: string;
|
||||
expandedAccounts: Record<string, boolean>;
|
||||
loading: boolean;
|
||||
unreadCount: number;
|
||||
unreadCount: Record<string, Record<string, number>>;
|
||||
showAddAccountForm: boolean;
|
||||
// Actions
|
||||
showFolders?: boolean;
|
||||
onFolderChange: (folder: string, accountId: string) => void;
|
||||
onRefresh: () => void;
|
||||
onComposeNew: () => void;
|
||||
onAccountSelect: (account: Account) => void;
|
||||
onToggleExpand: (accountId: string, expanded: boolean) => void;
|
||||
onShowAddAccountForm: (show: boolean) => void;
|
||||
onAddAccount: (formData: FormData) => Promise<void>;
|
||||
onAddAccount: (formData: any) => Promise<void>;
|
||||
onEditAccount: (account: Account) => void;
|
||||
onDeleteAccount: (account: Account) => void;
|
||||
onSelectEmail?: (emailId: string, accountId: string, folder: string) => void;
|
||||
onShowFoldersToggle?: (show: boolean) => void;
|
||||
}
|
||||
|
||||
export default function EmailSidebar({
|
||||
@ -52,20 +45,68 @@ export default function EmailSidebar({
|
||||
selectedAccount,
|
||||
selectedFolders,
|
||||
currentFolder,
|
||||
expandedAccounts,
|
||||
loading,
|
||||
unreadCount,
|
||||
showAddAccountForm,
|
||||
showFolders = true,
|
||||
onFolderChange,
|
||||
onRefresh,
|
||||
onComposeNew,
|
||||
onAccountSelect,
|
||||
onToggleExpand,
|
||||
onShowAddAccountForm,
|
||||
onAddAccount,
|
||||
onEditAccount,
|
||||
onDeleteAccount
|
||||
onDeleteAccount,
|
||||
onSelectEmail,
|
||||
onShowFoldersToggle
|
||||
}: EmailSidebarProps) {
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [formData, setFormData] = useState({
|
||||
email: '',
|
||||
password: '',
|
||||
displayName: '',
|
||||
host: '',
|
||||
port: '993',
|
||||
useSSL: true,
|
||||
smtpHost: '',
|
||||
smtpPort: '587',
|
||||
smtpUseSSL: false
|
||||
});
|
||||
const [activeTab, setActiveTab] = useState('imap');
|
||||
|
||||
// Handle form submission
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setIsSaving(true);
|
||||
try {
|
||||
await onAddAccount(formData);
|
||||
setFormData({
|
||||
email: '',
|
||||
password: '',
|
||||
displayName: '',
|
||||
host: '',
|
||||
port: '993',
|
||||
useSSL: true,
|
||||
smtpHost: '',
|
||||
smtpPort: '587',
|
||||
smtpUseSSL: false
|
||||
});
|
||||
onShowAddAccountForm(false);
|
||||
} catch (err) {
|
||||
console.error('Failed to add account:', err);
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Handle input changes
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { name, value, type, checked } = e.target;
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
[name]: type === 'checkbox' ? checked : value
|
||||
}));
|
||||
};
|
||||
|
||||
// Get the appropriate icon for a folder
|
||||
const getFolderIcon = (folder: string) => {
|
||||
@ -116,9 +157,9 @@ export default function EmailSidebar({
|
||||
<div className="flex items-center w-full">
|
||||
{getFolderIcon(baseFolder)}
|
||||
<span className="ml-2 truncate text-gray-700">{formatFolderName(baseFolder)}</span>
|
||||
{baseFolder === 'INBOX' && unreadCount > 0 && (
|
||||
{baseFolder === 'INBOX' && unreadCount[accountId]?.[folder] > 0 && (
|
||||
<span className="ml-auto bg-blue-500 text-white text-[10px] px-1.5 rounded-full">
|
||||
{unreadCount}
|
||||
{unreadCount[accountId][folder]}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
@ -163,14 +204,28 @@ export default function EmailSidebar({
|
||||
<div className="p-3 border-b border-gray-100">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<span className="text-sm font-medium text-gray-500">Accounts</span>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-7 w-7 p-0 text-gray-400 hover:text-gray-600"
|
||||
onClick={() => onShowAddAccountForm(!showAddAccountForm)}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
<div className="flex items-center gap-1">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-7 w-7 p-0 text-gray-400 hover:text-gray-600"
|
||||
onClick={() => onShowFoldersToggle?.(showFolders ? false : true)}
|
||||
>
|
||||
{showFolders ? (
|
||||
<ChevronUp className="h-4 w-4" />
|
||||
) : (
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
)}
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-7 w-7 p-0 text-gray-400 hover:text-gray-600"
|
||||
onClick={() => onShowAddAccountForm(!showAddAccountForm)}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Display all accounts */}
|
||||
@ -179,10 +234,7 @@ export default function EmailSidebar({
|
||||
{showAddAccountForm && (
|
||||
<div className="mb-2 p-2 border border-gray-200 rounded-md bg-white">
|
||||
<h4 className="text-xs font-medium mb-0.5 text-gray-700">Add IMAP Account</h4>
|
||||
<form onSubmit={async (e) => {
|
||||
e.preventDefault();
|
||||
await onAddAccount(new FormData(e.currentTarget));
|
||||
}}>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div>
|
||||
<Tabs defaultValue="imap" className="w-full">
|
||||
<TabsList className="grid w-full grid-cols-2 h-6 mb-0.5 bg-gray-100">
|
||||
@ -198,6 +250,8 @@ export default function EmailSidebar({
|
||||
placeholder="email@example.com"
|
||||
className="h-7 text-xs bg-white border-gray-300 mb-0.5 text-gray-900"
|
||||
required
|
||||
value={formData.email}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
@ -208,14 +262,18 @@ export default function EmailSidebar({
|
||||
placeholder="•••••••••"
|
||||
className="h-7 text-xs bg-white border-gray-300 mb-0.5 text-gray-900"
|
||||
required
|
||||
value={formData.password}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Input
|
||||
id="display_name"
|
||||
name="display_name"
|
||||
name="displayName"
|
||||
placeholder="John Doe"
|
||||
className="h-7 text-xs bg-white border-gray-300 mb-0.5 text-gray-900"
|
||||
value={formData.displayName}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
@ -225,6 +283,8 @@ export default function EmailSidebar({
|
||||
placeholder="imap.example.com"
|
||||
className="h-7 text-xs bg-white border-gray-300 mb-0.5 text-gray-900"
|
||||
required
|
||||
value={formData.host}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex gap-1">
|
||||
@ -236,12 +296,14 @@ export default function EmailSidebar({
|
||||
className="h-7 text-xs bg-white border-gray-300 text-gray-900"
|
||||
defaultValue="993"
|
||||
required
|
||||
value={formData.port}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center pl-1">
|
||||
<div className="flex items-center space-x-1">
|
||||
<Checkbox id="secure" name="secure" defaultChecked />
|
||||
<Label htmlFor="secure" className="text-xs">SSL</Label>
|
||||
<Checkbox id="useSSL" name="useSSL" defaultChecked={formData.useSSL} onChange={handleChange} />
|
||||
<Label htmlFor="useSSL" className="text-xs">SSL</Label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -251,24 +313,28 @@ export default function EmailSidebar({
|
||||
<div>
|
||||
<Input
|
||||
id="smtp_host"
|
||||
name="smtp_host"
|
||||
name="smtpHost"
|
||||
placeholder="smtp.example.com"
|
||||
className="h-7 text-xs bg-white border-gray-300 mb-0.5 text-gray-900"
|
||||
value={formData.smtpHost}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex gap-1">
|
||||
<div className="flex-1">
|
||||
<Input
|
||||
id="smtp_port"
|
||||
name="smtp_port"
|
||||
name="smtpPort"
|
||||
placeholder="587"
|
||||
className="h-7 text-xs bg-white border-gray-300 text-gray-900"
|
||||
defaultValue="587"
|
||||
value={formData.smtpPort}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center pl-1">
|
||||
<div className="flex items-center space-x-1">
|
||||
<Checkbox id="smtp_secure" name="smtp_secure" defaultChecked />
|
||||
<Checkbox id="smtp_secure" name="smtpUseSSL" defaultChecked={formData.smtpUseSSL} onChange={handleChange} />
|
||||
<Label htmlFor="smtp_secure" className="text-xs">SSL</Label>
|
||||
</div>
|
||||
</div>
|
||||
@ -283,9 +349,9 @@ export default function EmailSidebar({
|
||||
<Button
|
||||
type="submit"
|
||||
className="flex-1 h-6 text-xs bg-blue-500 hover:bg-blue-600 text-white rounded-md px-2 py-0"
|
||||
disabled={loading}
|
||||
disabled={isSaving}
|
||||
>
|
||||
{loading ? <Loader2 className="h-3 w-3 animate-spin mr-1" /> : null}
|
||||
{isSaving ? <Loader2 className="h-3 w-3 animate-spin mr-1" /> : null}
|
||||
Test & Add
|
||||
</Button>
|
||||
<Button
|
||||
@ -335,20 +401,9 @@ export default function EmailSidebar({
|
||||
</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"
|
||||
tabIndex={-1}
|
||||
onClick={e => { e.stopPropagation(); onToggleExpand(account.id, !expandedAccounts[account.id]); }}
|
||||
>
|
||||
{expandedAccounts[account.id] ? <ChevronUp className="h-3 w-3" /> : <ChevronDown className="h-3 w-3" />}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{/* Show folders for any expanded account */}
|
||||
{expandedAccounts[account.id] && account.folders && account.folders.length > 0 && (
|
||||
{/* Show folders for each account when selected and when folders are visible */}
|
||||
{selectedAccount?.id === account.id && showFolders && account.folders && account.folders.length > 0 && (
|
||||
<div className="pl-4">
|
||||
{account.folders.map((folder) => renderFolderButton(folder, account.id))}
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user