Skip to content

Commit d5a99ef

Browse files
⚙️ Added Episode Section
1 parent f4f6a7f commit d5a99ef

File tree

9 files changed

+171
-14
lines changed

9 files changed

+171
-14
lines changed

app/search/page.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ function searchPage({}: Props) {
1919
>
2020
<ToastContainerBar />
2121
<Navbar />
22-
<main>
22+
<main className="pl-4 pb-24 lg:space-y-24">
2323
<SearchComponent />
2424
</main>
2525
<Footer />

app/season/[id]/page.tsx

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
"use client";
2+
3+
import React, { useEffect, useState } from "react";
4+
import { motion } from "framer-motion";
5+
import Navbar from "@/components/Navbar";
6+
import Footer from "@/components/Footer";
7+
import { usePathname, useSearchParams } from "next/navigation";
8+
import GlobalLoading from "@/components/GlobalLoading";
9+
import SeasonFeed from "@/components/SeasonFeed";
10+
11+
type Props = {};
12+
13+
function SeasonPage({}: Props) {
14+
const pathname = usePathname();
15+
const searchParams = useSearchParams()!;
16+
const [seasons, setSeasons] = useState([]);
17+
const [loading, setLoading] = useState(true);
18+
19+
const search = searchParams.get("sessionNumber");
20+
21+
const fetchData = async (seasonId: string, seasonNumber: string | null) => {
22+
if (!seasonId && !seasonNumber) return;
23+
24+
try {
25+
setLoading(true);
26+
27+
const seasonsData = await fetch(
28+
`https://api.themoviedb.org/3/tv/${seasonId}/season/${seasonNumber}?api_key=${process.env.NEXT_PUBLIC_API_KEY}&language=en-US`
29+
).then((res) => res.json());
30+
31+
setSeasons(seasonsData.episodes);
32+
33+
setTimeout(() => {
34+
setLoading(false);
35+
}, 2000);
36+
} catch (error: any) {
37+
console.log("🚀 ~ file: page.tsx:23 ~ fetchData ~ error:", error);
38+
}
39+
};
40+
41+
useEffect(() => {
42+
if (!pathname) return;
43+
44+
const replaceName = pathname.replace("/season/", "");
45+
fetchData(replaceName, search!);
46+
}, []);
47+
48+
return (
49+
<motion.div
50+
initial={{ opacity: 0 }}
51+
whileInView={{ opacity: 1 }}
52+
viewport={{ once: true }}
53+
>
54+
<Navbar />
55+
<GlobalLoading isLoading={loading} />
56+
<main>
57+
<SeasonFeed seasons={seasons} />
58+
</main>
59+
<Footer />
60+
</motion.div>
61+
);
62+
}
63+
64+
export default SeasonPage;

components/DetailsBanner.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import CastSlide from "./CastSlide";
2121
import CircularRate from "./CircularRate";
2222
import Container from "./Container";
2323

24-
const pusher = new Pusher("value", {
24+
const pusher = new Pusher("", {
2525
cluster: "eu",
2626
});
2727

components/PersonBanner.tsx

+7-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
import { toast } from "react-toastify";
1717
import CircularRate from "./CircularRate";
1818

19-
const pusher = new Pusher("value", {
19+
const pusher = new Pusher("", {
2020
cluster: "eu",
2121
});
2222

@@ -191,6 +191,12 @@ function PersonBanner({ personData, taggedImages }: Props) {
191191
>
192192
{personData.name}
193193
</Typography>
194+
<div className="flex justify-start gap-x-20">
195+
<p>Birthday: {personData.birthday}</p>
196+
{personData.deathday && (
197+
<p>Deathday: {personData.deathday}</p>
198+
)}
199+
</div>
194200
<Stack direction="row" spacing={1} alignItems="center">
195201
<CircularRate
196202
value={personData.popularity / 100!}

components/SeasonFeed.tsx

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { Episode } from "@/typings";
2+
import { baseURL } from "@/utils/baseUrl";
3+
import React from "react";
4+
import CircularRate from "./CircularRate";
5+
6+
type Props = {
7+
seasons: Episode[];
8+
};
9+
10+
function SeasonFeed({ seasons }: Props) {
11+
return (
12+
<div className="pt-36 mx-8 overflow-x-hidden space-y-8 items-center">
13+
{seasons.map((season) => (
14+
<div
15+
className="relative flex flex-col min-w-0 break-words shadow-soft-xl rounded-2xl bg-clip-border bg-gray-900"
16+
key={season.id}
17+
>
18+
<div className="flex-auto p-4">
19+
<div className="flex flex-wrap -mx-3">
20+
<div className="max-w-full px-3 lg:w-1/2 lg:flex-none">
21+
<div className="flex flex-col h-full space-y-8">
22+
<p className="pt-2 mb-1 font-semibold">
23+
Episode
24+
{season.episode_number}
25+
</p>
26+
<h5 className="font-bold text-xl">{season.name}</h5>
27+
<p className="mb-12">{season.overview}</p>
28+
<a
29+
className="mt-auto mb-0 font-semibold leading-normal text-sm group text-slate-500"
30+
href="javascript:;"
31+
>
32+
<CircularRate value={season.vote_average} />
33+
<i className="fas fa-arrow-right ease-bounce text-sm group-hover:translate-x-1.25 ml-1 leading-normal transition-all duration-200"></i>
34+
</a>
35+
</div>
36+
</div>
37+
<div className="max-w-full px-3 mt-12 ml-auto text-center lg:mt-0 lg:w-5/12 lg:flex-none">
38+
<div
39+
className={`h-[300px] bg-gradient-to-tl from-purple-700 to-pink-500 rounded-xl !season.still_path && "animate-pulse"`}
40+
>
41+
<img
42+
src={`${baseURL}${season.still_path}`}
43+
className={`absolute top-0 hidden w-1/2 h-full lg:block ${
44+
!season.still_path && "animate-pulse"
45+
}`}
46+
alt="season"
47+
/>
48+
</div>
49+
</div>
50+
</div>
51+
</div>
52+
</div>
53+
))}
54+
</div>
55+
);
56+
}
57+
58+
export default SeasonFeed;

components/Seasons.tsx

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,30 @@
11
import { Details } from "@/typings";
22
import { baseURL } from "@/utils/baseUrl";
33
import { motion } from "framer-motion";
4-
import React from "react";
4+
import { useSession } from "next-auth/react";
5+
import { useRouter } from "next/navigation";
6+
import { toast } from "react-toastify";
7+
58
import Container from "./Container";
69

710
type Props = {
811
movieDetails: Details;
912
};
1013

1114
function Seasons({ movieDetails }: Props) {
15+
const router = useRouter();
16+
const { data: session } = useSession();
17+
18+
const navigatePage = (sessionId: number, sessionNumber: number) => {
19+
if (session) {
20+
router.push(`/season/${sessionId}?sessionNumber=${sessionNumber}`);
21+
} else {
22+
toast.error(
23+
"You Need to Sign In to Look Up More Information About This Session"
24+
);
25+
}
26+
};
27+
1228
return (
1329
<div className="px-4 pb-8">
1430
<Container header="Seasons">
@@ -24,6 +40,9 @@ function Seasons({ movieDetails }: Props) {
2440
}}
2541
key={season.id}
2642
className="relative h-28 min-w-[180px] cursor-pointer transition-transform duration-200 ease-out md:h-[400px] md:min-w-[200px] items-center hover:shadow-2xl"
43+
onClick={() =>
44+
navigatePage(movieDetails.id, season.season_number)
45+
}
2746
>
2847
<p
2948
className={`text-lg py-2.5 text-gray-400 ${

server/data/data.json

-7
This file was deleted.

server/index.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ const app = express();
1919
const port = process.env.PORT || 3001;
2020

2121
const pusher = new Pusher({
22-
appId: process.env.appId,
23-
key: process.env.key,
24-
secret: process.env.secret,
22+
appId: "1563131",
23+
key: "9a52b8f05435b6e35101",
24+
secret: "f7f36d4243b06c8eadb1",
2525
cluster: "ap2",
2626
useTLS: true,
2727
});

typings.d.ts

+17
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,20 @@ export interface MovieReviewData {
149149
url: string;
150150
author_details: AuthorDetails;
151151
}
152+
153+
export interface Episode {
154+
air_date: string;
155+
crew: any[];
156+
episode_number: number;
157+
guest_stars: Cast[];
158+
id: number;
159+
name: string;
160+
overview: string;
161+
production_code: string;
162+
runtime: number;
163+
season_number: number;
164+
show_id: number;
165+
still_path: number;
166+
vote_average: number;
167+
vote_count: number;
168+
}

0 commit comments

Comments
 (0)