feat: infinite scroll
This commit is contained in:
parent
93fd7d7526
commit
30f63454e3
@ -19,6 +19,7 @@
|
|||||||
"pixi.js": "^7.3.3",
|
"pixi.js": "^7.3.3",
|
||||||
"pocketbase": "^0.20.1",
|
"pocketbase": "^0.20.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
"react-bottom-scroll-listener": "^5.1.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-helmet": "^6.1.0",
|
"react-helmet": "^6.1.0",
|
||||||
"react-query": "^3.39.3",
|
"react-query": "^3.39.3",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import pb from "@/utility/api";
|
import pb from "@/utility/api";
|
||||||
import { Howl } from "howler";
|
import { Howl } from "howler";
|
||||||
import { useQuery } from "react-query";
|
import { useInfiniteQuery } from "react-query";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import playIcon from "@/assets/icons/play-outline.svg";
|
import playIcon from "@/assets/icons/play-outline.svg";
|
||||||
import openingSfx from "@/assets/audio/VO_JA_Furina_Opening_Treasure_Chest_02.ogg";
|
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 useModal from "@/hooks/useModal";
|
||||||
import LazyImage from "@/components/ui/LazyImage";
|
import LazyImage from "@/components/ui/LazyImage";
|
||||||
import PageMetadata from "@/components/containers/PageMetadata";
|
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({
|
const openingChestSfx = new Howl({
|
||||||
src: openingSfx,
|
src: openingSfx,
|
||||||
@ -15,13 +19,32 @@ const openingChestSfx = new Howl({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const ArtworksPage = () => {
|
const ArtworksPage = () => {
|
||||||
const { data } = useQuery({
|
const { data, isFetchingNextPage, hasNextPage, fetchNextPage } =
|
||||||
|
useInfiniteQuery({
|
||||||
queryKey: ["artworks"],
|
queryKey: ["artworks"],
|
||||||
queryFn: () =>
|
queryFn: ({ pageParam = 1 }) => {
|
||||||
pb.collection("artworks").getList(1, 100, { sort: "-created" }),
|
return pb
|
||||||
|
.collection("artworks")
|
||||||
|
.getList(pageParam, 12, { sort: "-created" });
|
||||||
|
},
|
||||||
|
getNextPageParam: (lastPage) =>
|
||||||
|
lastPage.page < lastPage.totalPages ? lastPage.page + 1 : undefined,
|
||||||
});
|
});
|
||||||
|
useBottomScrollListener<HTMLDivElement>(
|
||||||
|
() => {
|
||||||
|
if (!isFetchingNextPage) {
|
||||||
|
fetchNextPage();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ offset: 100 }
|
||||||
|
);
|
||||||
const viewItemModal = useModal<string>();
|
const viewItemModal = useModal<string>();
|
||||||
|
|
||||||
|
const items = useMemo(
|
||||||
|
() => data?.pages.flatMap((i) => i.items) || [],
|
||||||
|
[data]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container py-16">
|
<div className="container py-16">
|
||||||
<PageMetadata title="Treasures" />
|
<PageMetadata title="Treasures" />
|
||||||
@ -43,7 +66,7 @@ const ArtworksPage = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-2 md:grid-cols-3 xl:grid-cols-4 gap-4 mt-8">
|
<div className="grid grid-cols-2 md:grid-cols-3 xl:grid-cols-4 gap-4 mt-8">
|
||||||
{data?.items.map((item) => (
|
{items.map((item) => (
|
||||||
<Link
|
<Link
|
||||||
key={item.id}
|
key={item.id}
|
||||||
// to={`/treasures/${item.id}`}
|
// to={`/treasures/${item.id}`}
|
||||||
@ -66,6 +89,29 @@ const ArtworksPage = () => {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{hasNextPage && !isFetchingNextPage ? (
|
||||||
|
<div className="flex justify-center mt-8">
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
if (!isFetchingNextPage) {
|
||||||
|
fetchNextPage();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
variant="solid"
|
||||||
|
className="min-w-[200px]"
|
||||||
|
>
|
||||||
|
Load More
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{isFetchingNextPage ? (
|
||||||
|
<div className="flex flex-col justify-center items-center text-center mt-12 py-8">
|
||||||
|
<img src={loadingIllust} className="h-32 animate-bounce" />
|
||||||
|
<p className="mt-2">Loading next items..</p>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
<ViewSheet modal={viewItemModal} />
|
<ViewSheet modal={viewItemModal} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
12
yarn.lock
12
yarn.lock
@ -2048,6 +2048,11 @@ locate-path@^6.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
p-locate "^5.0.0"
|
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:
|
lodash.merge@^4.6.2:
|
||||||
version "4.6.2"
|
version "4.6.2"
|
||||||
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
|
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"
|
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
|
||||||
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
|
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:
|
react-dom@^18.2.0:
|
||||||
version "18.2.0"
|
version "18.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
|
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user