From 50d9be0d21a1a3b9adb96a494533d715dadae68a Mon Sep 17 00:00:00 2001 From: alma Date: Tue, 15 Apr 2025 20:45:04 +0200 Subject: [PATCH] mail page imap connection 5 --- app/mail/page.tsx | 575 ++++++---------------------------------------- 1 file changed, 68 insertions(+), 507 deletions(-) diff --git a/app/mail/page.tsx b/app/mail/page.tsx index 0e141f4..8c07db7 100644 --- a/app/mail/page.tsx +++ b/app/mail/page.tsx @@ -49,17 +49,13 @@ interface Mailbox { } export default function MailPage() { - // Single account for now since we're using IMAP - const [accounts] = useState([ + // Single IMAP account for now + const [accounts, setAccounts] = useState([ { id: 1, name: 'Work', email: 'contact@governance-labs.org', color: 'bg-blue-500' } ]); - const [emails, setEmails] = useState([]); - const [mailboxes, setMailboxes] = useState([]); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); - - const [selectedAccount] = useState(1); // Only one account for now + // State declarations + const [selectedAccount, setSelectedAccount] = useState(1); const [currentView, setCurrentView] = useState('inbox'); const [selectedEmail, setSelectedEmail] = useState(null); const [sidebarOpen, setSidebarOpen] = useState(true); @@ -76,6 +72,9 @@ export default function MailPage() { const [showBulkActions, setShowBulkActions] = useState(false); const [showCc, setShowCc] = useState(false); const [showBcc, setShowBcc] = useState(false); + const [emails, setEmails] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); // Fetch emails from IMAP API useEffect(() => { @@ -103,34 +102,39 @@ export default function MailPage() { fetchEmails(); }, [currentView]); // Refetch when view changes - // Fetch mailboxes from IMAP API - useEffect(() => { - async function fetchMailboxes() { - try { - const res = await fetch('/api/mail', { method: 'POST' }); - if (!res.ok) { - throw new Error('Failed to fetch mailboxes'); - } - const data = await res.json(); - if (data.error) { - throw new Error(data.error); - } - setMailboxes(data.mailboxes || []); - } catch (error) { - console.error('Error fetching mailboxes:', error); - } - } + // Mock folders data - will be replaced with IMAP folders later + const folders = [ + { id: 1, name: 'Important' }, + { id: 2, name: 'Work' }, + { id: 3, name: 'Personal' }, + { id: 4, name: 'Archive' } + ]; - fetchMailboxes(); - }, []); + // Modified accounts array with "All" option + const allAccounts = [ + { id: 0, name: 'All', email: '', color: 'bg-gray-500' }, + ...accounts + ]; - // Filter emails based on current view + // Filter emails based on selected account and view const filteredEmails = emails.filter(email => - currentView === 'starred' ? email.starred : email.category === currentView + (selectedAccount === 0 || email.accountId === selectedAccount) && + (currentView === 'starred' ? email.starred : email.category === currentView) ); // Handle email selection - const handleEmailClick = (emailId: number) => { + const handleEmailClick = async (emailId: number) => { + // Mark as read in IMAP + try { + await fetch('/api/mail/mark-read', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ emailId }) + }); + } catch (error) { + console.error('Error marking email as read:', error); + } + const updatedEmails = emails.map(email => email.id === emailId ? { ...email, read: true } : email ); @@ -141,493 +145,50 @@ export default function MailPage() { // Toggle starred status const toggleStarred = async (emailId: number, e: React.MouseEvent) => { e.stopPropagation(); - // TODO: Implement IMAP flag toggle + + // Toggle star in IMAP + try { + await fetch('/api/mail/toggle-star', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ emailId }) + }); + } catch (error) { + console.error('Error toggling star:', error); + } + const updatedEmails = emails.map(email => email.id === emailId ? { ...email, starred: !email.starred } : email ); setEmails(updatedEmails); }; - // 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' }); - } - }; - - // Get selected email - const getSelectedEmail = () => { - return emails.find(email => email.id === selectedEmail); - }; - - // Get account color - const getAccountColor = (accountId: number) => { - const account = accounts.find(acc => acc.id === accountId); - return account ? account.color : 'bg-gray-500'; - }; - - // Handle bulk selection - const toggleEmailSelection = (emailId: number, e: React.MouseEvent) => { - e.stopPropagation(); - setSelectedEmails(prev => - prev.includes(emailId) - ? prev.filter(id => id !== emailId) - : [...prev, emailId] - ); - setShowBulkActions(true); - }; - - // Handle select all - const toggleSelectAll = () => { - if (selectedEmails.length === filteredEmails.length) { - setSelectedEmails([]); - setShowBulkActions(false); - } else { - setSelectedEmails(filteredEmails.map(email => email.id)); - setShowBulkActions(true); - } - }; - - // Handle bulk delete - const handleBulkDelete = () => { - setDeleteType('emails'); - setShowDeleteConfirm(true); - }; - // Handle delete confirmation const handleDeleteConfirm = async () => { - // TODO: Implement IMAP delete - if (deleteType === 'email' && itemToDelete) { - setEmails(emails.filter(email => email.id !== itemToDelete)); - setSelectedEmail(null); - } else if (deleteType === 'emails') { - setEmails(emails.filter(email => !selectedEmails.includes(email.id))); - setSelectedEmails([]); - setShowBulkActions(false); + try { + if (deleteType === 'email' && itemToDelete) { + await fetch('/api/mail/delete', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ emailIds: [itemToDelete] }) + }); + setEmails(emails.filter(email => email.id !== itemToDelete)); + setSelectedEmail(null); + } else if (deleteType === 'emails') { + await fetch('/api/mail/delete', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ emailIds: selectedEmails }) + }); + setEmails(emails.filter(email => !selectedEmails.includes(email.id))); + setSelectedEmails([]); + setShowBulkActions(false); + } + } catch (error) { + console.error('Error deleting emails:', error); } setShowDeleteConfirm(false); }; - // Modified account action handler - const handleAccountAction = (accountId: number, action: 'edit' | 'delete') => { - setShowAccountActions(null); - if (action === 'delete') { - setDeleteType('account'); - setItemToDelete(accountId); - setShowDeleteConfirm(true); - } - }; - - if (loading) { - return ( -
-
- -

Loading your emails...

-
-
- ); - } - - if (error) { - return ( -
-
- -

{error}

- -
-
- ); - } - - return ( -
- {/* Sidebar */} -
- {/* Logo and toggle */} -
- {sidebarOpen &&

Mail

} - -
- - {/* Compose button */} -
- -
- - {/* Navigation */} - - - {/* Account info */} -
-
- - - {accounts[0].email.charAt(0).toUpperCase()} - - - {sidebarOpen && ( -
-

- {accounts[0].name} -

-

- {accounts[0].email} -

-
- )} -
-
-
- - {/* Main content */} -
- {/* Header */} -
-
- -
-
- - -
- -
-
-
- - {/* Email list */} -
- {filteredEmails.length > 0 ? ( -
- {filteredEmails.map((email) => ( -
handleEmailClick(email.id)} - > - toggleEmailSelection(email.id, e)} - className="h-4 w-4" - /> - -
-
-
- {email.fromName} -
-
- {email.subject} - {formatDate(email.date)} -
-
-
- ))} -
- ) : ( -
- -

No emails in this folder

-
- )} -
-
- - {/* Compose email modal */} - {composeOpen && ( -
- - - New Message - - - -
-
- - -
-
-
- -
- {!showCc && ( - - )} - {!showBcc && ( - - )} -
-
- -
- {showCc && ( -
-
- - -
- -
- )} - {showBcc && ( -
-
- - -
- -
- )} -
- - -
-
- -
- -