From f613054b9a81dcb910a4daf07c528714a23611cf Mon Sep 17 00:00:00 2001
From: PhilReact <philliplangmartinez@gmail.com>
Date: Sun, 16 Mar 2025 22:11:02 +0200
Subject: [PATCH] added pagination for lists

---
 src/common/LazyLoad.tsx                       |  28 +++--
 src/common/useScrollTracker.tsx               |  29 +++--
 src/components/ResourceList/DynamicGrid.tsx   |  25 +++-
 .../ResourceList/HorizontalPaginationList.tsx | 113 +++++++++---------
 .../ResourceList/ResourceListDisplay.tsx      | 110 +++++++----------
 .../ResourceList/VerticalPaginationList.tsx   |  97 +++++++++++++++
 src/hooks/useResources.tsx                    |   4 +
 src/state/lists.ts                            |   8 ++
 8 files changed, 264 insertions(+), 150 deletions(-)
 create mode 100644 src/components/ResourceList/VerticalPaginationList.tsx

diff --git a/src/common/LazyLoad.tsx b/src/common/LazyLoad.tsx
index 34a6cf9..4696dc7 100644
--- a/src/common/LazyLoad.tsx
+++ b/src/common/LazyLoad.tsx
@@ -1,22 +1,28 @@
-import React, { useState, useEffect, useRef } from 'react'
+import { CircularProgress } from '@mui/material';
+import React, { useEffect, useRef } from 'react'
 import { useInView } from 'react-intersection-observer'
-import CircularProgress from '@mui/material/CircularProgress'
 
 interface Props {
   onLoadMore: () => void
 }
 
 const LazyLoad: React.FC<Props> = ({ onLoadMore }) => {
+  const hasTriggeredRef = useRef(false); // Prevents multiple auto-triggers
 
   const [ref, inView] = useInView({
-    threshold: 0.7
-  })
+    threshold: 0.7,
+    triggerOnce: false, // Allows multiple triggers, but we control when
+  });
 
   useEffect(() => {
-    if (inView) {
-      onLoadMore()
+    if (inView && !hasTriggeredRef.current) {
+      hasTriggeredRef.current = true; // Set flag so it doesn’t trigger again immediately
+      onLoadMore();
+      setTimeout(() => {
+        hasTriggeredRef.current = false; // Reset trigger after a short delay
+      }, 1000);
     }
-  }, [inView])
+  }, [inView]);
 
   return (
     <div
@@ -24,11 +30,11 @@ const LazyLoad: React.FC<Props> = ({ onLoadMore }) => {
       style={{
         display: 'flex',
         justifyContent: 'center',
-        minHeight: '25px'
+        height: '50px',
+        overflow: 'hidden'
       }}
-    >
-    </div>
+    ><CircularProgress /></div>
   )
 }
 
-export default LazyLoad
+export default LazyLoad;
diff --git a/src/common/useScrollTracker.tsx b/src/common/useScrollTracker.tsx
index 0f7c4d2..04ae71a 100644
--- a/src/common/useScrollTracker.tsx
+++ b/src/common/useScrollTracker.tsx
@@ -1,26 +1,37 @@
-import { useEffect, useRef } from "react";
+import { useEffect, useRef, useState } from "react";
+
+export const useScrollTracker = (listName: string, hasList: boolean, disableScrollTracker?: boolean) => {
+  const elementRef = useRef<HTMLDivElement | null>(null);
+  const [hasMount, setHasMount] = useState(false);
+  const scrollPositionRef = useRef(0); // Store the last known scroll position
 
-export const useScrollTracker = (listName: string) => {
   useEffect(() => {
-    if (!listName) return;
-
+    if(disableScrollTracker) return
+    if (!listName || !hasList) return;
+    
     const SCROLL_KEY = `scroll-position-${listName}`;
 
-    // πŸ”Ή Restore saved scroll position for the given list
+    // πŸ”Ή Restore scroll when the component mounts
     const savedPosition = sessionStorage.getItem(SCROLL_KEY);
     if (savedPosition) {
       window.scrollTo(0, parseInt(savedPosition, 10));
+      setTimeout(() => {
+        setHasMount(true);
+      }, 200);
     }
 
+    // πŸ”Ή Capture scroll position before unmount
     const handleScroll = () => {
-      sessionStorage.setItem(SCROLL_KEY, window.scrollY.toString());
+      scrollPositionRef.current = window.scrollY; // Store the last known scroll position
     };
 
-    // πŸ”Ή Save scroll position on scroll
     window.addEventListener("scroll", handleScroll);
 
     return () => {
+      sessionStorage.setItem(SCROLL_KEY, scrollPositionRef.current.toString());
       window.removeEventListener("scroll", handleScroll);
     };
-  }, [listName]); // βœ… Only runs when listName changes
-};
\ No newline at end of file
+  }, [listName, hasList, disableScrollTracker]);
+
+  return { elementRef, hasMount };
+};
diff --git a/src/components/ResourceList/DynamicGrid.tsx b/src/components/ResourceList/DynamicGrid.tsx
index 7883292..a44b7c3 100644
--- a/src/components/ResourceList/DynamicGrid.tsx
+++ b/src/components/ResourceList/DynamicGrid.tsx
@@ -6,6 +6,7 @@ interface DynamicGridProps {
   gap?: number; // Spacing between grid items
   children: ReactNode
   minItemWidth?: number
+  setColumnsPerRow: (columns: number)=> void;
 }
 
 const DynamicGrid: React.FC<DynamicGridProps> = ({
@@ -13,12 +14,32 @@ const DynamicGrid: React.FC<DynamicGridProps> = ({
   minItemWidth = 200, // Minimum width per item
   gap = 10, // Space between items
   children,
-
+  setColumnsPerRow
 
 }) => {
+  const containerRef = useRef<HTMLDivElement | null>(null);
+  const itemContainerRef = useRef<HTMLDivElement | null>(null);
+
+  const updateColumns = () => {
+    if (containerRef.current && itemContainerRef.current) {
+      const containerWidth = containerRef.current.clientWidth;
+      const itemWidth = itemContainerRef.current.clientWidth
+      const calculatedColumns = Math.floor(containerWidth / itemWidth);
+      setColumnsPerRow(calculatedColumns);
+    }
+  };
+
+  useEffect(() => {
+    updateColumns(); // Run on mount
+    window.addEventListener("resize", updateColumns);
+    return () => window.removeEventListener("resize", updateColumns);
+  }, []);
+
   return (
     <div  style={{ display: "flex", flexDirection: "column", alignItems: "center", width: "100%" }}>
       <div
+              ref={containerRef}
+
         style={{
           display: "grid",
           gridTemplateColumns: `repeat(auto-fill, minmax(${minItemWidth}px, 1fr))`, // βœ… Expands to fit width
@@ -31,7 +52,7 @@ const DynamicGrid: React.FC<DynamicGridProps> = ({
         }}
       >
         {items.map((component, index) => (
-          <div key={index} style={{ width: "100%", display: "flex", justifyContent: "center", maxWidth: '400px' }}>
+          <div ref={index === 0 ? itemContainerRef : null} key={index} style={{ width: "100%", display: "flex", justifyContent: "center", maxWidth: '400px' }}>
             {component} {/* βœ… Renders user-provided component */}
           </div>
         ))}
diff --git a/src/components/ResourceList/HorizontalPaginationList.tsx b/src/components/ResourceList/HorizontalPaginationList.tsx
index c9429cd..efefbd2 100644
--- a/src/components/ResourceList/HorizontalPaginationList.tsx
+++ b/src/components/ResourceList/HorizontalPaginationList.tsx
@@ -1,21 +1,24 @@
-import React, { useEffect, useState, useCallback } from "react";
+import React, {  useMemo, useRef, useState } from "react";
 import DynamicGrid from "./DynamicGrid";
 import LazyLoad from "../../common/LazyLoad";
-import { ListItem, useCacheStore } from "../../state/cache";
+import { ListItem } from "../../state/cache";
 import { QortalMetadata } from "../../types/interfaces/resources";
-import { ListItemWrapper } from "./ResourceListDisplay";
+import { DefaultLoaderParams, ListItemWrapper } from "./ResourceListDisplay";
 
 interface HorizontalPaginatedListProps {
   items: QortalMetadata[];
   listItem: (item: ListItem, index: number) => React.ReactNode;
   loaderItem?: (status: "LOADING" | "ERROR") => React.ReactNode;
-  onLoadMore: () => void;
-  maxItems?: number;
+  onLoadMore: (limit: number) => void;
+  onLoadLess: (limit: number)=> void;
   minItemWidth?: number;
   gap?: number;
   isLoading?: boolean;
   onSeenLastItem?: (listItem: ListItem) => void;
-
+  isLoadingMore: boolean;
+  limit: number,
+  disablePagination?: boolean
+  defaultLoaderParams?: DefaultLoaderParams;
 }
 
 export const HorizontalPaginatedList = ({
@@ -23,84 +26,78 @@ export const HorizontalPaginatedList = ({
   listItem,
   loaderItem,
   onLoadMore,
-  maxItems = 60,
+  onLoadLess,
   minItemWidth,
   gap,
   isLoading,
   onSeenLastItem,
-
+  isLoadingMore,
+  limit,
+  disablePagination,
+  defaultLoaderParams
 }: HorizontalPaginatedListProps) => {
-  const [displayedItems, setDisplayedItems] = useState(items);
- 
+const lastItemRef= useRef<any>(null)
+const lastItemRef2= useRef<any>(null)
+const [columnsPerRow, setColumnsPerRow] = useState<null | number>(null)
 
-  useEffect(() => {
-    setDisplayedItems(items);
-  }, [items]);
+const displayedLimit = useMemo(()=> {
+    if(disablePagination) return limit || 20
+    return Math.floor((limit || 20) / (columnsPerRow || 3)) * (columnsPerRow || 3);
+}, [columnsPerRow, disablePagination])
 
-  const preserveScroll = useCallback((updateFunction: () => void) => {
-    const previousScrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
-    const previousScrollWidth = document.documentElement.scrollWidth || document.body.scrollWidth;
-
-    updateFunction(); // Perform the update (fetch new data, remove old)
-
-    requestAnimationFrame(() => {
-      const newScrollWidth = document.documentElement.scrollWidth || document.body.scrollWidth;
-      document.documentElement.scrollLeft = document.body.scrollLeft =
-        previousScrollLeft - (previousScrollWidth - newScrollWidth);
-    });
-  }, []);
-
-  useEffect(() => {
-    if (displayedItems.length > maxItems) {
-      preserveScroll(() => {
-        const excess = displayedItems.length - maxItems;
-        setDisplayedItems((prev) => prev.slice(excess)); // Trim from the start
-      });
-    }
-  }, [displayedItems, maxItems, preserveScroll]);
-
-  useEffect(() => {
-    const handleScroll = () => {
-      const scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
-      const clientWidth = document.documentElement.clientWidth || document.body.clientWidth;
-      const scrollWidth = document.documentElement.scrollWidth || document.body.scrollWidth;
-
-      if (scrollLeft + clientWidth >= scrollWidth - 10 && !isLoading) {
-        onLoadMore();
-      }
-    };
-
-    window.addEventListener("scroll", handleScroll);
-    return () => window.removeEventListener("scroll", handleScroll);
-  }, [onLoadMore, isLoading]);
+const displayedItems = disablePagination ? items : items?.length < (displayedLimit * 3) ? items?.slice(0, displayedLimit * 3)  : items.slice(- (displayedLimit * 3)) 
 
   return (
-    <div style={{ overflow: "auto", width: "100%", display: "flex", flexGrow: 1 }}>
+    <div style={{ overflowX: "hidden", width: "100%", display: "flex", flexGrow: 1, flexDirection: 'column' }}>
+      {!disablePagination && items?.length > (displayedLimit * 3) &&  (
+          <LazyLoad
+            onLoadMore={async () => {
+
+              await onLoadLess(displayedLimit);
+              lastItemRef2.current.scrollIntoView({ behavior: "auto", block: "start" });
+              setTimeout(() => {
+                window.scrollBy({ top: -50, behavior: "instant" }); // 'smooth' if needed
+              }, 0);
+            }}
+          />
+        )}
       <DynamicGrid
+        setColumnsPerRow={setColumnsPerRow}
         minItemWidth={minItemWidth}
         gap={gap}
-        items={displayedItems.map((item, index) => (
+        items={displayedItems?.map((item, index, list) => (
           <React.Fragment key={`${item?.name}-${item?.service}-${item?.identifier}`}>
+            <div style={{
+                width: '100%',
+                display: 'flex',
+                justifyContent: 'center'
+            }} ref={index === displayedLimit ? lastItemRef2 : index === list.length -displayedLimit - 1 ? lastItemRef : null}>
             <ListItemWrapper
+            defaultLoaderParams={defaultLoaderParams}
               item={item}
               index={index}
               render={listItem}
               renderListItemLoader={loaderItem}
             />
+            </div>
           </React.Fragment>
         ))}
       >
-        {!isLoading && displayedItems.length > 0 && (
+          
           <LazyLoad
-            onLoadMore={() => {
-              onLoadMore();
-              if (onSeenLastItem) {
-                // onSeenLastItem(displayedItems[displayedItems.length - 1]);
-              }
+            onLoadMore={async () => {
+              await onLoadMore(displayedLimit);
+              lastItemRef.current.scrollIntoView({ behavior: "auto", block: "end" });
+              setTimeout(() => {
+                window.scrollBy({ top: 50, behavior: "instant" }); // 'smooth' if needed
+              }, 0);
+
             }}
           />
-        )}
+    
       </DynamicGrid>
+
+     
     </div>
   );
 };
diff --git a/src/components/ResourceList/ResourceListDisplay.tsx b/src/components/ResourceList/ResourceListDisplay.tsx
index dcd1c19..0e671a5 100644
--- a/src/components/ResourceList/ResourceListDisplay.tsx
+++ b/src/components/ResourceList/ResourceListDisplay.tsx
@@ -2,28 +2,25 @@ import React, {
   CSSProperties,
   useCallback,
   useEffect,
-  useLayoutEffect,
   useMemo,
   useRef,
   useState,
-  useTransition,
 } from "react";
 import {
   QortalMetadata,
   QortalSearchParams,
 } from "../../types/interfaces/resources";
 import { useResources } from "../../hooks/useResources";
-import { MessageWrapper, VirtualizedList } from "../../common/VirtualizedList";
+import { VirtualizedList } from "../../common/VirtualizedList";
 import { ListLoader } from "../../common/ListLoader";
 import { ListItem, useCacheStore } from "../../state/cache";
 import { ResourceLoader } from "./ResourceLoader";
 import { ItemCardWrapper } from "./ItemCardWrapper";
 import { Spacer } from "../../common/Spacer";
-import DynamicGrid from "./DynamicGrid";
-import LazyLoad from "../../common/LazyLoad";
 import { useListStore } from "../../state/lists";
 import { useScrollTracker } from "../../common/useScrollTracker";
 import { HorizontalPaginatedList } from "./HorizontalPaginationList";
+import { VerticalPaginatedList } from "./VerticalPaginationList";
 type Direction = "VERTICAL" | "HORIZONTAL";
 
 interface ResourceListStyles {
@@ -37,7 +34,7 @@ interface ResourceListStyles {
   }
 }
 
-interface DefaultLoaderParams {
+export interface DefaultLoaderParams {
   listLoadingText?: string;
   listNoResultsText?: string;
   listItemLoadingText?: string;
@@ -57,6 +54,8 @@ interface BaseProps  {
   children?: React.ReactNode;
   searchCacheDuration?: number
   resourceCacheDuration?: number
+  disablePagination?: boolean
+  disableScrollTracker?: boolean
 }
 
 // βœ… Restrict `direction` only when `disableVirtualization = false`
@@ -86,17 +85,22 @@ export const MemorizedComponent = ({
   onSeenLastItem,
   listName,
   searchCacheDuration,
-  resourceCacheDuration
+  resourceCacheDuration,
+  disablePagination,
+  disableScrollTracker
 }: PropsResourceListDisplay)  => {
   const { fetchResources } = useResources();
   const {  getTemporaryResources, filterOutDeletedResources } = useCacheStore();
-  const [isLoading, setIsLoading] = useState(false);
   const memoizedParams = useMemo(() => JSON.stringify(search), [search]);
   const addList = useListStore().addList
+  const removeFromList =  useListStore().removeFromList
+
   const addItems = useListStore().addItems
-  const getListByName = useListStore().getListByName
   const list = useListStore().getListByName(listName)
+  const [isLoading, setIsLoading] = useState(list?.length > 0 ? false : true);
+
   const isListExpired = useCacheStore().isListExpired(listName)
+  const [isLoadingMore, setIsLoadingMore] = useState(false)
   const initialized = useRef(false)
 
   const getResourceList = useCallback(async () => {
@@ -124,13 +128,16 @@ export const MemorizedComponent = ({
   useEffect(() => {
     if(initialized.current) return
     initialized.current = true
-    if(!isListExpired) return
+    if(!isListExpired) {
+      setIsLoading(false)
+      return
+    }
     
     sessionStorage.removeItem(`scroll-position-${listName}`);
     getResourceList();
   }, [getResourceList, isListExpired]); // Runs when dependencies change
 
-  useScrollTracker(listName);
+  const {elementRef} = useScrollTracker(listName, list?.length > 0, disableScrollTracker);
 
    const setSearchCacheExpiryDuration = useCacheStore().setSearchCacheExpiryDuration
   const setResourceCacheExpiryDuration = useCacheStore().setResourceCacheExpiryDuration
@@ -152,18 +159,24 @@ export const MemorizedComponent = ({
 
 
 
-  const getResourceMoreList = useCallback(async () => {
+  const getResourceMoreList = useCallback(async (displayLimit?: number) => {
     try {
-      // setIsLoading(true);
+      setIsLoadingMore(true)
       const parsedParams = {...(JSON.parse(memoizedParams))};
       parsedParams.before = list.length === 0 ? null : list[list.length - 1]?.created
       parsedParams.offset = null
+      if(displayLimit){
+        parsedParams.limit = displayLimit
+      }
       const responseData = await fetchResources(parsedParams, listName); // Awaiting the async function
       addItems(listName, responseData || [])
     } catch (error) {
       console.error("Failed to fetch resources:", error);
     } finally {
-      setIsLoading(false);
+      setTimeout(() => {
+        setIsLoadingMore(false);
+
+      }, 1000);
     }
   }, [memoizedParams, listName, list]); 
 
@@ -191,6 +204,10 @@ export const MemorizedComponent = ({
   }, [listName]);
 
   return (
+    <div ref={elementRef} style={{
+      width: '100%',
+      height: '100%'
+    }}>
     <ListLoader
       noResultsMessage={
         defaultLoaderParams?.listNoResultsText || "No results available"
@@ -204,6 +221,7 @@ export const MemorizedComponent = ({
       loaderHeight={styles?.listLoadingHeight}
     >
       <div
+      
         style={{
           height: "100%",
           display: "flex",
@@ -236,72 +254,24 @@ export const MemorizedComponent = ({
           )}
           {disableVirtualization && direction === "HORIZONTAL" && (
             <>
-            <DynamicGrid
-              minItemWidth={styles?.horizontalStyles?.minItemWidth}
-              gap={styles?.gap}
-              items={listToDisplay?.map((item, index) => {
-                return (
-                  <React.Fragment
-                    key={`${item?.name}-${item?.service}-${item?.identifier}`}
-                  >
-                    <ListItemWrapper
-                      defaultLoaderParams={defaultLoaderParams}
-                      item={item}
-                      index={index}
-                      render={listItem}
-                      renderListItemLoader={loaderItem}
-                    />
-                  </React.Fragment>
-                );
-              })}
-            >
-
-            {!isLoading && listToDisplay?.length > 0 && (
-                <LazyLoad onLoadMore={()=> {
-                  getResourceMoreList()
-                  if(onSeenLastItem){
-                
-                    onSeenLastItem(listToDisplay[listToDisplay?.length - 1])
-                  }
-                }} />
-              )}
-              </DynamicGrid>
+             <HorizontalPaginatedList defaultLoaderParams={defaultLoaderParams} disablePagination={disablePagination} limit={search?.limit || 20} onLoadLess={(displayLimit)=> {
+              removeFromList(listName, displayLimit)
+             }} isLoadingMore={isLoadingMore} items={listToDisplay} listItem={listItem} onLoadMore={(displayLimit)=> getResourceMoreList(displayLimit)} gap={styles?.gap} isLoading={isLoading} minItemWidth={styles?.horizontalStyles?.minItemWidth} loaderItem={loaderItem} />
             </>
             
           )}
           {disableVirtualization && direction === "VERTICAL" && (
             <div style={disabledVirutalizationStyles}>
-              {listToDisplay?.map((item, index) => {
-                return (
-                  <React.Fragment
-                    key={`${item?.name}-${item?.service}-${item?.identifier}`}
-                  >
-                   
-                      <ListItemWrapper
-                        defaultLoaderParams={defaultLoaderParams}
-                        item={item}
-                        index={index}
-                        render={listItem}
-                        renderListItemLoader={loaderItem}
-                      />
-            
-                  </React.Fragment>
-                );
-              })}
-              {!isLoading && listToDisplay?.length > 0 && (
-                <LazyLoad onLoadMore={()=> {
-                  getResourceMoreList()
-                  if(onSeenLastItem){                    
-                    onSeenLastItem(listToDisplay[listToDisplay?.length - 1])
-                  }
-                }} />
-              )}
-              
+              <VerticalPaginatedList disablePagination={disablePagination} limit={search?.limit || 20} onLoadLess={(displayLimit)=> {
+
+              removeFromList(listName, displayLimit)
+             }} defaultLoaderParams={defaultLoaderParams} isLoadingMore={isLoadingMore} items={listToDisplay} listItem={listItem} onLoadMore={(displayLimit)=> getResourceMoreList(displayLimit)} gap={styles?.gap} isLoading={isLoading} minItemWidth={styles?.horizontalStyles?.minItemWidth} loaderItem={loaderItem} />
             </div>
           )}
         </div>
       </div>
     </ListLoader>
+    </div>
   );
 }
 
diff --git a/src/components/ResourceList/VerticalPaginationList.tsx b/src/components/ResourceList/VerticalPaginationList.tsx
new file mode 100644
index 0000000..458990e
--- /dev/null
+++ b/src/components/ResourceList/VerticalPaginationList.tsx
@@ -0,0 +1,97 @@
+import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
+import DynamicGrid from "./DynamicGrid";
+import LazyLoad from "../../common/LazyLoad";
+import { ListItem } from "../../state/cache";
+import { QortalMetadata } from "../../types/interfaces/resources";
+import { DefaultLoaderParams, ListItemWrapper } from "./ResourceListDisplay";
+import { Button } from "@mui/material";
+
+interface VerticalPaginatedListProps {
+  items: QortalMetadata[];
+  listItem: (item: ListItem, index: number) => React.ReactNode;
+  loaderItem?: (status: "LOADING" | "ERROR") => React.ReactNode;
+  onLoadMore: (limit: number) => void;
+  onLoadLess: (limit: number)=> void;
+  minItemWidth?: number;
+  gap?: number;
+  isLoading?: boolean;
+  onSeenLastItem?: (listItem: ListItem) => void;
+  isLoadingMore: boolean;
+  limit: number,
+  disablePagination?: boolean
+  defaultLoaderParams?: DefaultLoaderParams;
+}
+
+export const VerticalPaginatedList = ({
+  items,
+  listItem,
+  loaderItem,
+  onLoadMore,
+  onLoadLess,
+  minItemWidth,
+  gap,
+  isLoading,
+  onSeenLastItem,
+  isLoadingMore,
+  limit,
+  disablePagination,
+  defaultLoaderParams
+}: VerticalPaginatedListProps) => {
+
+const lastItemRef= useRef<any>(null)
+const lastItemRef2= useRef<any>(null)
+
+const displayedLimit = limit || 20
+
+const displayedItems = disablePagination ? items :  items.slice(- (displayedLimit * 3)) 
+
+  return (
+    <>
+      {!disablePagination && items?.length > (displayedLimit * 3) &&  (
+          <LazyLoad
+            onLoadMore={async () => {
+
+              await onLoadLess(displayedLimit);
+              lastItemRef2.current.scrollIntoView({ behavior: "auto", block: "start" });
+              setTimeout(() => {
+                window.scrollBy({ top: -50, behavior: "instant" }); // 'smooth' if needed
+              }, 0);
+            }}
+          />
+        )}
+
+        {displayedItems?.map((item, index, list) => {
+                        return (
+                          <React.Fragment
+                            key={`${item?.name}-${item?.service}-${item?.identifier}`}
+                          >
+                             <div style={{
+                width: '100%',
+                display: 'flex',
+                justifyContent: 'center'
+            }} ref={index === displayedLimit ? lastItemRef2 : index === list.length -displayedLimit - 1 ? lastItemRef : null}>
+                              <ListItemWrapper
+                                defaultLoaderParams={defaultLoaderParams}
+                                item={item}
+                                index={index}
+                                render={listItem}
+                                renderListItemLoader={loaderItem}
+                              />
+                    </div>
+                          </React.Fragment>
+                        );
+                      })}
+
+      <LazyLoad
+            onLoadMore={async () => {
+              await onLoadMore(displayedLimit);
+              lastItemRef.current.scrollIntoView({ behavior: "auto", block: "end" });
+              setTimeout(() => {
+                window.scrollBy({ top: 50, behavior: "instant" }); // 'smooth' if needed
+              }, 0);
+
+            }}
+          />
+    </>
+  );
+};
diff --git a/src/hooks/useResources.tsx b/src/hooks/useResources.tsx
index f86863d..6768bba 100644
--- a/src/hooks/useResources.tsx
+++ b/src/hooks/useResources.tsx
@@ -29,6 +29,7 @@ export const useResources = () => {
   } = useCacheStore();
   const requestControllers = new Map<string, AbortController>();
 
+
   const getArbitraryResource = async (
     url: string,
     key: string
@@ -42,6 +43,7 @@ export const useResources = () => {
 
     try {
       const res = await fetch(url, { signal: controller.signal });
+      if(!res?.ok) throw new Error('Error in downloading')
       return await res.text();
     } catch (error: any) {
       if (error?.name === "AbortError") {
@@ -90,6 +92,8 @@ export const useResources = () => {
         } catch (error) {
           hasFailedToDownload = true;
         }
+
+
         if (res === "canceled") return false;
 
         if (hasFailedToDownload) {
diff --git a/src/state/lists.ts b/src/state/lists.ts
index 254076f..258baed 100644
--- a/src/state/lists.ts
+++ b/src/state/lists.ts
@@ -15,6 +15,7 @@ interface ListStore {
 
   // CRUD Operations
   addList: (name: string, items: QortalMetadata[]) => void;
+  removeFromList: (name: string, length: number)=> void;
   addItem: (listName: string, item: QortalMetadata) => void;
   addItems: (listName: string, items: QortalMetadata[]) => void; 
   updateItem: (listName: string, item: QortalMetadata) => void;
@@ -35,6 +36,13 @@ export const useListStore = create<ListStore>((set, get) => ({
         [name]: { name, items }, // βœ… Store items as an array
       },
     })),
+  removeFromList: (name, length) =>
+    set((state) => ({
+      lists: {
+        ...state.lists,
+        [name]: { name, items: state.lists[name].items.slice(0, state.lists[name].items.length - length) }, // βœ… Store items as an array
+      },
+    })),
 
   addItem: (listName, item) =>
     set((state) => {