fix lists expiry

This commit is contained in:
PhilReact 2025-06-08 05:21:25 +03:00
parent 190c1ce182
commit a9d824cb4d
3 changed files with 57 additions and 33 deletions

View File

@ -86,6 +86,10 @@ interface BaseProps {
scrollerRef?: React.RefObject<HTMLElement | null> scrollerRef?: React.RefObject<HTMLElement | null>
} }
const defaultStyles = {
gap: 1
}
// ✅ Restrict `direction` only when `disableVirtualization = false` // ✅ Restrict `direction` only when `disableVirtualization = false`
interface VirtualizedProps extends BaseProps { interface VirtualizedProps extends BaseProps {
disableVirtualization?: false; disableVirtualization?: false;
@ -103,9 +107,7 @@ type PropsResourceListDisplay = VirtualizedProps | NonVirtualizedProps;
export const MemorizedComponent = ({ export const MemorizedComponent = ({
search, search,
listItem, listItem,
styles = { styles = defaultStyles,
gap: 1,
},
defaultLoaderParams, defaultLoaderParams,
loaderItem, loaderItem,
loaderList, loaderList,
@ -127,7 +129,9 @@ export const MemorizedComponent = ({
scrollerRef scrollerRef
}: PropsResourceListDisplay) => { }: PropsResourceListDisplay) => {
const {identifierOperations, lists} = useGlobal() const {identifierOperations, lists} = useGlobal()
const memoizedParams = useMemo(() => JSON.stringify(search), [search]); const [generatedIdentifier, setGeneratedIdentifier] = useState("")
const [memoizedParams, setMemorizedParams] = useState('')
const setSearchParamsForList = useCacheStore((s) => s.setSearchParamsForList);
const memoizedParamsSearchNewData = useMemo(() => { const memoizedParamsSearchNewData = useMemo(() => {
if(searchNewData?.intervalSearch){ if(searchNewData?.intervalSearch){
return JSON.stringify(searchNewData?.intervalSearch) return JSON.stringify(searchNewData?.intervalSearch)
@ -155,10 +159,7 @@ const removeFromList = useListStore((s) => s.removeFromList);
const addItems = useListStore((s) => s.addItems); const addItems = useListStore((s) => s.addItems);
const [isLoadingMore, setIsLoadingMore] = useState(false)
const initialized = useRef(false)
const [generatedIdentifier, setGeneratedIdentifier] = useState("")
const prevGeneratedIdentifierRef = useRef('')
const searchIntervalRef = useRef<null | number>(null) const searchIntervalRef = useRef<null | number>(null)
const lastItemTimestampRef = useRef<null | number>(null) const lastItemTimestampRef = useRef<null | number>(null)
const stringifiedEntityParams = useMemo(()=> { const stringifiedEntityParams = useMemo(()=> {
@ -218,6 +219,8 @@ const addItems = useListStore((s) => s.addItems);
) )
if(res){ if(res){
setGeneratedIdentifier(res) setGeneratedIdentifier(res)
setMemorizedParams(JSON.stringify({...search, identifier: res}))
} }
} }
@ -226,10 +229,11 @@ const addItems = useListStore((s) => s.addItems);
return return
} }
setGeneratedIdentifier(search?.identifier) setGeneratedIdentifier(search?.identifier)
setMemorizedParams(JSON.stringify({...search, identifier: search?.identifier}))
} catch (error) { } catch (error) {
console.error(error) console.error(error)
} }
}, [stringifiedEntityParams, search.identifier, identifierOperations.buildSearchPrefix]) }, [stringifiedEntityParams, search , identifierOperations.buildSearchPrefix])
const getResourceList = useCallback(async () => { const getResourceList = useCallback(async () => {
try { try {
@ -243,9 +247,7 @@ const addItems = useListStore((s) => s.addItems);
lastItemTimestampRef.current = null lastItemTimestampRef.current = null
const parsedParams = {...(JSON.parse(memoizedParams))}; const parsedParams = {...(JSON.parse(memoizedParams))};
parsedParams.identifier = generatedIdentifier
const responseData = await lists.fetchResources(parsedParams, listName, returnType, true); // Awaiting the async function const responseData = await lists.fetchResources(parsedParams, listName, returnType, true); // Awaiting the async function
addList(listName, responseData || []); addList(listName, responseData || []);
if(onNewData){ if(onNewData){
onNewData(false) onNewData(false)
@ -255,7 +257,7 @@ const addItems = useListStore((s) => s.addItems);
} finally { } finally {
setIsLoading(false); setIsLoading(false);
} }
}, [memoizedParams, lists.fetchResources, generatedIdentifier]); // Added dependencies for re-fetching }, [memoizedParams, generatedIdentifier, lists.fetchResources]); // Added dependencies for re-fetching
const resetSearch = useCallback(async ()=> { const resetSearch = useCallback(async ()=> {
lists.deleteList(listName); lists.deleteList(listName);
@ -268,22 +270,28 @@ const addItems = useListStore((s) => s.addItems);
} }
}, [resetSearch]) }, [resetSearch])
useEffect(() => { useEffect(() => {
if(!generatedIdentifier) return if(!listName || !memoizedParams) return
const isExpired = useCacheStore.getState().isListExpired(listName);
if(typeof isListExpiredRef.current === 'string' && typeof memoizedParamsRef.current === 'string') { if(typeof isExpired === 'string' && typeof memoizedParams=== 'string') {
const parsedParams = {...(JSON.parse(memoizedParamsRef.current))}; let copyMemoizedParams = {...(JSON.parse(memoizedParams))}
parsedParams.identifier = generatedIdentifier delete copyMemoizedParams.after
const stringedParams = JSON.stringify(parsedParams) delete copyMemoizedParams.before
if(stringedParams === isListExpiredRef.current){ delete copyMemoizedParams.offset
copyMemoizedParams = JSON.stringify(copyMemoizedParams)
if(copyMemoizedParams === isExpired){
const copyParams = {...(JSON.parse(memoizedParams))}
delete copyParams.after
delete copyParams.before
delete copyParams.offset
setSearchParamsForList(listName, copyParams)
setIsLoading(false) setIsLoading(false)
return return
} }
} }
sessionStorage.removeItem(`scroll-position-${listName}`); sessionStorage.removeItem(`scroll-position-${listName}`);
prevGeneratedIdentifierRef.current = generatedIdentifier
getResourceList(); getResourceList();
}, [getResourceList, generatedIdentifier]); // Runs when dependencies change }, [getResourceList, listName]); // Runs when dependencies change
const {elementRef} = useScrollTracker(listName, list?.length > 0, scrollerRef ? true : !disableVirtualization ? true : disableScrollTracker); const {elementRef} = useScrollTracker(listName, list?.length > 0, scrollerRef ? true : !disableVirtualization ? true : disableScrollTracker);
useScrollTrackerRef(listName, list?.length > 0, scrollerRef) useScrollTrackerRef(listName, list?.length > 0, scrollerRef)
@ -317,11 +325,9 @@ const setResourceCacheExpiryDuration = useCacheStore((s) => s.setResourceCacheEx
const getResourceMoreList = useCallback(async (displayLimit?: number) => { const getResourceMoreList = useCallback(async (displayLimit?: number) => {
try { try {
if(!generatedIdentifier) return if(!generatedIdentifier) return
setIsLoadingMore(true)
const parsedParams = {...(JSON.parse(memoizedParams))}; const parsedParams = {...(JSON.parse(memoizedParams))};
parsedParams.before = list.length === 0 ? null : list[list.length - 1]?.created parsedParams.before = list.length === 0 ? null : list[list.length - 1]?.created
parsedParams.offset = null parsedParams.offset = null
parsedParams.identifier = generatedIdentifier
if(displayLimit){ if(displayLimit){
parsedParams.limit = displayLimit parsedParams.limit = displayLimit
} }
@ -329,13 +335,8 @@ const setResourceCacheExpiryDuration = useCacheStore((s) => s.setResourceCacheEx
addItems(listName, responseData || []) addItems(listName, responseData || [])
} catch (error) { } catch (error) {
console.error("Failed to fetch resources:", error); console.error("Failed to fetch resources:", error);
} finally { }
setTimeout(() => { }, [memoizedParams, listName, list]);
setIsLoadingMore(false);
}, 1000);
}
}, [memoizedParams, listName, list, generatedIdentifier]);

View File

@ -27,6 +27,7 @@ export const useResources = (retryAttempts: number = 2) => {
const setResourceCache = useCacheStore((s) => s.setResourceCache); const setResourceCache = useCacheStore((s) => s.setResourceCache);
const addTemporaryResource = useCacheStore((s) => s.addTemporaryResource); const addTemporaryResource = useCacheStore((s) => s.addTemporaryResource);
const markResourceAsDeleted = useCacheStore((s) => s.markResourceAsDeleted); const markResourceAsDeleted = useCacheStore((s) => s.markResourceAsDeleted);
const setSearchParamsForList = useCacheStore((s) => s.setSearchParamsForList);
const deleteList = useListStore(state => state.deleteList) const deleteList = useListStore(state => state.deleteList)
const requestControllers = new Map<string, AbortController>(); const requestControllers = new Map<string, AbortController>();
@ -207,6 +208,11 @@ export const useResources = (retryAttempts: number = 2) => {
const cacheKey = generateCacheKey(params); const cacheKey = generateCacheKey(params);
const searchCache = getSearchCache(listName, cacheKey); const searchCache = getSearchCache(listName, cacheKey);
if (searchCache) { if (searchCache) {
const copyParams = {...params}
delete copyParams.after
delete copyParams.before
delete copyParams.offset
setSearchParamsForList(listName, JSON.stringify(copyParams))
return searchCache; return searchCache;
} }
@ -240,8 +246,11 @@ export const useResources = (retryAttempts: number = 2) => {
lastCreated = responseData[responseData.length - 1]?.created; lastCreated = responseData[responseData.length - 1]?.created;
if (!lastCreated) break; if (!lastCreated) break;
} }
const copyParams = {...params}
setSearchCache(listName, cacheKey, filteredResults, cancelRequests ? JSON.stringify(params) : null); delete copyParams.after
delete copyParams.before
delete copyParams.offset
setSearchCache(listName, cacheKey, filteredResults, cancelRequests ? JSON.stringify(copyParams) : null);
fetchDataFromResults(filteredResults, returnType); fetchDataFromResults(filteredResults, returnType);
return filteredResults; return filteredResults;

View File

@ -57,6 +57,7 @@ interface CacheState {
setResourceCache: (id: string, data: ListItem | false | null, customExpiry?: number) => void; setResourceCache: (id: string, data: ListItem | false | null, customExpiry?: number) => void;
setSearchCache: (listName: string, searchTerm: string, data: QortalMetadata[], searchParamsStringified: string | null, customExpiry?: number) => void; setSearchCache: (listName: string, searchTerm: string, data: QortalMetadata[], searchParamsStringified: string | null, customExpiry?: number) => void;
setSearchParamsForList: (ListName: string, searchParamsStringified: string)=> void;
getSearchCache: (listName: string, searchTerm: string) => QortalMetadata[] | null; getSearchCache: (listName: string, searchTerm: string) => QortalMetadata[] | null;
clearExpiredCache: () => void; clearExpiredCache: () => void;
getResourceCache: (id: string, ignoreExpire?: boolean) => ListItem | false | null; getResourceCache: (id: string, ignoreExpire?: boolean) => ListItem | false | null;
@ -127,7 +128,20 @@ export const useCacheStore = create<CacheState>
}, },
}; };
}), }),
setSearchParamsForList: (listName, searchParamsStringified) =>
set((state) => {
const existingList = state.searchCache[listName] || {};
return {
searchCache: {
...state.searchCache,
[listName]: {
...existingList,
searchParamsStringified,
},
},
};
}),
getSearchCache: (listName, searchTerm) => { getSearchCache: (listName, searchTerm) => {
const cache = get().searchCache[listName]; const cache = get().searchCache[listName];