Skip to content

Commit

Permalink
Merge pull request #28 from pirateIV/feat/pagination
Browse files Browse the repository at this point in the history
feat/refactor: add pagination, create comp. scroller for fetch on scroll
  • Loading branch information
pirateIV authored Aug 16, 2024
2 parents 2421e55 + 4b04894 commit 4a60498
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 47 deletions.
9 changes: 1 addition & 8 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,7 @@ const App = () => {

return (
<div className="font-sans h-full w-full grid grid-rows-[1fr,max-content] lg:grid-rows-none lg:grid-cols-[max-content,1fr]">
<div
id="app-scroller"
className="lg:order-2 overflow-x-hidden overflow-y-auto"
>
<div>
{pathname === "/" ? <MediaComponent isRoot={true} /> : <Outlet />}
</div>
</div>
{pathname === "/" ? <MediaComponent isRoot={true} /> : <Outlet />}
<NavBar />
</div>
);
Expand Down
13 changes: 13 additions & 0 deletions src/components/AppScroller.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const AppScroller = ({ children, scrollerRef }) => {
return (
<div
id="app-scroller"
ref={scrollerRef}
className="lg:order-2 overflow-x-hidden overflow-y-auto"
>
<div>{children}</div>
</div>
);
};

export default AppScroller;
5 changes: 4 additions & 1 deletion src/pages/[type]/[id].jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -20,7 +21,9 @@ const MediaType = () => {

return (
<>
<HeroMedia item={item} />
<AppScroller>
<HeroMedia item={item} />
</AppScroller>
</>
);
};
Expand Down
75 changes: 59 additions & 16 deletions src/pages/[type]/category/[query].jsx
Original file line number Diff line number Diff line change
@@ -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 (
<MediaAutoLoadGrid type={type} media={media}>
<span className="capitalize">{query.replace(/_/g, " ")}</span>
<span>{pathname.includes("tv") ? "TV Shows" : "Movies"}</span>
</MediaAutoLoadGrid>
<AppScroller scrollerRef={scrollerRef}>
<MediaAutoLoadGrid type={type} media={media}>
<span className="capitalize">{query.replace(/_/g, " ")}</span>
<span>{pathname.includes("tv") ? "TV Shows" : "Movies"}</span>
</MediaAutoLoadGrid>
</AppScroller>
);
};

Expand Down
21 changes: 12 additions & 9 deletions src/pages/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -40,15 +41,17 @@ const MediaComponent = ({ isRoot = false }) => {

return (
<>
<Link
to={`/${type}/${item?.id || ""}`}
className={!item?.id ? "hover:cursor-not-allowed" : ""}
onClick={(e) => !item?.id && e.preventDefault()}
>
<HeroMedia type={type} item={item} />
</Link>
<CarouselAutoQuery media={media} queries={queries} />
<TheFooter />
<AppScroller>
<Link
to={`/${type}/${item?.id || ""}`}
className={!item?.id ? "hover:cursor-not-allowed" : ""}
onClick={(e) => !item?.id && e.preventDefault()}
>
<HeroMedia type={type} item={item} />
</Link>
<CarouselAutoQuery media={media} queries={queries} />
<TheFooter />
</AppScroller>
</>
);
};
Expand Down
29 changes: 16 additions & 13 deletions src/pages/search.jsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
import AppScroller from "@/components/AppScroller";
import useHead from "@/hooks/useHead";

const Search = () => {
useHead("Search");

return (
<div>
<div className="flex bg-[#9ca3af1a] items-center px-6 py-4 gap-3 sticky">
<div className="i-ph-magnifying-glass text-xl opacity-50"></div>
<input
type="text"
className="text-2xl bg-transparent outline-none w-full"
placeholder="Type to search..."
autoFocus={true}
/>
<AppScroller>
<div>
<div className="flex bg-[#9ca3af1a] items-center px-6 py-4 gap-3 sticky">
<div className="i-ph-magnifying-glass text-xl opacity-50"></div>
<input
type="text"
className="text-2xl bg-transparent outline-none w-full"
placeholder="Type to search..."
autoFocus={true}
/>
</div>
<div className="text-4xl p-10 opacity-50 text-center">
Type something to search...
</div>
</div>
<div className="text-4xl p-10 opacity-50 text-center">
Type something to search...
</div>
</div>
</AppScroller>
);
};

Expand Down

0 comments on commit 4a60498

Please sign in to comment.