courrier redis

This commit is contained in:
alma 2025-04-27 14:50:44 +02:00
parent d73442573d
commit 1db445e6c9
5 changed files with 72 additions and 11 deletions

View File

@ -209,8 +209,18 @@ export default function CourrierPage() {
// Handle loading more emails on scroll // Handle loading more emails on scroll
const handleLoadMore = () => { const handleLoadMore = () => {
if (hasMoreEmails && !isLoading) { if (hasMoreEmails && !isLoading) {
// Increment the page and call loadEmails with isLoadMore=true // Increment the page
setPage(page + 1); 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 // 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 // Start prefetching additional pages for this folder
if (session?.user?.id && folder) { if (session?.user?.id && folder) {
// First two pages are most important - prefetch immediately
prefetchFolderEmails(session.user.id, folder, 3).catch(err => { prefetchFolderEmails(session.user.id, folder, 3).catch(err => {
console.error(`Error prefetching ${folder}:`, err); console.error(`Error prefetching ${folder}:`, err);
}); });

View File

@ -49,10 +49,16 @@ export default function EmailList({
const target = event.target as HTMLDivElement; const target = event.target as HTMLDivElement;
const { scrollTop, scrollHeight, clientHeight } = target; const { scrollTop, scrollHeight, clientHeight } = target;
// Save scroll position for restoration when needed
setScrollPosition(scrollTop); setScrollPosition(scrollTop);
// If user scrolls near the bottom and we have more emails, load more // If user scrolls near the bottom and we have more emails, load more
if (scrollHeight - scrollTop - clientHeight < 200 && hasMoreEmails && !isLoading) { if (scrollHeight - scrollTop - clientHeight < 200 && hasMoreEmails && !isLoading) {
// Store current scroll data before loading more
const currentScrollTop = scrollTop;
const currentScrollHeight = scrollHeight;
// Request more emails
onLoadMore(); onLoadMore();
} }
}; };

View File

@ -83,9 +83,12 @@ export const useCourrier = () => {
setIsLoading(true); setIsLoading(true);
setError(null); setError(null);
// Keep reference to the current page for this request
const currentRequestPage = page;
try { try {
// First try Redis cache with low timeout // 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) { if (cachedEmails) {
// Ensure cached data has emails array property // Ensure cached data has emails array property
if (Array.isArray(cachedEmails.emails)) { if (Array.isArray(cachedEmails.emails)) {
@ -96,12 +99,26 @@ export const useCourrier = () => {
const existingIds = new Set(prevEmails.map(email => email.id)); const existingIds = new Set(prevEmails.map(email => email.id));
// Filter out any duplicates before appending // Filter out any duplicates before appending
const newEmails = cachedEmails.emails.filter((email: Email) => !existingIds.has(email.id)); 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]; return [...prevEmails, ...newEmails];
}); });
} else { } else {
// For initial load, replace emails // For initial load, replace emails
console.log(`Setting ${cachedEmails.emails.length} cached emails for page ${currentRequestPage}`);
setEmails(cachedEmails.emails); 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)) { } else if (Array.isArray(cachedEmails)) {
// Direct array response // Direct array response
if (isLoadMore) { if (isLoadMore) {
@ -110,10 +127,15 @@ export const useCourrier = () => {
const existingIds = new Set(prevEmails.map(email => email.id)); const existingIds = new Set(prevEmails.map(email => email.id));
// Filter out any duplicates before appending // Filter out any duplicates before appending
const newEmails = cachedEmails.filter((email: Email) => !existingIds.has(email.id)); 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]; return [...prevEmails, ...newEmails];
}); });
} else { } else {
// For initial load, replace emails // For initial load, replace emails
console.log(`Setting ${cachedEmails.length} cached emails for page ${currentRequestPage}`);
setEmails(cachedEmails); setEmails(cachedEmails);
} }
} else { } else {
@ -123,7 +145,7 @@ export const useCourrier = () => {
setIsLoading(false); setIsLoading(false);
// Still refresh in background for fresh data // 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); console.error('Background refresh error:', err);
}); });
return; return;
@ -132,7 +154,7 @@ export const useCourrier = () => {
// Build query params // Build query params
const queryParams = new URLSearchParams({ const queryParams = new URLSearchParams({
folder: currentFolder, folder: currentFolder,
page: page.toString(), page: currentRequestPage.toString(),
perPage: perPage.toString() perPage: perPage.toString()
}); });
@ -157,10 +179,15 @@ export const useCourrier = () => {
const existingIds = new Set(prev.map(email => email.id)); const existingIds = new Set(prev.map(email => email.id));
// Filter out any duplicates before appending // Filter out any duplicates before appending
const newEmails = data.emails.filter((email: Email) => !existingIds.has(email.id)); 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]; return [...prev, ...newEmails];
}); });
} else { } else {
// Ensure we always set an array even if API returns invalid data // 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 : []); setEmails(Array.isArray(data.emails) ? data.emails : []);
} }
@ -178,7 +205,7 @@ export const useCourrier = () => {
setSelectedEmailIds([]); setSelectedEmailIds([]);
} }
} catch (err) { } 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 // Set emails to empty array on error to prevent runtime issues
if (!isLoadMore) { if (!isLoadMore) {
setEmails([]); setEmails([]);

View File

@ -458,8 +458,9 @@ export async function getEmails(
mailboxes 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) { if (!searchQuery) {
console.log(`Caching email list for ${userId}:${folder}:${page}:${perPage}`);
await cacheEmailList(userId, folder, page, perPage, result); await cacheEmailList(userId, folder, page, perPage, result);
} }

View File

@ -169,16 +169,32 @@ export async function prefetchUserEmailData(userId: string): Promise<void> {
export async function prefetchFolderEmails( export async function prefetchFolderEmails(
userId: string, userId: string,
folder: string, folder: string,
pages: number = 3 pages: number = 3,
startPage: number = 1
): Promise<void> { ): Promise<void> {
try { 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 // Fetch multiple pages in parallel
await Promise.allSettled( await Promise.allSettled(
Array.from({ length: pages }, (_, i) => i + 1).map(page => pagesToFetch.map(page =>
getEmails(userId, folder, page, 20) 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;
})
) )
); );