120 lines
3.6 KiB
TypeScript
Raw Normal View History

2024-01-10 22:24:12 +07:00
import pb from "@/utility/api";
import { Howl } from "howler";
2024-01-10 17:48:16 +00:00
import { useInfiniteQuery } from "react-query";
2024-01-10 22:24:12 +07:00
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";
import ViewSheet from "./viewSheet";
import useModal from "@/hooks/useModal";
import LazyImage from "@/components/ui/LazyImage";
import PageMetadata from "@/components/containers/PageMetadata";
2024-01-10 17:48:16 +00:00
import { useMemo } from "react";
import Button from "@/components/ui/Button";
import { useBottomScrollListener } from "react-bottom-scroll-listener";
2024-01-11 03:46:26 +00:00
import { Skeleton } from "@/components/ui/Skeleton";
2024-01-10 22:24:12 +07:00
const openingChestSfx = new Howl({
src: openingSfx,
preload: true,
});
const ArtworksPage = () => {
2024-01-11 03:46:26 +00:00
const { data, isLoading, isFetchingNextPage, hasNextPage, fetchNextPage } =
2024-01-10 17:48:16 +00:00
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<HTMLDivElement>(
() => {
if (!isFetchingNextPage) {
fetchNextPage();
}
},
{ offset: 100 }
);
2024-01-10 22:24:12 +07:00
const viewItemModal = useModal<string>();
2024-01-10 17:48:16 +00:00
const items = useMemo(
() => data?.pages.flatMap((i) => i.items) || [],
[data]
);
2024-01-10 22:24:12 +07:00
return (
<div className="container py-16">
<PageMetadata title="Treasures" />
2024-01-10 22:24:12 +07:00
<h1 className="text-2xl">Treasures</h1>
<div>
<p className="italic inline">Take it. Ahem... I allow you!</p>
<button
type="button"
className="bg-white rounded border-2 border-primary-300 hover:bg-gray-200 p-1 md:p-0.5 ml-2"
>
<img
src={playIcon}
alt="play"
className="h-4"
onClick={() => openingChestSfx.play()}
/>
</button>
</div>
<div className="grid grid-cols-2 md:grid-cols-3 xl:grid-cols-4 gap-4 mt-8">
2024-01-10 17:48:16 +00:00
{items.map((item) => (
2024-01-10 22:24:12 +07:00
<Link
key={item.id}
// to={`/treasures/${item.id}`}
to="#"
className="bg-white rounded-lg shadow border border-gray-300 overflow-hidden hover:scale-105 transition-all relative"
onClick={(e) => {
e.preventDefault();
viewItemModal.onOpen(item.id);
}}
>
<LazyImage
lazySrc={pb.files.getUrl(item, item.image, { thumb: "32x48" })}
2024-01-10 16:00:34 +00:00
src={pb.files.getUrl(item, item.image, { thumb: "256x384" })}
2024-01-10 22:24:12 +07:00
className="w-full aspect-[0.8] object-cover"
/>
<div className="absolute bottom-2 left-2 px-3 py-1 rounded-md bg-black/20 backdrop-blur-sm">
<p className="text-white">{item.artistName}</p>
</div>
</Link>
))}
2024-01-11 03:46:26 +00:00
{isLoading || isFetchingNextPage
? [...Array(12)].map((_, idx) => (
<Skeleton key={idx} className="aspect-[0.8]" />
))
: null}
2024-01-10 22:24:12 +07:00
</div>
2024-01-10 17:48:16 +00:00
{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}
2024-01-10 22:24:12 +07:00
<ViewSheet modal={viewItemModal} />
</div>
);
};
export default ArtworksPage;