Advertisement
_joel1024

Untitled

Aug 10th, 2024
409
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import { Query } from "@directus/sdk"
  2. import { ComponentType, ReactElement, ReactNode, useCallback, useMemo } from "react"
  3. import { FlatList } from "./utils/virtual-lists"
  4. import { FlatListProps, Platform } from "react-native"
  5. import { BottomLoader } from "./cards/molecules/listings"
  6. import { ViewAllButton } from "./utils/common-ui"
  7. import { useRouter } from "app/hooks/router"
  8. import { Button } from "./ui/button"
  9. import { useInfiniteQuery } from "@tanstack/react-query"
  10. import { uniqBy } from "lodash"
  11. import { defaultLimit } from "app/lib/constants"
  12.  
  13. interface InfiniteListProps<T> {
  14.     component: React.ComponentType<{ item: T }>
  15.     queryKey: any[]
  16.     queryFn: (limit: number, page: number) => Promise<T[]>
  17.     initialItems: T[]
  18.     apiOptions?: Query<any, T>
  19.     infinite?: boolean
  20.     flatListProps?: Omit<FlatListProps<T>, "data" | "renderItem">
  21. }
  22.  
  23. export default function InfiniteList<T>(props: InfiniteListProps<T>) {
  24.     const { component: RenderComponent, queryKey, queryFn, initialItems, apiOptions = {}, infinite = false, flatListProps } = props;
  25.     const { limit = defaultLimit } = apiOptions;
  26.  
  27.     const { data, fetchNextPage, hasNextPage } = useInfiniteQuery<{ items: T[], page: number }>({
  28.         initialPageParam: 0,
  29.         getNextPageParam: (lastPage, allPages, lastPageParam) => {
  30.             if (lastPage.items.length < limit) {
  31.                 return null;
  32.             }
  33.             return Number(lastPageParam) + 1;
  34.         },
  35.         queryKey: queryKey,
  36.         queryFn: async ({ pageParam = 0 }) => {
  37.             const page = Number(pageParam);
  38.             return await queryFn(limit, page).then(res => ({
  39.                 items: res,
  40.                 page: page,
  41.             }));
  42.         },
  43.         initialData: {
  44.             pages: [{ items: initialItems, page: 0 }],
  45.             pageParams: [0],
  46.         },
  47.         enabled: infinite,
  48.     });
  49.  
  50.     const finalData = useMemo(() => {
  51.         return uniqBy(
  52.             data?.pages.reduce((acc, page) => acc.concat(page.items), [] as T[]),
  53.             "id"
  54.         );
  55.     }, [data]);
  56.  
  57.     const handleEndReached = useCallback(() => {
  58.         if (hasNextPage) {
  59.             fetchNextPage();
  60.         }
  61.     }, [hasNextPage]);
  62.  
  63.     const List = useMemo(
  64.         () =>
  65.             withEndReached<T>({
  66.                 onEndReached: handleEndReached,
  67.                 endReached: !hasNextPage,
  68.                 infinite: infinite,
  69.                 horizontal: !!flatListProps?.horizontal,
  70.                 viewAllLink: "",
  71.             }),
  72.         [handleEndReached, hasNextPage, infinite, flatListProps?.horizontal]
  73.     );
  74.  
  75.     return (
  76.         <List
  77.             data={finalData}
  78.             renderItem={({ item }) => <RenderComponent item={item} />}
  79.             {...flatListProps}
  80.         />
  81.     );
  82. }
  83.  
  84. const withEndReached = <T,>({ onEndReached, endReached, infinite, horizontal, viewAllLink }: { onEndReached: () => void, endReached: boolean, infinite: boolean, horizontal: boolean, viewAllLink: string }) => {
  85.     const isWeb = Platform.OS === "web"
  86.     return (props: FlatListProps<T>) => <FlatList
  87.         {...props}
  88.         onEndReached={() => !isWeb && onEndReached()}
  89.         ListFooterComponent={() => {
  90.             const router = useRouter()
  91.             return infinite ? <BottomLoader endReached={endReached} onEndReached={() => isWeb && onEndReached()} /> :
  92.                 <ViewAllButton horizontal={horizontal} button={(props) => <Button onPress={() => router.push(viewAllLink)} {...props} />} />
  93.         }
  94.         }
  95.     />
  96. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement