From 1cc8db2d20267546a617901ad0652c5b0c15d81b Mon Sep 17 00:00:00 2001 From: alma Date: Sun, 27 Apr 2025 15:07:13 +0200 Subject: [PATCH] courrier correct panel 2 scroll up --- components/email/EmailList.tsx | 167 ++++++++++++++++----------------- 1 file changed, 80 insertions(+), 87 deletions(-) diff --git a/components/email/EmailList.tsx b/components/email/EmailList.tsx index 62c4676b..ec17772f 100644 --- a/components/email/EmailList.tsx +++ b/components/email/EmailList.tsx @@ -1,11 +1,11 @@ 'use client'; -import React, { useState } from 'react'; +import React, { useState, useRef, useEffect, useCallback } from 'react'; import { Loader2, Mail, Search, X } from 'lucide-react'; import { Email } from '@/hooks/use-courrier'; -import EmailListItem from './EmailListItem'; -import EmailListHeader from './EmailListHeader'; -import BulkActionsToolbar from './BulkActionsToolbar'; +import EmailListItem from '@/components/email/EmailListItem'; +import EmailListHeader from '@/components/email/EmailListHeader'; +import BulkActionsToolbar from '@/components/email/BulkActionsToolbar'; import { Input } from '@/components/ui/input'; interface EmailListProps { @@ -43,95 +43,67 @@ export default function EmailList({ }: EmailListProps) { const [scrollPosition, setScrollPosition] = useState(0); const [searchQuery, setSearchQuery] = useState(''); - const scrollRef = React.useRef(null); - const [emailsLength, setEmailsLength] = useState(emails.length); - const [isScrollingToTop, setIsScrollingToTop] = useState(false); + const [isLoadingMore, setIsLoadingMore] = useState(false); + const scrollRef = useRef(null); + const scrollTimeoutRef = useRef(null); + const prevEmailsLengthRef = useRef(emails.length); - // Track changes in emails array to manage scrolling - React.useEffect(() => { - // If email count increased, we loaded more emails - if (emails.length > emailsLength) { - // If not loading more at the bottom, let's maintain scroll position - if (!isLoading && scrollRef.current && !isScrollingToTop) { - // This ensures the visible emails stay the same after loading more - setTimeout(() => { - if (scrollRef.current) { - scrollRef.current.scrollTop = scrollPosition; - } - }, 50); - } - } - // Update the emails length tracker - setEmailsLength(emails.length); - }, [emails, emailsLength, isLoading, scrollPosition]); - - // Add event listener for scroll reset from parent component - React.useEffect(() => { - const handleResetScroll = () => { - console.log("Resetting scroll position to top"); - if (scrollRef.current) { - setTimeout(() => { - if (scrollRef.current) { - // Force scroll to top - scrollRef.current.scrollTop = 0; - } - }, 100); - } - }; - - // Listen for the custom event - window.addEventListener('reset-email-scroll', handleResetScroll); - - // Also reset scroll when folder changes - handleResetScroll(); - - return () => { - window.removeEventListener('reset-email-scroll', handleResetScroll); - }; - }, [currentFolder]); // Reset scroll when folder changes - - // Handle scroll to detect when user reaches the bottom or scrolls up - const handleScroll = (event: React.UIEvent) => { + // Debounced scroll handler for better performance + const handleScroll = useCallback((event: React.UIEvent) => { const target = event.target as HTMLDivElement; const { scrollTop, scrollHeight, clientHeight } = target; - // Save scroll position for restoration when needed + // Save scroll position for restoration setScrollPosition(scrollTop); - // Detect scrolling direction - setIsScrollingToTop(scrollTop < scrollPosition); + // Clear any existing timeout to prevent rapid firing + if (scrollTimeoutRef.current) { + clearTimeout(scrollTimeoutRef.current); + } - // 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; + // If near bottom (within 200px) and more emails are available, load more + if (scrollHeight - scrollTop - clientHeight < 200 && hasMoreEmails && !isLoading && !isLoadingMore) { + setIsLoadingMore(true); - // Request more emails - onLoadMore(); + // Use timeout to debounce load requests + scrollTimeoutRef.current = setTimeout(() => { + onLoadMore(); + + // Reset loading state after a delay + setTimeout(() => { + setIsLoadingMore(false); + }, 1000); + }, 100); } - }; + }, [hasMoreEmails, isLoading, isLoadingMore, onLoadMore]); - // Add a function to scroll to top - const scrollToTop = () => { - if (scrollRef.current) { - scrollRef.current.scrollTop = 0; + // Restore scroll position when emails are loaded + useEffect(() => { + if (emails.length > prevEmailsLengthRef.current && scrollRef.current && scrollPosition > 0) { + // Maintain scroll position when new emails are added + scrollRef.current.scrollTop = scrollPosition; } - }; + + prevEmailsLengthRef.current = emails.length; + }, [emails.length, scrollPosition]); - // Update title to show date sort order - React.useEffect(() => { - // Add a small indicator in the header to show emails are sorted by date - const headerElement = document.querySelector('.email-header-title'); - if (headerElement) { - headerElement.setAttribute('title', 'Emails are sorted by date (newest first)'); - } + // Clean up timeouts on unmount + useEffect(() => { + return () => { + if (scrollTimeoutRef.current) { + clearTimeout(scrollTimeoutRef.current); + } + }; }, []); - // Handle search const handleSearch = (e: React.FormEvent) => { e.preventDefault(); onSearch?.(searchQuery); + + // Reset scroll to top when searching + if (scrollRef.current) { + scrollRef.current.scrollTop = 0; + } }; const clearSearch = () => { @@ -139,11 +111,21 @@ export default function EmailList({ onSearch?.(''); }; + const scrollToTop = () => { + if (scrollRef.current) { + // Use smooth scrolling for better UX + scrollRef.current.scrollTo({ + top: 0, + behavior: 'smooth' + }); + } + }; + // Render loading state if (isLoading && emails.length === 0) { return (
-
+
); } @@ -219,17 +201,17 @@ export default function EmailList({ onScroll={handleScroll} >
- {/* Add a small note to show emails are sorted by date */} -
- Sorted by date (newest first) - -
+ )} + {/* Email list */} {emails.map((email) => ( ))} - {isLoading && emails.length > 0 && ( + {/* Loading indicator */} + {(isLoading || isLoadingMore) && (
-
+
)} + + {/* Load more button - only show when near bottom but not auto-loading */} + {hasMoreEmails && !isLoading && !isLoadingMore && ( + + )}