mail page ui correction maj compose 20 bis 13

This commit is contained in:
alma 2025-04-16 14:32:41 +02:00
parent ca3d1d832b
commit a224c152b6
2 changed files with 118 additions and 113 deletions

View File

@ -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

View File

@ -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 */}