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