diff --git a/src/App.jsx b/src/App.jsx index 02c90fa..f359a5f 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -10,14 +10,7 @@ const App = () => { return (
-
-
- {pathname === "/" ? : } -
-
+ {pathname === "/" ? : }
); diff --git a/src/components/AppScroller.jsx b/src/components/AppScroller.jsx new file mode 100644 index 0000000..e5f594e --- /dev/null +++ b/src/components/AppScroller.jsx @@ -0,0 +1,13 @@ +const AppScroller = ({ children, scrollerRef }) => { + return ( +
+
{children}
+
+ ); +}; + +export default AppScroller; diff --git a/src/pages/[type]/[id].jsx b/src/pages/[type]/[id].jsx index 180c954..18193d7 100644 --- a/src/pages/[type]/[id].jsx +++ b/src/pages/[type]/[id].jsx @@ -2,6 +2,7 @@ import { useEffect, useState } from "react"; import { getMedia } from "@/services/tmdb"; import { useLocation, useParams } from "react-router-dom"; import HeroMedia from "@/components/media/Hero"; +import AppScroller from "@/components/AppScroller"; const MediaType = () => { const { id } = useParams(); @@ -20,7 +21,9 @@ const MediaType = () => { return ( <> - + + + ); }; diff --git a/src/pages/[type]/category/[query].jsx b/src/pages/[type]/category/[query].jsx index 5537ae9..8c40d50 100644 --- a/src/pages/[type]/category/[query].jsx +++ b/src/pages/[type]/category/[query].jsx @@ -1,36 +1,79 @@ -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { listMedia } from "@/services/tmdb"; +import AppScroller from "@/components/AppScroller"; import { useLocation, useParams } from "react-router-dom"; import MediaAutoLoadGrid from "@/components/media/AutoLoadGrid"; const MediaQuery = () => { const { query } = useParams(); const { pathname } = useLocation(); + const [page, setPage] = useState(1); const [media, setMedia] = useState([]); + const [loading, setLoading] = useState(false); + const [hasMore, setHasMore] = useState(true); + + const scrollerRef = useRef(null); const type = pathname.includes("tv") ? "tv" : "movie"; + const fetchMediaPages = async (pageNum) => { + setLoading(true); + + try { + const res = await listMedia(type, query, pageNum); + const data = await res.data; + console.log(data?.results); + + if (data?.results.length === 0) { + setHasMore(false); // No more data to fetch + } else { + setMedia((prevMedia) => [...prevMedia, ...data?.results]); + } + } catch (error) { + console.log("Error occured fetching media", error); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + fetchMediaPages(page); + }, [page]); + useEffect(() => { - const fetchMediaPages = async () => { - try { - const res = await listMedia(type, query, page); - const data = await res.data; - console.log(data?.results); - - setMedia(data?.results); - } catch (error) { - console.log("Error occured fetching media", error); + const handleScroll = () => { + if (loading || !hasMore || !scrollerRef.current) return; + + const scroller = scrollerRef.current; + const scrollTop = scroller.scrollTop; + const scrollHeight = scroller.scrollHeight; + const clientHeight = scroller.clientHeight; + + if (scrollTop + clientHeight >= scrollHeight - 100) { + setPage((prevPage) => prevPage + 1); + } + }; + + const scroller = scrollerRef.current; + if (scroller) { + scroller.addEventListener("scroll", handleScroll); + } + + return () => { + if (scroller) { + scroller.removeEventListener("scroll", handleScroll); } }; - fetchMediaPages(); - }, []); + }, [loading, hasMore, scrollerRef]); return ( - - {query.replace(/_/g, " ")} - {pathname.includes("tv") ? "TV Shows" : "Movies"} - + + + {query.replace(/_/g, " ")} + {pathname.includes("tv") ? "TV Shows" : "Movies"} + + ); }; diff --git a/src/pages/index.jsx b/src/pages/index.jsx index 465fb31..c4c9fa2 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -5,6 +5,7 @@ import { getMedia, listMedia } from "@/services/tmdb"; import { useEffect, useState, useCallback, useMemo } from "react"; import { QUERY_LIST } from "@/constants/lists"; import TheFooter from "@/components/TheFooter"; +import AppScroller from "@/components/AppScroller"; const MediaComponent = ({ isRoot = false }) => { const { pathname } = useLocation(); @@ -40,15 +41,17 @@ const MediaComponent = ({ isRoot = false }) => { return ( <> - !item?.id && e.preventDefault()} - > - - - - + + !item?.id && e.preventDefault()} + > + + + + + ); }; diff --git a/src/pages/search.jsx b/src/pages/search.jsx index 9dfd8ab..27bb94d 100644 --- a/src/pages/search.jsx +++ b/src/pages/search.jsx @@ -1,23 +1,26 @@ +import AppScroller from "@/components/AppScroller"; import useHead from "@/hooks/useHead"; const Search = () => { useHead("Search"); return ( -
-
-
- + +
+
+
+ +
+
+ Type something to search... +
-
- Type something to search... -
-
+ ); };