mail page ui correction maj compose 20 bis 13
This commit is contained in:
parent
ca3d1d832b
commit
a224c152b6
@ -116,6 +116,7 @@ export async function GET() {
|
||||
const allEmails: Email[] = [];
|
||||
|
||||
imap.once('ready', () => {
|
||||
// Get all mailboxes first
|
||||
imap.getBoxes((err, boxes) => {
|
||||
if (err) {
|
||||
console.error('Error getting mailboxes:', err);
|
||||
@ -124,21 +125,17 @@ export async function GET() {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Available mailboxes:', Object.keys(boxes));
|
||||
// Get the list of available mailboxes
|
||||
const availableMailboxes = Object.keys(boxes);
|
||||
console.log('Available mailboxes:', availableMailboxes);
|
||||
|
||||
// Map of folder names to their types
|
||||
const folderMap = {
|
||||
'INBOX': 'inbox',
|
||||
'Sent': 'sent',
|
||||
'Trash': 'trash',
|
||||
'Drafts': 'drafts'
|
||||
};
|
||||
|
||||
const foldersToCheck = Object.keys(folderMap);
|
||||
// These are the folders we want to process based on your IMAP structure
|
||||
const foldersToCheck = ['INBOX', 'Sent', 'Trash', 'Spam', 'Drafts', 'Archives', 'Archive'];
|
||||
let foldersProcessed = 0;
|
||||
|
||||
const processFolder = (folderName: string) => {
|
||||
console.log(`Opening folder: ${folderName}`);
|
||||
console.log(`Processing folder: ${folderName}`);
|
||||
|
||||
imap.openBox(folderName, false, (err, box) => {
|
||||
if (err) {
|
||||
console.error(`Error opening ${folderName}:`, err);
|
||||
@ -149,7 +146,7 @@ export async function GET() {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Successfully opened ${folderName}, messages:`, box.messages.total);
|
||||
console.log(`Successfully opened ${folderName}, total messages: ${box.messages.total}`);
|
||||
|
||||
if (box.messages.total === 0) {
|
||||
foldersProcessed++;
|
||||
@ -160,14 +157,7 @@ export async function GET() {
|
||||
}
|
||||
|
||||
// Search for all messages in the folder
|
||||
const searchCriteria = ['ALL'];
|
||||
|
||||
// For INBOX, exclude drafts
|
||||
if (folderName === 'INBOX') {
|
||||
searchCriteria.push(['!KEYWORD', '\\Draft']);
|
||||
}
|
||||
|
||||
imap.search(searchCriteria, (err, results) => {
|
||||
imap.search(['ALL'], (err, results) => {
|
||||
if (err) {
|
||||
console.error(`Search error in ${folderName}:`, err);
|
||||
foldersProcessed++;
|
||||
@ -177,7 +167,7 @@ export async function GET() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sort results to get the most recent messages first
|
||||
// Get the most recent messages (up to 20)
|
||||
const messageNumbers = results
|
||||
.sort((a, b) => b - a)
|
||||
.slice(0, 20);
|
||||
@ -205,8 +195,7 @@ export async function GET() {
|
||||
starred: false,
|
||||
body: '',
|
||||
to: '',
|
||||
folder: folderName, // Keep the original folder name
|
||||
draft: false
|
||||
folder: folderName // Keep exact folder name
|
||||
};
|
||||
|
||||
msg.on('body', (stream, info) => {
|
||||
@ -231,16 +220,10 @@ export async function GET() {
|
||||
email.id = attrs.uid;
|
||||
email.read = attrs.flags?.includes('\\Seen') || false;
|
||||
email.starred = attrs.flags?.includes('\\Flagged') || false;
|
||||
email.draft = attrs.flags?.includes('\\Draft') || false;
|
||||
});
|
||||
|
||||
msg.once('end', () => {
|
||||
// Only add the email if it belongs in this folder
|
||||
if (folderName === 'INBOX' && !email.draft) {
|
||||
allEmails.push(email);
|
||||
} else if (folderName !== 'INBOX') {
|
||||
allEmails.push(email);
|
||||
}
|
||||
allEmails.push(email);
|
||||
});
|
||||
});
|
||||
|
||||
@ -249,7 +232,7 @@ export async function GET() {
|
||||
});
|
||||
|
||||
f.once('end', () => {
|
||||
console.log(`Finished processing ${folderName}`);
|
||||
console.log(`Finished processing ${folderName}, emails found: ${allEmails.length}`);
|
||||
foldersProcessed++;
|
||||
if (foldersProcessed === foldersToCheck.length) {
|
||||
finishProcessing();
|
||||
@ -259,16 +242,13 @@ export async function GET() {
|
||||
});
|
||||
};
|
||||
|
||||
// Process folders sequentially
|
||||
// Process each folder sequentially
|
||||
foldersToCheck.forEach(folder => processFolder(folder));
|
||||
});
|
||||
});
|
||||
|
||||
function finishProcessing() {
|
||||
console.log('All folders processed, total emails:', allEmails.length);
|
||||
// Sort all emails by date
|
||||
allEmails.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
|
||||
|
||||
const response = {
|
||||
emails: allEmails,
|
||||
mailUrl: process.env.NEXTCLOUD_URL ? `${process.env.NEXTCLOUD_URL}/apps/mail/` : null
|
||||
|
||||
@ -23,7 +23,8 @@ import {
|
||||
MoreVertical, Settings, Plus as PlusIcon, Trash2, Edit, Mail,
|
||||
Inbox, Send, Star, Trash, Plus, ChevronLeft, ChevronRight,
|
||||
Search, ChevronDown, Folder, ChevronUp, Reply, Forward, ReplyAll,
|
||||
MoreHorizontal, FolderOpen, X, Paperclip, MessageSquare, Copy, EyeOff
|
||||
MoreHorizontal, FolderOpen, X, Paperclip, MessageSquare, Copy, EyeOff,
|
||||
AlertOctagon, Archive
|
||||
} from 'lucide-react';
|
||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||
|
||||
@ -47,7 +48,7 @@ interface Email {
|
||||
read?: boolean;
|
||||
starred?: boolean;
|
||||
deleted?: boolean;
|
||||
category?: 'inbox' | 'sent' | 'trash';
|
||||
category?: 'inbox' | 'sent' | 'trash' | 'spam' | 'drafts' | 'archives' | 'archive';
|
||||
cc?: string;
|
||||
bcc?: string;
|
||||
flags?: string[];
|
||||
@ -429,6 +430,55 @@ function cleanEmailContent(content: string): string {
|
||||
});
|
||||
}
|
||||
|
||||
// Add a type for the available views
|
||||
type MailView = 'inbox' | 'sent' | 'trash' | 'spam' | 'drafts' | 'archives' | 'archive' | 'starred';
|
||||
|
||||
// Update the sidebar navigation
|
||||
const sidebarNavItems = [
|
||||
{
|
||||
view: 'inbox' as MailView,
|
||||
label: 'Inbox',
|
||||
icon: Inbox,
|
||||
folder: 'INBOX'
|
||||
},
|
||||
{
|
||||
view: 'starred' as MailView,
|
||||
label: 'Starred',
|
||||
icon: Star,
|
||||
folder: null // This is handled by the starred flag
|
||||
},
|
||||
{
|
||||
view: 'sent' as MailView,
|
||||
label: 'Sent',
|
||||
icon: Send,
|
||||
folder: 'Sent'
|
||||
},
|
||||
{
|
||||
view: 'drafts' as MailView,
|
||||
label: 'Drafts',
|
||||
icon: Edit,
|
||||
folder: 'Drafts'
|
||||
},
|
||||
{
|
||||
view: 'spam' as MailView,
|
||||
label: 'Spam',
|
||||
icon: AlertOctagon,
|
||||
folder: 'Spam'
|
||||
},
|
||||
{
|
||||
view: 'trash' as MailView,
|
||||
label: 'Trash',
|
||||
icon: Trash,
|
||||
folder: 'Trash'
|
||||
},
|
||||
{
|
||||
view: 'archives' as MailView,
|
||||
label: 'Archives',
|
||||
icon: Archive,
|
||||
folder: 'Archives'
|
||||
}
|
||||
];
|
||||
|
||||
export default function MailPage() {
|
||||
const router = useRouter();
|
||||
const [loading, setLoading] = useState(true);
|
||||
@ -437,7 +487,7 @@ export default function MailPage() {
|
||||
{ id: 1, name: 'Mail', email: 'alma@governance-labs.org', color: 'bg-blue-500' }
|
||||
]);
|
||||
const [selectedAccount, setSelectedAccount] = useState<Account | null>(null);
|
||||
const [currentView, setCurrentView] = useState('inbox');
|
||||
const [currentView, setCurrentView] = useState<MailView>('inbox');
|
||||
const [showCompose, setShowCompose] = useState(false);
|
||||
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
|
||||
const [selectedEmails, setSelectedEmails] = useState<string[]>([]);
|
||||
@ -476,27 +526,28 @@ export default function MailPage() {
|
||||
console.log('Selected account:', selectedAccount);
|
||||
}, [emails, currentView, selectedAccount]);
|
||||
|
||||
// Update the filteredEmails logic
|
||||
// Update the filteredEmails logic to match exactly with the folders
|
||||
const filteredEmails = useMemo(() => {
|
||||
console.log('Filtering emails:', {
|
||||
total: emails.length,
|
||||
folders: emails.map(e => e.folder),
|
||||
byFolder: emails.reduce((acc, email) => {
|
||||
acc[email.folder] = (acc[email.folder] || 0) + 1;
|
||||
return acc;
|
||||
}, {} as Record<string, number>),
|
||||
currentView
|
||||
});
|
||||
|
||||
// Find the current nav item
|
||||
const currentNavItem = sidebarNavItems.find(item => item.view === currentView);
|
||||
|
||||
// If it's starred view, filter by starred flag
|
||||
if (currentView === 'starred') {
|
||||
return emails.filter(email => email.starred);
|
||||
}
|
||||
|
||||
// Otherwise filter by folder
|
||||
return emails.filter(email => {
|
||||
switch (currentView) {
|
||||
case 'inbox':
|
||||
return email.folder === 'INBOX' && !email.draft;
|
||||
case 'starred':
|
||||
return Boolean(email.starred);
|
||||
case 'sent':
|
||||
return email.folder === 'Sent';
|
||||
case 'trash':
|
||||
return email.folder === 'Trash';
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
return email.folder === currentNavItem?.folder;
|
||||
});
|
||||
}, [emails, currentView]);
|
||||
|
||||
@ -968,6 +1019,40 @@ export default function MailPage() {
|
||||
);
|
||||
};
|
||||
|
||||
// Render the sidebar navigation
|
||||
const renderSidebarNav = () => (
|
||||
<nav className="p-3">
|
||||
<ul className="space-y-0.5 px-2">
|
||||
{sidebarNavItems.map((item) => (
|
||||
<li key={item.view}>
|
||||
<Button
|
||||
variant={currentView === item.view ? 'secondary' : 'ghost'}
|
||||
className={`w-full justify-start py-2 ${
|
||||
currentView === item.view ? 'bg-gray-100 text-gray-900' : 'text-gray-600 hover:text-gray-900'
|
||||
}`}
|
||||
onClick={() => {
|
||||
setCurrentView(item.view);
|
||||
setSelectedEmail(null);
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center justify-between w-full">
|
||||
<div className="flex items-center">
|
||||
<item.icon className="h-4 w-4 mr-2" />
|
||||
<span>{item.label}</span>
|
||||
</div>
|
||||
{item.view === 'inbox' && unreadCount > 0 && (
|
||||
<span className="ml-auto bg-blue-600 text-white text-xs px-2 py-0.5 rounded-full">
|
||||
{unreadCount}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</Button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</nav>
|
||||
);
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="flex h-[calc(100vh-theme(spacing.12))] items-center justify-center bg-gray-100 mt-12">
|
||||
@ -1058,67 +1143,7 @@ export default function MailPage() {
|
||||
</div>
|
||||
|
||||
{/* Navigation */}
|
||||
<nav className="p-3">
|
||||
<ul className="space-y-0.5 px-2">
|
||||
<li>
|
||||
<Button
|
||||
variant={currentView === 'inbox' ? 'secondary' : 'ghost'}
|
||||
className={`w-full justify-start py-2 ${
|
||||
currentView === 'inbox' ? 'bg-gray-100 text-gray-900' : 'text-gray-600 hover:text-gray-900'
|
||||
}`}
|
||||
onClick={() => {setCurrentView('inbox'); setSelectedEmail(null);}}
|
||||
>
|
||||
<div className="flex items-center justify-between w-full">
|
||||
<div className="flex items-center">
|
||||
<Inbox className="h-4 w-4 mr-2" />
|
||||
<span>Inbox</span>
|
||||
</div>
|
||||
{unreadCount > 0 && (
|
||||
<span className="ml-auto bg-blue-600 text-white text-xs px-2 py-0.5 rounded-full">
|
||||
{unreadCount}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</Button>
|
||||
</li>
|
||||
<li>
|
||||
<Button
|
||||
variant={currentView === 'starred' ? 'secondary' : 'ghost'}
|
||||
className={`w-full justify-start py-2 ${
|
||||
currentView === 'starred' ? 'bg-gray-100 text-gray-900' : 'text-gray-600 hover:text-gray-900'
|
||||
}`}
|
||||
onClick={() => {setCurrentView('starred'); setSelectedEmail(null);}}
|
||||
>
|
||||
<Star className="h-4 w-4 mr-2" />
|
||||
<span>Starred</span>
|
||||
</Button>
|
||||
</li>
|
||||
<li>
|
||||
<Button
|
||||
variant={currentView === 'sent' ? 'secondary' : 'ghost'}
|
||||
className={`w-full justify-start py-2 ${
|
||||
currentView === 'sent' ? 'bg-gray-100 text-gray-900' : 'text-gray-600 hover:text-gray-900'
|
||||
}`}
|
||||
onClick={() => {setCurrentView('sent'); setSelectedEmail(null);}}
|
||||
>
|
||||
<Send className="h-4 w-4 mr-2" />
|
||||
<span>Sent</span>
|
||||
</Button>
|
||||
</li>
|
||||
<li>
|
||||
<Button
|
||||
variant={currentView === 'trash' ? 'secondary' : 'ghost'}
|
||||
className={`w-full justify-start py-2 ${
|
||||
currentView === 'trash' ? 'bg-gray-100 text-gray-900' : 'text-gray-600 hover:text-gray-900'
|
||||
}`}
|
||||
onClick={() => {setCurrentView('trash'); setSelectedEmail(null);}}
|
||||
>
|
||||
<Trash className="h-4 w-4 mr-2" />
|
||||
<span>Trash</span>
|
||||
</Button>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
{renderSidebarNav()}
|
||||
</div>
|
||||
|
||||
{/* Main content area */}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user