ultisuite-client/components/gmail/contacts-page/use-discovery-scroll-load.ts
R3D347HR4Y 07d57f13a8
Some checks are pending
E2E / Playwright e2e (push) Waiting to run
Add Contact Avatar Features and Improve UI Components
- Introduced new ContactAvatar and ContactAvatarPicker components for enhanced avatar management in contact views.
- Updated ContactDetailView and ContactFormView to utilize the new avatar components, improving user experience when adding or editing contacts.
- Enhanced ContactHoverCard and ContactRow components to display avatars, providing a more visually appealing interface.
- Added loading and error states in ContactsListView for better user feedback during data fetching.
- Implemented a new ContactsLoadState component to handle loading and error scenarios in the contacts list.
- Updated package.json to include @formkit/auto-animate for improved UI animations.
2026-06-06 20:26:51 +02:00

80 lines
2.0 KiB
TypeScript

"use client"
import { useEffect, useRef, type RefObject } from "react"
interface UseDiscoveryScrollLoadOptions {
sentinelRef: RefObject<HTMLElement | null>
hasNextPage: boolean
isFetchingNextPage: boolean
onLoadMore: () => void
/** Pages chargées auto sans scroll (évite de tout prefetch si le sentinel est visible) */
maxAutoLoads?: number
scrollRootSelector?: string
}
export function useDiscoveryScrollLoad({
sentinelRef,
hasNextPage,
isFetchingNextPage,
onLoadMore,
maxAutoLoads = 1,
scrollRootSelector = "main.overflow-y-auto",
}: UseDiscoveryScrollLoadOptions) {
const autoLoadsRef = useRef(0)
const userScrolledRef = useRef(false)
useEffect(() => {
if (hasNextPage) {
autoLoadsRef.current = 0
userScrolledRef.current = false
}
}, [hasNextPage])
useEffect(() => {
const root =
document.querySelector(scrollRootSelector) ??
sentinelRef.current?.closest("main")
if (!root) return
const onScroll = () => {
if (root.scrollTop > 40) userScrolledRef.current = true
}
root.addEventListener("scroll", onScroll, { passive: true })
return () => root.removeEventListener("scroll", onScroll)
}, [scrollRootSelector, sentinelRef])
useEffect(() => {
const el = sentinelRef.current
if (!el || !hasNextPage) return
const root =
document.querySelector(scrollRootSelector) ??
el.closest("main")
const observer = new IntersectionObserver(
([entry]) => {
if (!entry?.isIntersecting || isFetchingNextPage) return
if (!userScrolledRef.current && autoLoadsRef.current >= maxAutoLoads) return
autoLoadsRef.current += 1
onLoadMore()
},
{
root: root instanceof Element ? root : null,
rootMargin: "160px",
threshold: 0,
},
)
observer.observe(el)
return () => observer.disconnect()
}, [
sentinelRef,
hasNextPage,
isFetchingNextPage,
onLoadMore,
scrollRootSelector,
maxAutoLoads,
])
}