'use client'; import React, { useState, useEffect } from 'react'; import { useRouter } from 'next/navigation'; import { useSession } from 'next-auth/react'; import { Mail, Loader2, AlertCircle, MoreVertical, Settings, Plus as PlusIcon, Trash2, Edit, Inbox, Send, Star, Trash, Plus, ChevronLeft, ChevronRight, Search, ChevronDown, Folder, ChevronUp, Reply, Forward, ReplyAll, MoreHorizontal, FolderOpen, X, Paperclip, MessageSquare, Copy, EyeOff, AlertOctagon, Archive, RefreshCw } from 'lucide-react'; import { Dialog, DialogContent } from '@/components/ui/dialog'; import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { ScrollArea } from '@/components/ui/scroll-area'; import { Avatar, AvatarFallback } from '@/components/ui/avatar'; import { Button } from '@/components/ui/button'; // Import components import EmailSidebar from '@/components/email/EmailSidebar'; import EmailList from '@/components/email/EmailList'; import EmailSidebarContent from '@/components/email/EmailSidebarContent'; import EmailDetailView from '@/components/email/EmailDetailView'; import ComposeEmail from '@/components/email/ComposeEmail'; import { DeleteConfirmDialog, LoginNeededAlert } from '@/components/email/EmailDialogs'; // Import the custom hook import { useCourrier, EmailData } from '@/hooks/use-courrier'; // Import the prefetching function import { prefetchFolderEmails } from '@/lib/services/prefetch-service'; // Import the RedisCacheStatus component import { RedisCacheStatus } from '@/components/debug/RedisCacheStatus'; // Simplified version for this component function SimplifiedLoadingFix() { // In production, don't render anything if (process.env.NODE_ENV === 'production') { return null; } // Simple debugging component return (
Debug: Email app loaded
); } interface Account { id: number; name: string; email: string; color: string; folders?: string[]; } export default function CourrierPage() { const router = useRouter(); const { data: session } = useSession(); // Get all the email functionality from the hook const { emails = [], selectedEmail, selectedEmailIds, currentFolder, mailboxes, isLoading, isSending, error, searchQuery, page, totalPages, loadEmails, handleEmailSelect, markEmailAsRead, toggleStarred, sendEmail, deleteEmails, toggleEmailSelection, toggleSelectAll, changeFolder, searchEmails, formatEmailForAction, setPage, } = useCourrier(); // UI state const [showComposeModal, setShowComposeModal] = useState(false); const [composeType, setComposeType] = useState<'new' | 'reply' | 'reply-all' | 'forward'>('new'); const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); const [showLoginNeeded, setShowLoginNeeded] = useState(false); const [sidebarOpen, setSidebarOpen] = useState(true); const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false); const [accountsDropdownOpen, setAccountsDropdownOpen] = useState(true); const [currentView, setCurrentView] = useState('INBOX'); const [unreadCount, setUnreadCount] = useState(0); const [loading, setLoading] = useState(false); const [prefetchStarted, setPrefetchStarted] = useState(false); const [showFolders, setShowFolders] = useState(true); // Mock accounts for the sidebar const [accounts, setAccounts] = useState([ { id: 0, name: 'All', email: '', color: 'bg-gray-500' }, { id: 1, name: 'Mail', email: 'user@example.com', color: 'bg-blue-500', folders: mailboxes } ]); const [selectedAccount, setSelectedAccount] = useState(null); // Update account folders when mailboxes change useEffect(() => { setAccounts(prev => { const updated = [...prev]; if (updated[1]) { updated[1].folders = mailboxes; } return updated; }); }, [mailboxes]); // Calculate unread count (this would be replaced with actual data in production) useEffect(() => { // Example: counting unread emails in the inbox const unreadInInbox = (emails || []).filter(email => !email.read && currentFolder === 'INBOX').length; setUnreadCount(unreadInInbox); }, [emails, currentFolder]); // Initialize session and start prefetching useEffect(() => { // Flag to prevent multiple initialization attempts let isMounted = true; let initAttempted = false; const initSession = async () => { if (initAttempted) return; initAttempted = true; try { setLoading(true); // First check if Redis is ready before making API calls const redisStatus = await fetch('/api/redis/status') .then(res => res.json()) .catch(() => ({ ready: false })); if (!isMounted) return; // Call the session API to check email credentials and start prefetching const response = await fetch('/api/courrier/session'); const data = await response.json(); if (!isMounted) return; if (data.authenticated) { if (data.hasEmailCredentials) { console.log('Session initialized, prefetch status:', data.prefetchStarted ? 'running' : 'not started'); setPrefetchStarted(Boolean(data.prefetchStarted)); // Preload first page of emails for faster initial rendering if (session?.user?.id) { await loadEmails(); // If the user hasn't opened this page recently, trigger a background refresh if (data.lastVisit && Date.now() - data.lastVisit > 5 * 60 * 1000) { // It's been more than 5 minutes, refresh in background try { const refreshResponse = await fetch('/api/courrier/refresh', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ folder: currentFolder }) }); console.log('Background refresh triggered'); } catch (error) { console.error('Failed to trigger background refresh', error); } } } } else { // User is authenticated but doesn't have email credentials setShowLoginNeeded(true); } } } catch (error) { console.error('Error initializing session:', error); } finally { if (isMounted) { setLoading(false); } } }; if (session?.user?.id) { initSession(); } return () => { isMounted = false; }; }, [session?.user?.id, loadEmails, currentFolder]); // Helper to get folder icons const getFolderIcon = (folder: string) => { const folderLower = folder.toLowerCase(); if (folderLower.includes('inbox')) { return Inbox; } else if (folderLower.includes('sent')) { return Send; } else if (folderLower.includes('trash')) { return Trash; } else if (folderLower.includes('archive')) { return Archive; } else if (folderLower.includes('draft')) { return Edit; } else if (folderLower.includes('spam') || folderLower.includes('junk')) { return AlertOctagon; } else { return Folder; } }; // Helper to format folder names const formatFolderName = (folder: string) => { return folder.charAt(0).toUpperCase() + folder.slice(1).toLowerCase(); }; // Check for more emails const hasMoreEmails = page < totalPages; // Handle loading more emails on scroll const handleLoadMore = () => { if (hasMoreEmails && !isLoading) { // Increment the page const nextPage = page + 1; setPage(nextPage); console.log(`Requesting page ${nextPage} for folder ${currentFolder}`); // Immediately trigger a load for this page rather than relying on the useEffect // This helps ensure we get the data faster loadEmails(true).catch(error => { console.error(`Error loading page ${nextPage}:`, error); }); // Also prefetch additional pages to make scrolling smoother if (session?.user?.id) { // Prefetch next page beyond the one we're loading const pagesToPrefetch = 2; // Prefetch 2 pages ahead // Small delay to let the current request start first setTimeout(() => { console.log(`Prefetching pages ${nextPage + 1} to ${nextPage + pagesToPrefetch}`); prefetchFolderEmails(session.user.id, currentFolder, pagesToPrefetch, nextPage + 1) .catch(err => { console.error(`Error prefetching additional pages for ${currentFolder}:`, err); }); }, 200); } } }; // Handle bulk actions const handleBulkAction = async (action: 'delete' | 'mark-read' | 'mark-unread' | 'archive') => { if (selectedEmailIds.length === 0) return; switch (action) { case 'delete': setShowDeleteConfirm(true); break; case 'mark-read': // Mark all selected emails as read for (const emailId of selectedEmailIds) { await markEmailAsRead(emailId, true); } break; case 'mark-unread': // Mark all selected emails as unread for (const emailId of selectedEmailIds) { await markEmailAsRead(emailId, false); } break; case 'archive': // Archive functionality would be implemented here break; } }; // Handle email actions const handleReply = () => { if (!selectedEmail) return; setComposeType('reply'); setShowComposeModal(true); }; const handleReplyAll = () => { if (!selectedEmail) return; setComposeType('reply-all'); setShowComposeModal(true); }; const handleForward = () => { if (!selectedEmail) return; setComposeType('forward'); setShowComposeModal(true); }; const handleComposeNew = () => { setComposeType('new'); setShowComposeModal(true); }; // Handle mailbox change with prefetching const handleMailboxChange = (folder: string) => { // Reset to page 1 when changing folders setPage(1); // Change folder in the state changeFolder(folder); setCurrentView(folder); // Start prefetching additional pages for this folder if (session?.user?.id && folder) { // First two pages are most important - prefetch immediately prefetchFolderEmails(session.user.id, folder, 3).catch(err => { console.error(`Error prefetching ${folder}:`, err); }); } }; // Handle sending email const handleSendEmail = async (emailData: EmailData) => { return await sendEmail(emailData); }; // Handle delete confirmation const handleDeleteConfirm = async () => { await deleteEmails(selectedEmailIds); setShowDeleteConfirm(false); }; // Check login on mount useEffect(() => { // Check if the user is logged in after a short delay const timer = setTimeout(() => { if (error?.includes('Not authenticated') || error?.includes('No email credentials found')) { setShowLoginNeeded(true); } }, 2000); return () => clearTimeout(timer); }, [error]); // Go to login page const handleGoToLogin = () => { router.push('/courrier/login'); }; return ( <> {/* Main layout */}
{/* Sidebar */}
{/* Courrier Title */}
COURRIER
{/* Compose button and refresh button */}
{/* Accounts Section */}
{accountsDropdownOpen && (
{accounts.map(account => (
{/* Show folders for email accounts (not for "All" account) without the "Folders" header */} {account.id !== 0 && showFolders && (
{account.folders && account.folders.length > 0 ? ( account.folders.map((folder) => ( )) ) : (
{/* Create placeholder folder items with shimmer effect */} {Array.from({ length: 5 }).map((_, index) => (
))}
)}
)}
))}
)}
{/* Email List and Content View */}
{/* Email List */} {/* Email Content View */}
{selectedEmail ? ( handleEmailSelect('')} onReply={handleReply} onReplyAll={handleReplyAll} onForward={handleForward} onToggleStar={() => toggleStarred(selectedEmail.id)} /> ) : (

Select an email to read

Choose an email from the list or compose a new message to get started.

)}
{/* Login needed alert */} setShowLoginNeeded(false)} /> {/* Compose Modal */} {showComposeModal && ( setShowComposeModal(false)} onSend={async (emailData: EmailData) => { await sendEmail(emailData); }} /> )} {/* Delete Confirmation Dialog */} setShowDeleteConfirm(false)} /> ); }