Advertisement
_joel1024

Untitled

Aug 10th, 2024
387
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.     return (
  64.         <FlatList<T>
  65.             data={finalData}
  66.             renderItem={({ item }) => <RenderComponent item={item} />}
  67.             // @ts-expect-error id not in T
  68.             keyExtractor={(item) => item.id}
  69.             onEndReached={!isWeb ? handleEndReached : undefined}
  70.             ListFooterComponent={() => {
  71.                 const router = useRouter()
  72.                 return infinite ? <BottomLoader endReached={!hasNextPage} onEndReached={() => isWeb && handleEndReached()} /> :
  73.                     <ViewAllButton horizontal={!!flatListProps?.horizontal} button={(props) => <Button onPress={() => router.push("")} {...props} />} />
  74.             }}
  75.             {...flatListProps}
  76.         />
  77.     );
  78. }
  79.  
  80. const withEndReached = <T,>({ onEndReached, endReached, infinite, horizontal, viewAllLink }: { onEndReached: () => void, endReached: boolean, infinite: boolean, horizontal: boolean, viewAllLink: string }) => {
  81.     const isWeb = Platform.OS === "web"
  82.     return (props: FlatListProps<T>) => <FlatList
  83.         {...props}
  84.         onEndReached={() => !isWeb && onEndReached()}
  85.         ListFooterComponent={() => {
  86.             const router = useRouter()
  87.             return infinite ? <BottomLoader endReached={endReached} onEndReached={() => isWeb && onEndReached()} /> :
  88.                 <ViewAllButton horizontal={horizontal} button={(props) => <Button onPress={() => router.push(viewAllLink)} {...props} />} />
  89.         }
  90.         }
  91.     />
  92. }
  93.  
  94. const isWeb = Platform.OS === "web"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement