mirror of
https://github.com/Qortal/qapp-core.git
synced 2025-06-15 01:41:21 +00:00
added custom expiration to caches
This commit is contained in:
parent
52f1d570a6
commit
dcfe746b5b
@ -1,7 +1,7 @@
|
|||||||
import React, { useRef, useEffect, useState, useCallback } from "react";
|
import React, { useEffect, useState, useCallback } from "react";
|
||||||
import DynamicGrid from "./DynamicGrid";
|
import DynamicGrid from "./DynamicGrid";
|
||||||
import LazyLoad from "../../common/LazyLoad";
|
import LazyLoad from "../../common/LazyLoad";
|
||||||
import { ListItem } from "../../state/cache";
|
import { ListItem, useCacheStore } from "../../state/cache";
|
||||||
import { QortalMetadata } from "../../types/interfaces/resources";
|
import { QortalMetadata } from "../../types/interfaces/resources";
|
||||||
import { ListItemWrapper } from "./ResourceListDisplay";
|
import { ListItemWrapper } from "./ResourceListDisplay";
|
||||||
|
|
||||||
@ -15,6 +15,7 @@ interface HorizontalPaginatedListProps {
|
|||||||
gap?: number;
|
gap?: number;
|
||||||
isLoading?: boolean;
|
isLoading?: boolean;
|
||||||
onSeenLastItem?: (listItem: ListItem) => void;
|
onSeenLastItem?: (listItem: ListItem) => void;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const HorizontalPaginatedList = ({
|
export const HorizontalPaginatedList = ({
|
||||||
@ -27,26 +28,25 @@ export const HorizontalPaginatedList = ({
|
|||||||
gap,
|
gap,
|
||||||
isLoading,
|
isLoading,
|
||||||
onSeenLastItem,
|
onSeenLastItem,
|
||||||
|
|
||||||
}: HorizontalPaginatedListProps) => {
|
}: HorizontalPaginatedListProps) => {
|
||||||
const listRef = useRef<HTMLDivElement | null>(null);
|
|
||||||
const [displayedItems, setDisplayedItems] = useState(items);
|
const [displayedItems, setDisplayedItems] = useState(items);
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setDisplayedItems(items);
|
setDisplayedItems(items);
|
||||||
}, [items]);
|
}, [items]);
|
||||||
|
|
||||||
const preserveScroll = useCallback((updateFunction: () => void) => {
|
const preserveScroll = useCallback((updateFunction: () => void) => {
|
||||||
const container = listRef.current;
|
const previousScrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
|
||||||
if (!container) return;
|
const previousScrollWidth = document.documentElement.scrollWidth || document.body.scrollWidth;
|
||||||
|
|
||||||
const previousScrollLeft = container.scrollLeft;
|
|
||||||
const previousScrollWidth = container.scrollWidth;
|
|
||||||
|
|
||||||
updateFunction(); // Perform the update (fetch new data, remove old)
|
updateFunction(); // Perform the update (fetch new data, remove old)
|
||||||
|
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
const newScrollWidth = container.scrollWidth;
|
const newScrollWidth = document.documentElement.scrollWidth || document.body.scrollWidth;
|
||||||
container.scrollLeft = previousScrollLeft - (previousScrollWidth - newScrollWidth);
|
document.documentElement.scrollLeft = document.body.scrollLeft =
|
||||||
|
previousScrollLeft - (previousScrollWidth - newScrollWidth);
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -60,28 +60,23 @@ export const HorizontalPaginatedList = ({
|
|||||||
}, [displayedItems, maxItems, preserveScroll]);
|
}, [displayedItems, maxItems, preserveScroll]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const container = listRef.current;
|
|
||||||
if (!container) return;
|
|
||||||
|
|
||||||
const handleScroll = () => {
|
const handleScroll = () => {
|
||||||
if (
|
const scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
|
||||||
container.scrollLeft + container.clientWidth >= container.scrollWidth - 10 &&
|
const clientWidth = document.documentElement.clientWidth || document.body.clientWidth;
|
||||||
!isLoading
|
const scrollWidth = document.documentElement.scrollWidth || document.body.scrollWidth;
|
||||||
) {
|
|
||||||
|
if (scrollLeft + clientWidth >= scrollWidth - 10 && !isLoading) {
|
||||||
onLoadMore();
|
onLoadMore();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
container.addEventListener("scroll", handleScroll);
|
window.addEventListener("scroll", handleScroll);
|
||||||
return () => container.removeEventListener("scroll", handleScroll);
|
return () => window.removeEventListener("scroll", handleScroll);
|
||||||
}, [onLoadMore, isLoading]);
|
}, [onLoadMore, isLoading]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={listRef} style={{
|
<div style={{ overflow: "auto", width: "100%", display: "flex", flexGrow: 1 }}>
|
||||||
overflow: 'auto', width: '100%', display: 'flex', flexGrow: 1
|
|
||||||
}}>
|
|
||||||
<DynamicGrid
|
<DynamicGrid
|
||||||
|
|
||||||
minItemWidth={minItemWidth}
|
minItemWidth={minItemWidth}
|
||||||
gap={gap}
|
gap={gap}
|
||||||
items={displayedItems.map((item, index) => (
|
items={displayedItems.map((item, index) => (
|
||||||
@ -95,19 +90,17 @@ export const HorizontalPaginatedList = ({
|
|||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
>
|
>
|
||||||
{!isLoading && displayedItems.length > 0 && (
|
{!isLoading && displayedItems.length > 0 && (
|
||||||
<LazyLoad
|
<LazyLoad
|
||||||
onLoadMore={() => {
|
onLoadMore={() => {
|
||||||
onLoadMore();
|
onLoadMore();
|
||||||
if (onSeenLastItem) {
|
if (onSeenLastItem) {
|
||||||
// onSeenLastItem(displayedItems[displayedItems.length - 1]);
|
// onSeenLastItem(displayedItems[displayedItems.length - 1]);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</DynamicGrid>
|
</DynamicGrid>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -23,6 +23,7 @@ import DynamicGrid from "./DynamicGrid";
|
|||||||
import LazyLoad from "../../common/LazyLoad";
|
import LazyLoad from "../../common/LazyLoad";
|
||||||
import { useListStore } from "../../state/lists";
|
import { useListStore } from "../../state/lists";
|
||||||
import { useScrollTracker } from "../../common/useScrollTracker";
|
import { useScrollTracker } from "../../common/useScrollTracker";
|
||||||
|
import { HorizontalPaginatedList } from "./HorizontalPaginationList";
|
||||||
type Direction = "VERTICAL" | "HORIZONTAL";
|
type Direction = "VERTICAL" | "HORIZONTAL";
|
||||||
|
|
||||||
interface ResourceListStyles {
|
interface ResourceListStyles {
|
||||||
@ -54,6 +55,8 @@ interface BaseProps {
|
|||||||
onSeenLastItem?: (listItem: QortalMetadata) => void;
|
onSeenLastItem?: (listItem: QortalMetadata) => void;
|
||||||
listName: string,
|
listName: string,
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
|
searchCacheDuration?: number
|
||||||
|
resourceCacheDuration?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✅ Restrict `direction` only when `disableVirtualization = false`
|
// ✅ Restrict `direction` only when `disableVirtualization = false`
|
||||||
@ -82,6 +85,8 @@ export const MemorizedComponent = ({
|
|||||||
direction = "VERTICAL",
|
direction = "VERTICAL",
|
||||||
onSeenLastItem,
|
onSeenLastItem,
|
||||||
listName,
|
listName,
|
||||||
|
searchCacheDuration,
|
||||||
|
resourceCacheDuration
|
||||||
}: PropsResourceListDisplay) => {
|
}: PropsResourceListDisplay) => {
|
||||||
const { fetchResources } = useResources();
|
const { fetchResources } = useResources();
|
||||||
const { getTemporaryResources, filterOutDeletedResources } = useCacheStore();
|
const { getTemporaryResources, filterOutDeletedResources } = useCacheStore();
|
||||||
@ -93,12 +98,6 @@ export const MemorizedComponent = ({
|
|||||||
const list = useListStore().getListByName(listName)
|
const list = useListStore().getListByName(listName)
|
||||||
const isListExpired = useCacheStore().isListExpired(listName)
|
const isListExpired = useCacheStore().isListExpired(listName)
|
||||||
const initialized = useRef(false)
|
const initialized = useRef(false)
|
||||||
useScrollTracker(listName);
|
|
||||||
|
|
||||||
const listToDisplay = useMemo(()=> {
|
|
||||||
return filterOutDeletedResources([...getTemporaryResources(listName), ...list])
|
|
||||||
}, [list, listName, filterOutDeletedResources, getTemporaryResources])
|
|
||||||
|
|
||||||
|
|
||||||
const getResourceList = useCallback(async () => {
|
const getResourceList = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
@ -122,6 +121,37 @@ export const MemorizedComponent = ({
|
|||||||
}
|
}
|
||||||
}, [memoizedParams, fetchResources]); // Added dependencies for re-fetching
|
}, [memoizedParams, fetchResources]); // Added dependencies for re-fetching
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if(initialized.current) return
|
||||||
|
initialized.current = true
|
||||||
|
if(!isListExpired) return
|
||||||
|
|
||||||
|
sessionStorage.removeItem(`scroll-position-${listName}`);
|
||||||
|
getResourceList();
|
||||||
|
}, [getResourceList, isListExpired]); // Runs when dependencies change
|
||||||
|
|
||||||
|
useScrollTracker(listName);
|
||||||
|
|
||||||
|
const setSearchCacheExpiryDuration = useCacheStore().setSearchCacheExpiryDuration
|
||||||
|
const setResourceCacheExpiryDuration = useCacheStore().setResourceCacheExpiryDuration
|
||||||
|
useEffect(()=> {
|
||||||
|
if(searchCacheDuration){
|
||||||
|
setSearchCacheExpiryDuration(searchCacheDuration)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
useEffect(()=> {
|
||||||
|
if(resourceCacheDuration){
|
||||||
|
setResourceCacheExpiryDuration(resourceCacheDuration)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const listToDisplay = useMemo(()=> {
|
||||||
|
return filterOutDeletedResources([...getTemporaryResources(listName), ...list])
|
||||||
|
}, [list, listName, filterOutDeletedResources, getTemporaryResources])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const getResourceMoreList = useCallback(async () => {
|
const getResourceMoreList = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
// setIsLoading(true);
|
// setIsLoading(true);
|
||||||
@ -137,13 +167,7 @@ export const MemorizedComponent = ({
|
|||||||
}
|
}
|
||||||
}, [memoizedParams, listName, list]);
|
}, [memoizedParams, listName, list]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if(initialized.current) return
|
|
||||||
initialized.current = true
|
|
||||||
if(!isListExpired) return
|
|
||||||
sessionStorage.removeItem(`scroll-position-${listName}`);
|
|
||||||
getResourceList();
|
|
||||||
}, [getResourceList, isListExpired]); // Runs when dependencies change
|
|
||||||
|
|
||||||
const disabledVirutalizationStyles: CSSProperties = useMemo(() => {
|
const disabledVirutalizationStyles: CSSProperties = useMemo(() => {
|
||||||
if (styles?.disabledVirutalizationStyles?.parentContainer)
|
if (styles?.disabledVirutalizationStyles?.parentContainer)
|
||||||
@ -212,7 +236,6 @@ export const MemorizedComponent = ({
|
|||||||
)}
|
)}
|
||||||
{disableVirtualization && direction === "HORIZONTAL" && (
|
{disableVirtualization && direction === "HORIZONTAL" && (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
<DynamicGrid
|
<DynamicGrid
|
||||||
minItemWidth={styles?.horizontalStyles?.minItemWidth}
|
minItemWidth={styles?.horizontalStyles?.minItemWidth}
|
||||||
gap={styles?.gap}
|
gap={styles?.gap}
|
||||||
|
@ -249,7 +249,7 @@ export const useResources = () => {
|
|||||||
fetchIndividualPublish,
|
fetchIndividualPublish,
|
||||||
addNewResources,
|
addNewResources,
|
||||||
updateNewResources,
|
updateNewResources,
|
||||||
deleteProduct
|
deleteProduct,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -65,14 +65,21 @@ interface CacheState {
|
|||||||
markResourceAsDeleted: (item: QortalMetadata) => void;
|
markResourceAsDeleted: (item: QortalMetadata) => void;
|
||||||
filterOutDeletedResources: (items: QortalMetadata[]) => QortalMetadata[];
|
filterOutDeletedResources: (items: QortalMetadata[]) => QortalMetadata[];
|
||||||
isListExpired: (listName: string)=> boolean
|
isListExpired: (listName: string)=> boolean
|
||||||
|
searchCacheExpiryDuration: number;
|
||||||
|
resourceCacheExpiryDuration: number;
|
||||||
|
setSearchCacheExpiryDuration: (duration: number) => void;
|
||||||
|
setResourceCacheExpiryDuration: (duration: number)=> void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useCacheStore = create<CacheState>
|
export const useCacheStore = create<CacheState>
|
||||||
((set, get) => ({
|
((set, get) => ({
|
||||||
|
searchCacheExpiryDuration: 5 * 60 * 1000,
|
||||||
|
resourceCacheExpiryDuration: 30 * 60 * 1000,
|
||||||
resourceCache: {},
|
resourceCache: {},
|
||||||
searchCache: {},
|
searchCache: {},
|
||||||
deletedResources: {},
|
deletedResources: {},
|
||||||
|
setSearchCacheExpiryDuration: (duration) => set({ searchCacheExpiryDuration: duration }),
|
||||||
|
setResourceCacheExpiryDuration: (duration) => set({ resourceCacheExpiryDuration: duration }),
|
||||||
getResourceCache: (id, ignoreExpire) => {
|
getResourceCache: (id, ignoreExpire) => {
|
||||||
const cache = get().resourceCache[id];
|
const cache = get().resourceCache[id];
|
||||||
if (cache) {
|
if (cache) {
|
||||||
@ -91,7 +98,7 @@ export const useCacheStore = create<CacheState>
|
|||||||
|
|
||||||
setResourceCache: (id, data, customExpiry) =>
|
setResourceCache: (id, data, customExpiry) =>
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const expiry = Date.now() + (customExpiry || 30 * 60 * 1000); // 30 mins
|
const expiry = Date.now() + (customExpiry || get().resourceCacheExpiryDuration);
|
||||||
return {
|
return {
|
||||||
resourceCache: {
|
resourceCache: {
|
||||||
...state.resourceCache,
|
...state.resourceCache,
|
||||||
@ -100,24 +107,25 @@ export const useCacheStore = create<CacheState>
|
|||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
|
|
||||||
setSearchCache: (listName, searchTerm, data, customExpiry) =>
|
setSearchCache: (listName, searchTerm, data, customExpiry) =>
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const expiry = Date.now() + (customExpiry || 5 * 60 * 1000); // 5 mins
|
const expiry = Date.now() + (customExpiry || get().searchCacheExpiryDuration);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
searchCache: {
|
searchCache: {
|
||||||
...state.searchCache,
|
...state.searchCache,
|
||||||
[listName]: {
|
[listName]: {
|
||||||
searches: {
|
searches: {
|
||||||
...(state.searchCache[listName]?.searches || {}),
|
...(state.searchCache[listName]?.searches || {}),
|
||||||
[searchTerm]: data,
|
[searchTerm]: data,
|
||||||
|
},
|
||||||
|
temporaryNewResources: state.searchCache[listName]?.temporaryNewResources || [],
|
||||||
|
expiry,
|
||||||
},
|
},
|
||||||
temporaryNewResources: state.searchCache[listName]?.temporaryNewResources || [],
|
|
||||||
expiry,
|
|
||||||
},
|
},
|
||||||
},
|
};
|
||||||
};
|
}),
|
||||||
}),
|
|
||||||
|
|
||||||
getSearchCache: (listName, searchTerm) => {
|
getSearchCache: (listName, searchTerm) => {
|
||||||
const cache = get().searchCache[listName];
|
const cache = get().searchCache[listName];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user