diff options
| author | Factiven <[email protected]> | 2023-04-23 23:34:10 +0700 |
|---|---|---|
| committer | Factiven <[email protected]> | 2023-04-23 23:34:10 +0700 |
| commit | 9f5d9cc424cfbcc6ac1819a5b4fa48fd7b57c22d (patch) | |
| tree | a5094c9bcabe4002a3e42ec6823b61f69557f611 /pages | |
| parent | Update [param].js (diff) | |
| download | moopa-9f5d9cc424cfbcc6ac1819a5b4fa48fd7b57c22d.tar.xz moopa-9f5d9cc424cfbcc6ac1819a5b4fa48fd7b57c22d.zip | |
Added Infinite Scroll at [param].js
Diffstat (limited to 'pages')
| -rw-r--r-- | pages/search/[param].js | 217 |
1 files changed, 141 insertions, 76 deletions
diff --git a/pages/search/[param].js b/pages/search/[param].js index ca20b40..78da79e 100644 --- a/pages/search/[param].js +++ b/pages/search/[param].js @@ -64,20 +64,23 @@ export default function Card() { hasil = null; tipe = "MANGA"; } - // console.log(hasil); + // ; const [search, setQuery] = useState(hasil); const [type, setSelectedType] = useState(tipe); const [seasonYear, setSeasonYear] = useState(); const [season, setSeason] = useState(); const [genres, setSelectedGenre] = useState(); - const [perPage, setPerPage] = useState(25); + const [perPage, setPerPage] = useState(10); const [sort, setSelectedSort] = useState(["POPULARITY_DESC"]); const [isVisible, setIsVisible] = useState(false); const inputRef = useRef(null); + const [page, setPage] = useState(1); + const [nextPage, setNextPage] = useState(true); + async function advance() { setLoading(true); const data = await aniAdvanceSearch( @@ -86,17 +89,55 @@ export default function Card() { seasonYear, season, genres, + page, perPage, sort ); - setData(data); + if (data.media.length === 0) { + setNextPage(false); + } else if (data !== null && page > 1) { + setData((prevData) => { + return [...(prevData ?? []), ...data.media]; + }); + setNextPage(data.pageInfo.hasNextPage); + } else { + setData(data.media); + } + setNextPage(data.pageInfo.hasNextPage); setLoading(false); } useEffect(() => { + setData(null); + setPage(1); + setNextPage(true); advance(); }, [search, type, seasonYear, season, genres, perPage, sort]); + useEffect(() => { + advance(); + }, [page]); + + useEffect(() => { + function handleScroll() { + if (page > 10 || !nextPage) { + window.removeEventListener("scroll", handleScroll); + return; + } + + if ( + window.innerHeight + window.pageYOffset >= + document.body.offsetHeight - 0 + ) { + setPage((prevPage) => prevPage + 1); + } + } + + window.addEventListener("scroll", handleScroll); + + return () => window.removeEventListener("scroll", handleScroll); + }, [page, nextPage]); + const handleKeyDown = async (event) => { if (event.key === "Enter") { event.preventDefault(); @@ -125,7 +166,7 @@ export default function Card() { router.push(`/search/${e.target.value.toLowerCase()}`); } - // console.log(genres); + // ); return ( <> @@ -171,7 +212,10 @@ export default function Card() { <h1 className="font-bold pb-5 text-md pl-1 font-outfit">SORT</h1> <select className="w-[297px] h-[46px] bg-secondary rounded-[10px] flex items-center text-center" - onChange={(e) => setSelectedSort(e.target.value)} + onChange={(e) => { + setSelectedSort(e.target.value); + setData(null); + }} > <option value={["POPULARITY_DESC"]}>Sort By</option> {sorts.map((sort) => ( @@ -242,11 +286,16 @@ export default function Card() { </h1> <select className="w-[195px] lg:w-[297px] lg:h-[46px] h-[35px] bg-secondary rounded-[10px] flex items-center text-center cursor-pointer hover:bg-[#272b35] transition-all duration-300" - onChange={(e) => setSelectedGenre(e.target.value)} + onChange={(e) => + setSelectedGenre( + e.target.value === "undefined" + ? undefined + : e.target.value + ) + } > - <option value={["Action"]}>Select a Genre</option> + <option value="undefined">Select a Genre</option> {genre.map((option) => { - // console.log(option); return ( <option key={option} value={option}> {option} @@ -278,7 +327,9 @@ export default function Card() { </h1> <select className="w-[195px] h-[35px] bg-secondary rounded-[10px] flex items-center text-center cursor-pointer hover:bg-[#272b35] transition-all duration-300" - onChange={(e) => setSelectedSort(e.target.value)} + onChange={(e) => { + setSelectedSort(e.target.value); + }} > <option value={["POPULARITY_DESC"]}>Sort By</option> {sorts.map((sort) => ( @@ -292,77 +343,91 @@ export default function Card() { )} </AnimatePresence> </div> - <AnimatePresence> - <div - key="card-keys" - className="grid pt-3 lg:grid-cols-5 justify-items-center grid-cols-3 w-screen px-2 lg:w-auto lg:gap-10 gap-2 lg:gap-y-24 gap-y-12 overflow-hidden" - > - {loading ? ( - <> - <SkeletonTheme baseColor="#3B3C41" highlightColor="#4D4E52"> - {[1, 2, 4, 5, 6, 7, 8].map((item) => ( - <div - key={item} - className="flex flex-col w-[115px] xs:w-[140px] lg:w-[228px] gap-5" - style={{ scale: 0.98 }} - > - <Skeleton className="lg:h-[313px] xs:h-[215px] h-[175px]" /> - <Skeleton width={110} height={30} /> + <div className="flex flex-col gap-14 items-center"> + <AnimatePresence> + <div + key="card-keys" + className="grid pt-3 lg:grid-cols-5 justify-items-center grid-cols-3 w-screen px-2 lg:w-auto lg:gap-10 gap-2 lg:gap-y-24 gap-y-12 overflow-hidden" + > + {loading + ? "" + : !data?.length && ( + <div className="w-screen text-[#ff7f57] lg:col-start-3 col-start-2 items-center flex justify-center text-center font-bold font-karla lg:text-2xl"> + Oops!<br></br> Nothing's Found... </div> - ))} - </SkeletonTheme> - </> - ) : data && data.media.length === 0 ? ( - <div className="w-screen text-[#ff7f57] lg:col-start-3 col-start-2 items-center flex justify-center text-center font-bold font-karla lg:text-2xl"> - Oops!<br></br> Nothing's Found... - </div> - ) : ( - data.media.map((anime) => { - return ( - <m.div - initial={{ scale: 0.9 }} - animate={{ scale: 1, transition: { duration: 0.35 } }} - className="w-[115px] xs:w-[140px] lg:w-[228px]" - key={anime.id} - > - <Link - href={ - anime.format === "MANGA" || anime.format === "NOVEL" - ? `/manga/detail/id?aniId=${anime.id}&aniTitle=${anime.title.userPreferred}` - : `/anime/${anime.id}` - } - className="" + )} + {data && + data?.map((anime, index) => { + return ( + <m.div + initial={{ scale: 0.9 }} + animate={{ scale: 1, transition: { duration: 0.35 } }} + className="w-[115px] xs:w-[140px] lg:w-[228px]" + key={index} > + <Link + href={ + anime.format === "MANGA" || anime.format === "NOVEL" + ? `/manga/detail/id?aniId=${anime.id}&aniTitle=${anime.title.userPreferred}` + : `/anime/${anime.id}` + } + className="" + > + <div + className=" bg-[#3B3C41] lg:h-[313px] xs:h-[215px] h-[175px] hover:scale-105 scale-100 transition-all cursor-pointer duration-200 ease-out rounded-[10px]" + style={{ + backgroundImage: `url(${anime.coverImage.extraLarge})`, + backgroundSize: "cover", + backgroundPosition: "center", + }} + /> + </Link> + <Link href={`/anime/${anime.id}`}> + <h1 className="font-outfit font-bold lg:text-[20px] pt-4 line-clamp-2"> + {anime.status === "RELEASING" ? ( + <span className="dots bg-green-500" /> + ) : anime.status === "NOT_YET_RELEASED" ? ( + <span className="dots bg-red-500" /> + ) : null} + {anime.title.userPreferred} + </h1> + </Link> + <h2 className="font-outfit lg:text-[15px] text-[11px] font-light pt-2 text-[#8B8B8B]"> + {anime.format || <p>-</p>} ·{" "} + {anime.status || <p>-</p>} ·{" "} + {anime.episodes || 0} Episodes + </h2> + </m.div> + ); + })} + + {loading && ( + <> + <SkeletonTheme baseColor="#3B3C41" highlightColor="#4D4E52"> + {[1, 2, 4, 5, 6, 7, 8].map((item) => ( <div - className=" bg-[#3B3C41] lg:h-[313px] xs:h-[215px] h-[175px] hover:scale-105 scale-100 transition-all cursor-pointer duration-200 ease-out rounded-[10px]" - style={{ - backgroundImage: `url(${anime.coverImage.extraLarge})`, - backgroundSize: "cover", - backgroundPosition: "center", - }} - /> - </Link> - <Link href={`/anime/${anime.id}`}> - <h1 className="font-outfit font-bold lg:text-[20px] pt-4 line-clamp-2"> - {anime.status === "RELEASING" ? ( - <span className="dots bg-green-500" /> - ) : anime.status === "NOT_YET_RELEASED" ? ( - <span className="dots bg-red-500" /> - ) : null} - {anime.title.userPreferred} - </h1> - </Link> - <h2 className="font-outfit lg:text-[15px] text-[11px] font-light pt-2 text-[#8B8B8B]"> - {anime.format || <p>-</p>} ·{" "} - {anime.status || <p>-</p>} · {anime.episodes || 0}{" "} - Episodes - </h2> - </m.div> - ); - }) + key={item} + className="flex flex-col w-[115px] xs:w-[140px] lg:w-[228px] gap-5" + style={{ scale: 0.98 }} + > + <Skeleton className="lg:h-[313px] xs:h-[215px] h-[175px]" /> + <Skeleton width={110} height={30} /> + </div> + ))} + </SkeletonTheme> + </> + )} + </div> + {!loading && page > 10 && nextPage && ( + <button + onClick={() => setPage((p) => p + 1)} + className="bg-secondary md:w-[30%] w-[80%] h-10 rounded-md" + > + Load More + </button> )} - </div> - </AnimatePresence> + </AnimatePresence> + </div> </div> <Footer /> </div> |