diff --git a/src/Router.tsx b/src/Router.tsx index bf4cef2..559b309 100644 --- a/src/Router.tsx +++ b/src/Router.tsx @@ -16,7 +16,10 @@ const router = createBrowserRouter([ { path: "/treasures", Component: ArtworksPage, - children: [{ index: true }, { path: ":id" }], + }, + { + path: "/treasures/:id", + Component: ArtworksPage, }, ], ErrorBoundary: () => ( diff --git a/src/components/ui/LazyImage.tsx b/src/components/ui/LazyImage.tsx index 23a5807..6a6e65f 100644 --- a/src/components/ui/LazyImage.tsx +++ b/src/components/ui/LazyImage.tsx @@ -4,32 +4,40 @@ import React, { useState } from "react"; type Props = React.ComponentProps<"img"> & { lazySrc: string; containerClassName?: string; + placeholderClassName?: string; + placeholder?: React.ReactNode; }; const LazyImage = ({ lazySrc, src, containerClassName, + placeholderClassName, className, + placeholder, ...props }: Props) => { const [isLoaded, setLoaded] = useState(false); return ( -
+
+
+ + {!isLoaded && placeholder ? placeholder : null} + setLoaded(true)} + onLoad={() => setTimeout(() => setLoaded(true), 50)} className={cn( - "transition-all", + "transition-all duration-500 relative z-[1]", isLoaded ? "opacity-100" : "opacity-0", className )} diff --git a/src/pages/artworks/ArtworkListing.tsx b/src/pages/artworks/ArtworkListing.tsx new file mode 100644 index 0000000..2d65246 --- /dev/null +++ b/src/pages/artworks/ArtworkListing.tsx @@ -0,0 +1,83 @@ +import pb from "@/utility/api"; +import { useInfiniteQuery } from "react-query"; +import { Link } from "react-router-dom"; +import LazyImage from "@/components/ui/LazyImage"; +import React, { useMemo } from "react"; +import Button from "@/components/ui/Button"; +import { useBottomScrollListener } from "react-bottom-scroll-listener"; +import { Skeleton } from "@/components/ui/Skeleton"; + +const ArtworkListing = () => { + const { data, isLoading, 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 items = useMemo( + () => data?.pages.flatMap((i) => i.items) || [], + [data] + ); + + return ( +
+
+ {items.map((item) => ( + + +
+

{item.artistName}

+
+ + ))} + + {isLoading || isFetchingNextPage + ? [...Array(12)].map((_, idx) => ( + + )) + : null} +
+ + {hasNextPage && !isFetchingNextPage ? ( +
+ +
+ ) : null} +
+ ); +}; + +export default React.memo(ArtworkListing); diff --git a/src/pages/artworks/page.tsx b/src/pages/artworks/page.tsx index d2967e8..d66657d 100644 --- a/src/pages/artworks/page.tsx +++ b/src/pages/artworks/page.tsx @@ -1,16 +1,11 @@ -import pb from "@/utility/api"; import { Howl } from "howler"; -import { useInfiniteQuery } from "react-query"; -import { Link, useNavigate, useParams } from "react-router-dom"; +import { useLocation, useNavigate, useParams } 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 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 { Skeleton } from "@/components/ui/Skeleton"; +import ArtworkListing from "./ArtworkListing"; +import { useCallback } from "react"; const openingChestSfx = new Howl({ src: openingSfx, @@ -20,31 +15,15 @@ const openingChestSfx = new Howl({ const ArtworksPage = () => { const { id: viewArtId } = useParams(); const navigate = useNavigate(); + const location = useLocation(); - const { data, isLoading, 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 items = useMemo( - () => data?.pages.flatMap((i) => i.items) || [], - [data] - ); + const goBack = useCallback(() => { + if (location.key !== "default") { + navigate(-1); + } else { + navigate("/treasures"); + } + }, [location, navigate]); return (
@@ -66,52 +45,9 @@ const ArtworksPage = () => {
-
- {items.map((item) => ( - - -
-

{item.artistName}

-
- - ))} + - {isLoading || isFetchingNextPage - ? [...Array(12)].map((_, idx) => ( - - )) - : null} -
- - {hasNextPage && !isFetchingNextPage ? ( -
- -
- ) : null} - - navigate("/treasures")} - /> +
); }; diff --git a/src/pages/artworks/viewSheet.tsx b/src/pages/artworks/viewSheet.tsx index 77cfef6..92e8945 100644 --- a/src/pages/artworks/viewSheet.tsx +++ b/src/pages/artworks/viewSheet.tsx @@ -5,6 +5,8 @@ import loadingIllust from "@/assets/images/l9fsdoa2j7vb1.gif"; import Badge from "@/components/ui/Badge"; import Button from "@/components/ui/Button"; import { ChevronLeft } from "lucide-react"; +import LazyImage from "@/components/ui/LazyImage"; +import { useEffect, useState } from "react"; type Props = { id?: string | null; @@ -12,13 +14,20 @@ type Props = { onClose: () => void; }; -const ViewSheet = ({ id, isOpen, onClose }: Props) => { +const ViewSheet = ({ id: viewId, isOpen, onClose }: Props) => { + const [id, setId] = useState(viewId); const { data, isLoading, isError } = useQuery({ queryKey: ["artwork", id], queryFn: () => pb.collection("artworks").getOne(id || ""), enabled: !!id, }); + useEffect(() => { + if (viewId) { + setId(viewId); + } + }, [viewId, setId]); + return ( {
- +

+ Loading... +

+
+ } />
-
+