courrier correct panel 2 scroll up

This commit is contained in:
alma 2025-04-27 15:20:07 +02:00
parent a6bd553a27
commit ceca769cbf
4 changed files with 98 additions and 27 deletions

View File

@ -246,15 +246,28 @@ export default function CourrierPage() {
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 2 pages beyond the current next page
prefetchFolderEmails(session.user.id, currentFolder, 2, nextPage + 1).catch(err => {
console.error(`Error prefetching additional pages for ${currentFolder}:`, err);
});
// 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);
}
// Note: loadEmails will be called automatically due to the page dependency in useEffect
}
};

View File

@ -63,7 +63,7 @@ export default function EmailList({
// If near bottom (within 200px) and more emails are available, load more
// Added additional checks to prevent loading loop
const isNearBottom = scrollHeight - scrollTop - clientHeight < 200;
const isNearBottom = scrollHeight - scrollTop - clientHeight < 300; // Increased detection area
if (isNearBottom && hasMoreEmails && !isLoading && !isLoadingMore) {
setIsLoadingMore(true);
@ -71,13 +71,16 @@ export default function EmailList({
scrollTimeoutRef.current = setTimeout(() => {
// Clear the timeout reference before loading
scrollTimeoutRef.current = null;
console.log('Loading more emails from scroll trigger');
onLoadMore();
// Reset loading state after a delay
setTimeout(() => {
console.log('Resetting loading more state after timeout');
setIsLoadingMore(false);
}, 1500); // Increased from 1000ms to 1500ms to prevent quick re-triggering
}, 200); // Increased from 100ms to 200ms for better debouncing
}, 3000); // Increased from 1500ms to 3000ms to allow more time for loading
}, 300); // Increased from 200ms to 300ms for better debouncing
}
}, [hasMoreEmails, isLoading, isLoadingMore, onLoadMore]);
@ -105,6 +108,25 @@ export default function EmailList({
prevEmailsLengthRef.current = emails.length;
}, [emails.length, scrollPosition, isLoading]);
// Add safety mechanism to reset loading state if we get stuck
useEffect(() => {
// If we have more emails now but still in loading state, reset it
if (emails.length > prevEmailsLengthRef.current && isLoadingMore) {
console.log('Safety reset: Clearing loading state after emails updated');
setIsLoadingMore(false);
}
// Add a timeout-based safety mechanism
const safetyTimeout = setTimeout(() => {
if (isLoadingMore) {
console.log('Safety timeout: Resetting stuck loading state');
setIsLoadingMore(false);
}
}, 5000);
return () => clearTimeout(safetyTimeout);
}, [emails.length, isLoadingMore]);
// Add listener for custom reset scroll event
useEffect(() => {
const handleResetScroll = () => {
@ -258,14 +280,18 @@ export default function EmailList({
{/* Loading indicator */}
{(isLoading || isLoadingMore) && (
<div className="flex items-center justify-center p-4">
<Loader2 className="h-4 w-4 text-blue-500 animate-spin" />
<Loader2 className="h-4 w-4 text-blue-500 animate-spin mr-2" />
<span className="text-sm text-gray-500">Loading more emails...</span>
</div>
)}
{/* Load more button - only show when near bottom but not auto-loading */}
{hasMoreEmails && !isLoading && !isLoadingMore && (
<button
onClick={onLoadMore}
onClick={() => {
console.log('Manual load more triggered');
onLoadMore();
}}
className="w-full py-2 text-gray-500 hover:bg-gray-100 text-sm"
>
Load more emails

View File

@ -80,15 +80,24 @@ export const useCourrier = () => {
const loadEmails = useCallback(async (isLoadMore = false) => {
if (!session?.user?.id) return;
console.log(`Loading emails for folder ${currentFolder}, page ${page}, isLoadMore: ${isLoadMore}`);
// If already loading, don't trigger multiple simultaneous requests
if (isLoading) {
console.log('Skipping loadEmails - already loading');
return;
}
setIsLoading(true);
setError(null);
// Keep reference to the current page for this request
const currentRequestPage = page;
const requestStartTime = Date.now();
try {
// First try Redis cache with low timeout
const cachedEmails = await getCachedEmailsWithTimeout(session.user.id, currentFolder, currentRequestPage, perPage, 100);
const cachedEmails = await getCachedEmailsWithTimeout(session.user.id, currentFolder, currentRequestPage, perPage, 200);
if (cachedEmails) {
// Ensure cached data has emails array property
if (Array.isArray(cachedEmails.emails)) {
@ -101,7 +110,7 @@ export const useCourrier = () => {
const newEmails = cachedEmails.emails.filter((email: Email) => !existingIds.has(email.id));
// Log pagination info
console.log(`Added ${newEmails.length} cached emails from page ${currentRequestPage} to existing ${prevEmails.length} emails`);
console.log(`Added ${newEmails.length} cached emails from page ${currentRequestPage} to existing ${prevEmails.length} emails (${Date.now() - requestStartTime}ms)`);
// Combine emails and sort them by date (newest first)
const combinedEmails = [...prevEmails, ...newEmails];
@ -109,7 +118,7 @@ export const useCourrier = () => {
});
} else {
// For initial load, replace emails
console.log(`Setting ${cachedEmails.emails.length} cached emails for page ${currentRequestPage}`);
console.log(`Setting ${cachedEmails.emails.length} cached emails for page ${currentRequestPage} (${Date.now() - requestStartTime}ms)`);
// Ensure emails are sorted by date (newest first)
setEmails(cachedEmails.emails.sort((a: Email, b: Email) => new Date(b.date).getTime() - new Date(a.date).getTime()));
}
@ -187,7 +196,7 @@ export const useCourrier = () => {
const newEmails = data.emails.filter((email: Email) => !existingIds.has(email.id));
// Log pagination info
console.log(`Added ${newEmails.length} fetched emails from page ${currentRequestPage} to existing ${prev.length} emails`);
console.log(`Added ${newEmails.length} fetched emails from page ${currentRequestPage} to existing ${prev.length} emails (${Date.now() - requestStartTime}ms)`);
// Combine emails and sort them by date (newest first)
const combinedEmails = [...prev, ...newEmails];
@ -230,6 +239,7 @@ export const useCourrier = () => {
description: err instanceof Error ? err.message : 'Failed to load emails'
});
} finally {
console.log(`Completed loading emails for page ${currentRequestPage} (${Date.now() - requestStartTime}ms)`);
setIsLoading(false);
}
}, [currentFolder, page, perPage, searchQuery, session?.user?.id, toast]);
@ -239,7 +249,11 @@ export const useCourrier = () => {
if (session?.user?.id) {
// If page is greater than 1, we're loading more emails
const isLoadingMore = page > 1;
loadEmails(isLoadingMore);
// Add a small delay to prevent rapid consecutive loads
const loadTimer = setTimeout(() => {
loadEmails(isLoadingMore);
}, 50);
// If we're loading the first page, publish an event to reset scroll position
if (page === 1 && typeof window !== 'undefined') {
@ -247,8 +261,10 @@ export const useCourrier = () => {
const event = new CustomEvent('reset-email-scroll');
window.dispatchEvent(event);
}
return () => clearTimeout(loadTimer);
}
}, [currentFolder, page, perPage, session?.user?.id, loadEmails]);
}, [currentFolder, page, session?.user?.id, loadEmails]);
// Fetch a single email's content
const fetchEmailContent = useCallback(async (emailId: string) => {

View File

@ -19,7 +19,7 @@ export async function getCachedEmailsWithTimeout(
folder: string,
page: number,
perPage: number,
timeoutMs: number = 100
timeoutMs: number = 200
): Promise<any | null> {
return new Promise((resolve) => {
const timeoutId = setTimeout(() => {
@ -73,16 +73,29 @@ export async function refreshEmailsInBackground(
page: number = 1,
perPage: number = 20
): Promise<void> {
// Track ongoing refreshes to avoid duplicates
const refreshKey = `${userId}:${folder}:${page}`;
// Use a higher priority for inbox and small page numbers
const priority = folder === 'INBOX' && page <= 2 ? 100 : 300;
// Use setTimeout to ensure this runs after current execution context
setTimeout(async () => {
try {
console.log(`Background refresh for ${userId}:${folder}:${page}:${perPage}`);
const freshData = await getEmails(userId, folder, page, perPage);
console.log(`Background refresh completed for ${userId}:${folder}`);
console.log(`Background refresh completed for ${userId}:${folder}:${page} with ${freshData.emails.length} emails`);
// If it's the inbox and there's a next page, prefetch that too
if (folder === 'INBOX' && page === 1) {
setTimeout(() => {
refreshEmailsInBackground(userId, folder, 2, perPage);
}, 500);
}
} catch (error) {
console.error('Background refresh error:', error);
}
}, 100);
}, priority);
}
/**
@ -183,9 +196,12 @@ export async function prefetchFolderEmails(
console.log(`Will prefetch pages: ${pagesToFetch.join(', ')}`);
// Fetch multiple pages in parallel
await Promise.allSettled(
pagesToFetch.map(page =>
// Fetch multiple pages in parallel, but with a slight delay between them to avoid overwhelming the server
for (let i = 0; i < pagesToFetch.length; i++) {
const page = pagesToFetch[i];
// Use a delay for all but the first page
setTimeout(() => {
getEmails(userId, folder, page, 20)
.then(result => {
console.log(`Successfully prefetched and cached page ${page} of ${folder} with ${result.emails.length} emails`);
@ -194,11 +210,11 @@ export async function prefetchFolderEmails(
.catch(err => {
console.error(`Error prefetching page ${page} of ${folder}:`, err);
return null;
})
)
);
});
}, i * 300); // Stagger prefetches with 300ms between them
}
console.log(`Completed prefetching ${pages} pages of ${folder}`);
console.log(`Scheduled prefetching for ${pages} pages of ${folder}`);
} catch (error) {
console.error(`Error prefetching folder ${folder}:`, error);
}