From a9beba1bd9afd04576b8bbefaadca2c88cdb6381 Mon Sep 17 00:00:00 2001 From: alma Date: Fri, 25 Apr 2025 20:49:21 +0200 Subject: [PATCH] panel 2 courier api restore --- app/courrier/loading-fix.tsx | 113 ++++++++++ app/courrier/page.tsx | 402 +++++++++++++++++++---------------- 2 files changed, 335 insertions(+), 180 deletions(-) create mode 100644 app/courrier/loading-fix.tsx diff --git a/app/courrier/loading-fix.tsx b/app/courrier/loading-fix.tsx new file mode 100644 index 00000000..0f7d3075 --- /dev/null +++ b/app/courrier/loading-fix.tsx @@ -0,0 +1,113 @@ +/** + * This is a debugging component that provides troubleshooting tools + * for the email loading process in the Courrier application. + */ +'use client'; + +import { Button } from '@/components/ui/button'; +import { RefreshCw, AlertCircle, CheckCircle } from 'lucide-react'; + +interface LoadingFixProps { + loading: boolean; + isLoadingInitial: boolean; + setLoading: (value: boolean) => void; + setIsLoadingInitial: (value: boolean) => void; + setEmails: (emails: any[]) => void; + loadEmails: () => void; + emails: any[]; +} + +export function LoadingFix({ + loading, + isLoadingInitial, + setLoading, + setIsLoadingInitial, + setEmails, + loadEmails, + emails +}: LoadingFixProps) { + const forceResetLoadingStates = () => { + console.log('[DEBUG] Force resetting loading states to false'); + // Force both loading states to false + setLoading(false); + setIsLoadingInitial(false); + }; + + const forceTriggerLoad = () => { + console.log('[DEBUG] Force triggering a new email load'); + setLoading(true); + setTimeout(() => { + loadEmails(); + }, 100); + }; + + const resetEmailState = () => { + console.log('[DEBUG] Resetting email state to empty array'); + setEmails([]); + setTimeout(() => { + forceTriggerLoad(); + }, 100); + }; + + return ( +
+
Debug Tools
+
+
+ Loading State: + {loading ? ( + + Active + + ) : ( + + Inactive + + )} +
+
+ Initial Loading: + {isLoadingInitial ? ( + + Active + + ) : ( + + Inactive + + )} +
+
+ Emails Loaded: + 0 ? "text-green-500" : "text-red-500"}> + {emails.length} + +
+ + + +
+
+ ); +} \ No newline at end of file diff --git a/app/courrier/page.tsx b/app/courrier/page.tsx index 879fb789..a9bd1839 100644 --- a/app/courrier/page.tsx +++ b/app/courrier/page.tsx @@ -33,6 +33,7 @@ import DOMPurify from 'isomorphic-dompurify'; import ComposeEmail from '@/components/ComposeEmail'; import { decodeEmail, cleanHtml } from '@/lib/mail-parser-wrapper'; import { Attachment as MailParserAttachment } from 'mailparser'; +import { LoadingFix } from './loading-fix'; export interface Account { id: number; @@ -585,15 +586,17 @@ export default function CourrierPage() { useEffect(() => { const loadInitialData = async () => { try { - console.log('Loading initial email data...'); + console.log('[DEBUG] Starting initial email data loading...'); setLoading(true); setIsLoadingInitial(true); // Check credentials first + console.log('[DEBUG] Checking credentials...'); const credResponse = await fetch('/api/courrier'); if (!credResponse.ok) { const errorData = await credResponse.json(); if (errorData.error === 'No stored credentials found') { + console.log('[DEBUG] No credentials found, redirecting to login'); router.push('/courrier/login'); return; } @@ -603,8 +606,13 @@ export default function CourrierPage() { try { // Try to get user email from credentials const credsData = await credResponse.json(); + console.log('[DEBUG] Credentials response:', { + hasEmail: !!credsData.email, + status: credResponse.status + }); + if (credsData.email) { - console.log('Got email from credentials:', credsData.email); + console.log('[DEBUG] Got email from credentials:', credsData.email); setAccounts(prev => prev.map(account => account.id === 1 ? { @@ -616,15 +624,20 @@ export default function CourrierPage() { )); } } catch (error) { - console.warn('Error getting email from credentials:', error); + console.warn('[DEBUG] Error getting email from credentials:', error); } // First do a quick request just for folders try { + console.log('[DEBUG] Preloading folders...'); const folderResponse = await fetch('/api/courrier?folder=INBOX&page=1&limit=1'); if (folderResponse.ok) { const folderData = await folderResponse.json(); - console.log('Preloading folders:', folderData.folders); + console.log('[DEBUG] Folder data:', { + folders: folderData.folders?.length || 0, + emails: folderData.emails?.length || 0 + }); + if (folderData.folders && folderData.folders.length > 0) { setAvailableFolders(folderData.folders); setAccounts(prev => prev.map(account => @@ -635,10 +648,11 @@ export default function CourrierPage() { } } } catch (error) { - console.warn('Error preloading folders:', error); + console.warn('[DEBUG] Error preloading folders:', error); } // Then load emails (forced fetch with timestamp) + console.log('[DEBUG] Fetching emails...'); const timestamp = Date.now(); const emailResponse = await fetch( `/api/courrier?folder=${encodeURIComponent(currentView)}&page=${page}&limit=${emailsPerPage}&_t=${timestamp}`, @@ -650,20 +664,16 @@ export default function CourrierPage() { } const data = await emailResponse.json(); - console.log(`Loaded ${data.emails?.length || 0} emails`); - console.log('API response data:', { - emailCount: data.emails?.length || 0, - folderCount: data.folders?.length || 0 - }); + console.log(`[DEBUG] Loaded ${data.emails?.length || 0} emails, response status: ${emailResponse.status}`); // Set available folders if present if (data.folders) { - console.log('Setting folders from initialization:', data.folders); + console.log('[DEBUG] Setting folders from initialization:', data.folders.length); setAvailableFolders(data.folders); // Update the mail account with folders setAccounts(prev => { - console.log('Updating accounts with folders'); + console.log('[DEBUG] Updating accounts with folders'); return prev.map(account => account.id === 1 ? { ...account, folders: data.folders } @@ -671,10 +681,11 @@ export default function CourrierPage() { ); }); } else { - console.warn('No folders returned from API during initialization'); + console.warn('[DEBUG] No folders returned from API during initialization'); } // Process emails and sort by date + console.log('[DEBUG] Processing emails...'); const processedEmails = (data.emails || []) .map((email: any) => { // Add proper handling for from field which might be an array or object @@ -772,6 +783,7 @@ export default function CourrierPage() { to: toText, subject: email.subject || '(No subject)', content: email.content || '', + preview: email.preview || '', date: email.date || new Date().toISOString(), read: email.read || false, starred: email.starred || false, @@ -785,6 +797,7 @@ export default function CourrierPage() { .sort((a: Email, b: Email) => new Date(b.date).getTime() - new Date(a.date).getTime()); // Set emails + console.log('[DEBUG] Setting emails state with', processedEmails.length, 'emails'); setEmails(processedEmails); // Update unread count for inbox @@ -798,10 +811,12 @@ export default function CourrierPage() { // Update pagination setHasMore(data.hasMore); setError(null); + console.log('[DEBUG] Initial load complete, setting loading states to false'); } catch (err) { - console.error('Error loading initial data:', err); + console.error('[DEBUG] Error loading initial data:', err); setError(err instanceof Error ? err.message : 'Failed to load data'); } finally { + console.log('[DEBUG] Setting loading state to false in finally block'); setLoading(false); setIsLoadingInitial(false); } @@ -1016,7 +1031,7 @@ export default function CourrierPage() { // Update the email list to use filtered emails const renderEmailList = () => { - console.log('Rendering email list with state:', { + console.log('[DEBUG] Rendering email list with state:', { loading, isLoadingInitial, emailCount: emails.length, @@ -1039,6 +1054,10 @@ export default function CourrierPage() {

Loading emails...

+

+ {loading ? 'Loading state: true' : ''} + {isLoadingInitial ? 'Loading initial: true' : ''} +

) : filteredEmails.length === 0 ? ( @@ -1057,6 +1076,7 @@ export default function CourrierPage() { size="sm" className="mt-5 bg-blue-600 hover:bg-blue-700" onClick={() => { + console.log('[DEBUG] Manual refresh clicked'); setLoading(true); loadEmails(); }} @@ -1637,11 +1657,11 @@ export default function CourrierPage() { try { // Skip if already loading if (isLoadingInitial || isLoadingMore) { - console.log('Skipping loadEmails - already loading'); + console.log('[DEBUG] Skipping loadEmails - already loading'); return; } - console.log(`Loading emails for folder: ${currentView}, page: ${page}, isLoadMore: ${isLoadMore}`); + console.log(`[DEBUG] Loading emails for folder: ${currentView}, page: ${page}, isLoadMore: ${isLoadMore}`); if (isLoadMore) { setIsLoadingMore(true); @@ -1651,175 +1671,184 @@ export default function CourrierPage() { // Fetch emails with timestamp for cache busting const timestamp = Date.now(); - const response = await fetch( - `/api/courrier?folder=${encodeURIComponent(currentView)}&page=${page}&limit=${emailsPerPage}&_t=${timestamp}`, - { cache: 'no-store' } - ); - - if (!response.ok) { - console.error('API response error:', response.status, response.statusText); - throw new Error('Failed to load emails'); - } - - const data = await response.json(); - console.log('API response:', { - emailCount: data.emails?.length || 0, - folderCount: data.folders?.length || 0, - hasMore: data.hasMore, - total: data.total - }); - - // Set available folders - if (data.folders) { - console.log('Setting available folders:', data.folders); - setAvailableFolders(data.folders); + try { + const response = await fetch( + `/api/courrier?folder=${encodeURIComponent(currentView)}&page=${page}&limit=${emailsPerPage}&_t=${timestamp}`, + { cache: 'no-store' } + ); - // Update the mail account with folders - setAccounts(prev => prev.map(account => - account.id === 1 - ? { ...account, folders: data.folders } - : account - )); - } else { - console.warn('No folders returned from API'); - } - - // Process and sort emails - const processedEmails = (data.emails || []) - .map((email: any) => { - // Add proper handling for from field which might be an array or object - let fromText = ''; - let fromName = ''; - let toText = ''; - let ccText = ''; - let bccText = ''; - - // Handle 'from' field - if (email.from) { - if (Array.isArray(email.from)) { - if (email.from.length > 0) { - if (typeof email.from[0] === 'object') { - fromText = email.from[0].address || ''; - fromName = email.from[0].name || email.from[0].address?.split('@')[0] || ''; - } else { - fromText = email.from[0] || ''; - fromName = fromText.split('@')[0] || ''; - } - } - } - else if (typeof email.from === 'object') { - fromText = email.from.address || ''; - fromName = email.from.name || email.from.address?.split('@')[0] || ''; - } - else if (typeof email.from === 'string') { - fromText = email.from; - fromName = email.fromName || email.from.split('@')[0] || ''; - } - } - - // Handle 'to' field - if (email.to) { - if (Array.isArray(email.to)) { - if (email.to.length > 0) { - if (typeof email.to[0] === 'object') { - toText = email.to.map((t: any) => t.address || '').join(', '); - } else { - toText = email.to.join(', '); - } - } - } - else if (typeof email.to === 'object') { - toText = email.to.address || ''; - } - else if (typeof email.to === 'string') { - toText = email.to; - } - } - - // Handle 'cc' field - if (email.cc) { - if (Array.isArray(email.cc)) { - if (email.cc.length > 0) { - if (typeof email.cc[0] === 'object') { - ccText = email.cc.map((c: any) => c.address || '').join(', '); - } else { - ccText = email.cc.join(', '); - } - } - } - else if (typeof email.cc === 'object') { - ccText = email.cc.address || ''; - } - else if (typeof email.cc === 'string') { - ccText = email.cc; - } - } - - // Handle 'bcc' field - if (email.bcc) { - if (Array.isArray(email.bcc)) { - if (email.bcc.length > 0) { - if (typeof email.bcc[0] === 'object') { - bccText = email.bcc.map((b: any) => b.address || '').join(', '); - } else { - bccText = email.bcc.join(', '); - } - } - } - else if (typeof email.bcc === 'object') { - bccText = email.bcc.address || ''; - } - else if (typeof email.bcc === 'string') { - bccText = email.bcc; - } - } - - return { - id: email.id, - accountId: 1, - from: fromText, - fromName: fromName, - to: toText, - subject: email.subject || '(No subject)', - content: email.content || '', - date: email.date || new Date().toISOString(), - read: email.read || false, - starred: email.starred || false, - folder: email.folder || currentView, - cc: ccText, - bcc: bccText, - flags: email.flags || [], - hasAttachments: email.hasAttachments || false - }; - }) - .sort((a: Email, b: Email) => new Date(b.date).getTime() - new Date(a.date).getTime()); - - // Set emails appropriately - setEmails(prev => { - if (isLoadMore) { - // Filter out duplicates when appending - const existingIds = new Set(prev.map(email => email.id)); - const uniqueNewEmails = processedEmails.filter((email: Email) => !existingIds.has(email.id)); - return [...prev, ...uniqueNewEmails]; - } else { - return processedEmails; + if (!response.ok) { + console.error('[DEBUG] API response error:', response.status, response.statusText); + throw new Error('Failed to load emails'); } - }); - - // Update unread count - if (currentView === 'INBOX') { - const unreadInboxEmails = processedEmails.filter( - (email: Email) => !email.read && email.folder === 'INBOX' - ).length; - setUnreadCount(unreadInboxEmails); + + const data = await response.json(); + console.log('[DEBUG] API response:', { + emailCount: data.emails?.length || 0, + folderCount: data.folders?.length || 0, + hasMore: data.hasMore, + total: data.total + }); + + // Set available folders + if (data.folders) { + console.log('[DEBUG] Setting available folders:', data.folders.length); + setAvailableFolders(data.folders); + + // Update the mail account with folders + setAccounts(prev => prev.map(account => + account.id === 1 + ? { ...account, folders: data.folders } + : account + )); + } else { + console.warn('[DEBUG] No folders returned from API'); + } + + // Process and sort emails + const processedEmails = (data.emails || []) + .map((email: any) => { + // Add proper handling for from field which might be an array or object + let fromText = ''; + let fromName = ''; + let toText = ''; + let ccText = ''; + let bccText = ''; + + // Handle 'from' field + if (email.from) { + if (Array.isArray(email.from)) { + if (email.from.length > 0) { + if (typeof email.from[0] === 'object') { + fromText = email.from[0].address || ''; + fromName = email.from[0].name || email.from[0].address?.split('@')[0] || ''; + } else { + fromText = email.from[0] || ''; + fromName = fromText.split('@')[0] || ''; + } + } + } + else if (typeof email.from === 'object') { + fromText = email.from.address || ''; + fromName = email.from.name || email.from.address?.split('@')[0] || ''; + } + else if (typeof email.from === 'string') { + fromText = email.from; + fromName = email.fromName || email.from.split('@')[0] || ''; + } + } + + // Handle 'to' field + if (email.to) { + if (Array.isArray(email.to)) { + if (email.to.length > 0) { + if (typeof email.to[0] === 'object') { + toText = email.to.map((t: any) => t.address || '').join(', '); + } else { + toText = email.to.join(', '); + } + } + } + else if (typeof email.to === 'object') { + toText = email.to.address || ''; + } + else if (typeof email.to === 'string') { + toText = email.to; + } + } + + // Handle 'cc' field + if (email.cc) { + if (Array.isArray(email.cc)) { + if (email.cc.length > 0) { + if (typeof email.cc[0] === 'object') { + ccText = email.cc.map((c: any) => c.address || '').join(', '); + } else { + ccText = email.cc.join(', '); + } + } + } + else if (typeof email.cc === 'object') { + ccText = email.cc.address || ''; + } + else if (typeof email.cc === 'string') { + ccText = email.cc; + } + } + + // Handle 'bcc' field + if (email.bcc) { + if (Array.isArray(email.bcc)) { + if (email.bcc.length > 0) { + if (typeof email.bcc[0] === 'object') { + bccText = email.bcc.map((b: any) => b.address || '').join(', '); + } else { + bccText = email.bcc.join(', '); + } + } + } + else if (typeof email.bcc === 'object') { + bccText = email.bcc.address || ''; + } + else if (typeof email.bcc === 'string') { + bccText = email.bcc; + } + } + + return { + id: email.id, + accountId: 1, + from: fromText, + fromName: fromName, + to: toText, + subject: email.subject || '(No subject)', + content: email.content || '', + preview: email.preview || '', + date: email.date || new Date().toISOString(), + read: email.read || false, + starred: email.starred || false, + folder: email.folder || currentView, + cc: ccText, + bcc: bccText, + flags: email.flags || [], + hasAttachments: email.hasAttachments || false + }; + }) + .sort((a: Email, b: Email) => new Date(b.date).getTime() - new Date(a.date).getTime()); + + // Set emails appropriately + console.log('[DEBUG] Setting emails state with', processedEmails.length, 'emails'); + setEmails(prev => { + if (isLoadMore) { + // Filter out duplicates when appending + const existingIds = new Set(prev.map(email => email.id)); + const uniqueNewEmails = processedEmails.filter((email: Email) => !existingIds.has(email.id)); + return [...prev, ...uniqueNewEmails]; + } else { + return processedEmails; + } + }); + + // Update unread count + if (currentView === 'INBOX') { + const unreadInboxEmails = processedEmails.filter( + (email: Email) => !email.read && email.folder === 'INBOX' + ).length; + setUnreadCount(unreadInboxEmails); + } + + setHasMore(data.hasMore); + setError(null); + } catch (err) { + console.error('[DEBUG] Error in fetch emails:', err); + setError('Failed to load emails'); + throw err; // Rethrow to ensure the finally block still runs } - - setHasMore(data.hasMore); - setError(null); } catch (err) { - console.error('Error loading emails:', err); + console.error('[DEBUG] Error loading emails:', err); setError('Failed to load emails'); } finally { + console.log('[DEBUG] Setting loading states to false in loadEmails finally block'); setLoading(false); setIsLoadingMore(false); setIsLoadingInitial(false); @@ -2146,6 +2175,19 @@ export default function CourrierPage() { }} /> {renderDeleteConfirmDialog()} + + {/* Debug tools - only shown in development mode */} + {process.env.NODE_ENV !== 'production' && ( + + )} ); } \ No newline at end of file