+
{collection.coverImageUrl ? (

window.removeEventListener("scroll", handleScroll);
}, [fetchNextPage, hasNextPage, isFetchingNextPage]);
+ // Sentinel-based trigger — more reliable than scroll math on desktop, where
+ // the footer can keep the window-scroll threshold from being reached.
+ const loadMoreRef = useRef
(null);
+ useEffect(() => {
+ const el = loadMoreRef.current;
+ if (!el) return;
+ const observer = new IntersectionObserver(
+ (entries) => {
+ if (entries[0].isIntersecting && hasNextPage && !isFetchingNextPage) {
+ fetchNextPage();
+ }
+ },
+ { rootMargin: "600px" }
+ );
+ observer.observe(el);
+ return () => observer.disconnect();
+ }, [fetchNextPage, hasNextPage, isFetchingNextPage]);
+
// Memoize expensive filtering operations
const { oddProducts, evenProducts } = useMemo(() => {
const odd = products.filter((_, index) => index % 2 === 0);
@@ -177,6 +195,7 @@ const MondrianProductList = ({
{hasNextPage &&
}
+
>
)}
>
diff --git a/app/routes/collection.$id.tsx b/app/routes/collection.$id.tsx
index 1b35ddc..6002fb2 100644
--- a/app/routes/collection.$id.tsx
+++ b/app/routes/collection.$id.tsx
@@ -143,12 +143,12 @@ export default function CollectionDetail() {
{/* Collection Header */}
{/* Cover Image */}
-
+
{collection.coverImageUrl ? (

) : (
diff --git a/app/routes/collections.tsx b/app/routes/collections.tsx
index f349ecd..b360846 100644
--- a/app/routes/collections.tsx
+++ b/app/routes/collections.tsx
@@ -148,7 +148,7 @@ export default function Collections() {
>
{/* Collection Image - بزرگ */}
-
+
{collection.coverImageUrl ? (
-
-
+
+
{seller?.storeLogo ? (

) : null}
-
+
{seller?.storeName}
{seller?.isVerified ? (
@@ -246,7 +246,7 @@ export default function Seller() {
-