panel 2 courier api restore

This commit is contained in:
alma 2025-04-25 20:49:21 +02:00
parent 522683b599
commit a9beba1bd9
2 changed files with 335 additions and 180 deletions

View File

@ -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 (
<div className="fixed bottom-4 right-4 z-50 p-4 bg-white shadow-lg rounded-lg border border-gray-200">
<div className="text-sm font-medium mb-2">Debug Tools</div>
<div className="flex flex-col gap-2">
<div className="flex items-center text-xs">
<span className="inline-block w-28">Loading State:</span>
{loading ? (
<span className="text-yellow-500 flex items-center">
<AlertCircle className="h-3 w-3 mr-1" /> Active
</span>
) : (
<span className="text-green-500 flex items-center">
<CheckCircle className="h-3 w-3 mr-1" /> Inactive
</span>
)}
</div>
<div className="flex items-center text-xs">
<span className="inline-block w-28">Initial Loading:</span>
{isLoadingInitial ? (
<span className="text-yellow-500 flex items-center">
<AlertCircle className="h-3 w-3 mr-1" /> Active
</span>
) : (
<span className="text-green-500 flex items-center">
<CheckCircle className="h-3 w-3 mr-1" /> Inactive
</span>
)}
</div>
<div className="flex items-center text-xs">
<span className="inline-block w-28">Emails Loaded:</span>
<span className={emails.length > 0 ? "text-green-500" : "text-red-500"}>
{emails.length}
</span>
</div>
<Button
variant="outline"
size="sm"
className="text-xs h-8"
onClick={forceResetLoadingStates}
>
Reset Loading States
</Button>
<Button
variant="outline"
size="sm"
className="text-xs h-8"
onClick={forceTriggerLoad}
>
Force Reload Emails
</Button>
<Button
variant="outline"
size="sm"
className="text-xs h-8"
onClick={resetEmailState}
>
Reset Email State
</Button>
</div>
</div>
);
}

View File

@ -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() {
<div className="flex flex-col items-center">
<div className="animate-spin rounded-full h-8 w-8 border-t-2 border-b-2 border-blue-500 mb-4"></div>
<p className="text-sm text-gray-500">Loading emails...</p>
<p className="text-xs text-gray-400 mt-2">
{loading ? 'Loading state: true' : ''}
{isLoadingInitial ? 'Loading initial: true' : ''}
</p>
</div>
</div>
) : 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' && (
<LoadingFix
loading={loading}
isLoadingInitial={isLoadingInitial}
setLoading={setLoading}
setIsLoadingInitial={setIsLoadingInitial}
setEmails={setEmails}
loadEmails={loadEmails}
emails={emails}
/>
)}
</>
);
}