From 1db445e6c936bd137a19c0e21506e68801f1543a Mon Sep 17 00:00:00 2001 From: alma Date: Sun, 27 Apr 2025 14:50:44 +0200 Subject: [PATCH] courrier redis --- app/courrier/page.tsx | 15 ++++++++++++-- components/email/EmailList.tsx | 6 ++++++ hooks/use-courrier.ts | 35 ++++++++++++++++++++++++++++---- lib/services/email-service.ts | 3 ++- lib/services/prefetch-service.ts | 24 ++++++++++++++++++---- 5 files changed, 72 insertions(+), 11 deletions(-) diff --git a/app/courrier/page.tsx b/app/courrier/page.tsx index 05f59255..56a8424b 100644 --- a/app/courrier/page.tsx +++ b/app/courrier/page.tsx @@ -209,8 +209,18 @@ export default function CourrierPage() { // Handle loading more emails on scroll const handleLoadMore = () => { if (hasMoreEmails && !isLoading) { - // Increment the page and call loadEmails with isLoadMore=true - setPage(page + 1); + // Increment the page + const nextPage = page + 1; + setPage(nextPage); + + // 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); + }); + } + // Note: loadEmails will be called automatically due to the page dependency in useEffect } }; @@ -275,6 +285,7 @@ export default function CourrierPage() { // 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); }); diff --git a/components/email/EmailList.tsx b/components/email/EmailList.tsx index eac71c6a..165e91fd 100644 --- a/components/email/EmailList.tsx +++ b/components/email/EmailList.tsx @@ -49,10 +49,16 @@ export default function EmailList({ const target = event.target as HTMLDivElement; const { scrollTop, scrollHeight, clientHeight } = target; + // Save scroll position for restoration when needed setScrollPosition(scrollTop); // If user scrolls near the bottom and we have more emails, load more if (scrollHeight - scrollTop - clientHeight < 200 && hasMoreEmails && !isLoading) { + // Store current scroll data before loading more + const currentScrollTop = scrollTop; + const currentScrollHeight = scrollHeight; + + // Request more emails onLoadMore(); } }; diff --git a/hooks/use-courrier.ts b/hooks/use-courrier.ts index ba1e3276..09a13506 100644 --- a/hooks/use-courrier.ts +++ b/hooks/use-courrier.ts @@ -83,9 +83,12 @@ export const useCourrier = () => { setIsLoading(true); setError(null); + // Keep reference to the current page for this request + const currentRequestPage = page; + try { // First try Redis cache with low timeout - const cachedEmails = await getCachedEmailsWithTimeout(session.user.id, currentFolder, page, perPage, 100); + const cachedEmails = await getCachedEmailsWithTimeout(session.user.id, currentFolder, currentRequestPage, perPage, 100); if (cachedEmails) { // Ensure cached data has emails array property if (Array.isArray(cachedEmails.emails)) { @@ -96,12 +99,26 @@ export const useCourrier = () => { const existingIds = new Set(prevEmails.map(email => email.id)); // Filter out any duplicates before appending 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`); + return [...prevEmails, ...newEmails]; }); } else { // For initial load, replace emails + console.log(`Setting ${cachedEmails.emails.length} cached emails for page ${currentRequestPage}`); setEmails(cachedEmails.emails); } + + // Set pagination info from cache if available + if (cachedEmails.totalEmails) setTotalEmails(cachedEmails.totalEmails); + if (cachedEmails.totalPages) setTotalPages(cachedEmails.totalPages); + + // Update available mailboxes if provided + if (cachedEmails.mailboxes && cachedEmails.mailboxes.length > 0) { + setMailboxes(cachedEmails.mailboxes); + } } else if (Array.isArray(cachedEmails)) { // Direct array response if (isLoadMore) { @@ -110,10 +127,15 @@ export const useCourrier = () => { const existingIds = new Set(prevEmails.map(email => email.id)); // Filter out any duplicates before appending const newEmails = cachedEmails.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`); + return [...prevEmails, ...newEmails]; }); } else { // For initial load, replace emails + console.log(`Setting ${cachedEmails.length} cached emails for page ${currentRequestPage}`); setEmails(cachedEmails); } } else { @@ -123,7 +145,7 @@ export const useCourrier = () => { setIsLoading(false); // Still refresh in background for fresh data - refreshEmailsInBackground(session.user.id, currentFolder, page, perPage).catch(err => { + refreshEmailsInBackground(session.user.id, currentFolder, currentRequestPage, perPage).catch(err => { console.error('Background refresh error:', err); }); return; @@ -132,7 +154,7 @@ export const useCourrier = () => { // Build query params const queryParams = new URLSearchParams({ folder: currentFolder, - page: page.toString(), + page: currentRequestPage.toString(), perPage: perPage.toString() }); @@ -157,10 +179,15 @@ export const useCourrier = () => { const existingIds = new Set(prev.map(email => email.id)); // Filter out any duplicates before appending 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`); + return [...prev, ...newEmails]; }); } else { // Ensure we always set an array even if API returns invalid data + console.log(`Setting ${data.emails?.length || 0} fetched emails for page ${currentRequestPage}`); setEmails(Array.isArray(data.emails) ? data.emails : []); } @@ -178,7 +205,7 @@ export const useCourrier = () => { setSelectedEmailIds([]); } } catch (err) { - console.error('Error loading emails:', err); + console.error(`Error loading emails for page ${currentRequestPage}:`, err); // Set emails to empty array on error to prevent runtime issues if (!isLoadMore) { setEmails([]); diff --git a/lib/services/email-service.ts b/lib/services/email-service.ts index 318b01d2..17f0cec1 100644 --- a/lib/services/email-service.ts +++ b/lib/services/email-service.ts @@ -458,8 +458,9 @@ export async function getEmails( mailboxes }; - // Cache the result if it's not a search query + // Always cache the result if it's not a search query, even for pagination if (!searchQuery) { + console.log(`Caching email list for ${userId}:${folder}:${page}:${perPage}`); await cacheEmailList(userId, folder, page, perPage, result); } diff --git a/lib/services/prefetch-service.ts b/lib/services/prefetch-service.ts index 8f82636b..69943bec 100644 --- a/lib/services/prefetch-service.ts +++ b/lib/services/prefetch-service.ts @@ -169,16 +169,32 @@ export async function prefetchUserEmailData(userId: string): Promise { export async function prefetchFolderEmails( userId: string, folder: string, - pages: number = 3 + pages: number = 3, + startPage: number = 1 ): Promise { try { - console.log(`Prefetching ${pages} pages of emails for folder ${folder}`); + console.log(`Prefetching ${pages} pages of emails for folder ${folder} starting from page ${startPage}`); + + // Calculate the range of pages to prefetch + const pagesToFetch = Array.from( + { length: pages }, + (_, i) => startPage + i + ); + + console.log(`Will prefetch pages: ${pagesToFetch.join(', ')}`); // Fetch multiple pages in parallel await Promise.allSettled( - Array.from({ length: pages }, (_, i) => i + 1).map(page => + pagesToFetch.map(page => getEmails(userId, folder, page, 20) - .catch(err => console.error(`Error prefetching page ${page} of ${folder}:`, err)) + .then(result => { + console.log(`Successfully prefetched and cached page ${page} of ${folder} with ${result.emails.length} emails`); + return result; + }) + .catch(err => { + console.error(`Error prefetching page ${page} of ${folder}:`, err); + return null; + }) ) );