diff --git a/package.json b/package.json index b740948..ea149f4 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "pixi.js": "^7.3.3", "pocketbase": "^0.20.1", "react": "^18.2.0", + "react-bottom-scroll-listener": "^5.1.0", "react-dom": "^18.2.0", "react-helmet": "^6.1.0", "react-query": "^3.39.3", diff --git a/src/pages/artworks/page.tsx b/src/pages/artworks/page.tsx index 26985ab..7a08c0f 100644 --- a/src/pages/artworks/page.tsx +++ b/src/pages/artworks/page.tsx @@ -1,6 +1,6 @@ import pb from "@/utility/api"; import { Howl } from "howler"; -import { useQuery } from "react-query"; +import { useInfiniteQuery } from "react-query"; import { Link } from "react-router-dom"; import playIcon from "@/assets/icons/play-outline.svg"; import openingSfx from "@/assets/audio/VO_JA_Furina_Opening_Treasure_Chest_02.ogg"; @@ -8,6 +8,10 @@ import ViewSheet from "./viewSheet"; import useModal from "@/hooks/useModal"; import LazyImage from "@/components/ui/LazyImage"; import PageMetadata from "@/components/containers/PageMetadata"; +import { useMemo } from "react"; +import Button from "@/components/ui/Button"; +import { useBottomScrollListener } from "react-bottom-scroll-listener"; +import loadingIllust from "@/assets/images/l9fsdoa2j7vb1.gif"; const openingChestSfx = new Howl({ src: openingSfx, @@ -15,13 +19,32 @@ const openingChestSfx = new Howl({ }); const ArtworksPage = () => { - const { data } = useQuery({ - queryKey: ["artworks"], - queryFn: () => - pb.collection("artworks").getList(1, 100, { sort: "-created" }), - }); + const { data, isFetchingNextPage, hasNextPage, fetchNextPage } = + useInfiniteQuery({ + queryKey: ["artworks"], + queryFn: ({ pageParam = 1 }) => { + return pb + .collection("artworks") + .getList(pageParam, 12, { sort: "-created" }); + }, + getNextPageParam: (lastPage) => + lastPage.page < lastPage.totalPages ? lastPage.page + 1 : undefined, + }); + useBottomScrollListener( + () => { + if (!isFetchingNextPage) { + fetchNextPage(); + } + }, + { offset: 100 } + ); const viewItemModal = useModal(); + const items = useMemo( + () => data?.pages.flatMap((i) => i.items) || [], + [data] + ); + return (
@@ -43,7 +66,7 @@ const ArtworksPage = () => {
- {data?.items.map((item) => ( + {items.map((item) => ( { ))}
+ {hasNextPage && !isFetchingNextPage ? ( +
+ +
+ ) : null} + + {isFetchingNextPage ? ( +
+ +

Loading next items..

+
+ ) : null} + ); diff --git a/yarn.lock b/yarn.lock index 9390768..b593cf0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2048,6 +2048,11 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" @@ -2418,6 +2423,13 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +react-bottom-scroll-listener@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/react-bottom-scroll-listener/-/react-bottom-scroll-listener-5.1.0.tgz#8544536ad794c47ee0728c117f988d69cb05e0ff" + integrity sha512-HI4qRKLbQ0Ox8xwIgYtLMk+1zETTaLtGBrhcTUFVRLL3OjVzfnyPPiXPGDnAPY6sGQh4KFH7Flp1dddnSmG33A== + dependencies: + lodash.debounce "^4.0.8" + react-dom@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"