diff --git a/src/App.jsx b/src/App.jsx
index 08ed6b2a..4bc80fe3 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,8 +1,8 @@
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Layout from "./Layout.jsx";
-import MainPage from "./page/MainPage.jsx";
-import DetailPage from "./page/DetailPage.jsx";
+import MainPage from "./pages/MainPage.jsx";
+import DetailPage from "./pages/DetailPage.jsx";
import { createGlobalStyle } from "styled-components";
diff --git a/src/Layout.jsx b/src/Layout.jsx
index 20ec962d..df6005bd 100644
--- a/src/Layout.jsx
+++ b/src/Layout.jsx
@@ -1,10 +1,8 @@
import { Outlet } from "react-router-dom";
-import NavigationBar from "./component/NavigationBarComponent";
export default function Layout() {
return (
-
diff --git a/src/assets/react.svg b/src/images/react.svg
similarity index 100%
rename from src/assets/react.svg
rename to src/images/react.svg
diff --git a/src/Page/DetailPage.jsx b/src/pages/DetailPage.jsx
similarity index 63%
rename from src/Page/DetailPage.jsx
rename to src/pages/DetailPage.jsx
index d3fba3fa..12b916d7 100644
--- a/src/Page/DetailPage.jsx
+++ b/src/pages/DetailPage.jsx
@@ -1,33 +1,38 @@
import styled from "styled-components";
+import NavigationBar from "./components/NavigationBar";
+
import { useParams } from "react-router-dom";
-import useDetailApi from "../Api/DetailApi";
+import useTmdbDetailData from "./data/hooks/useTmdbDetailData";
// <-------------------- function -------------------->
export default function DetailPage() {
const { id } = useParams();
- const detailApi = useDetailApi(id);
+ const tmdbDetail = useTmdbDetailData(id);
// <-------------------- return -------------------->
return (
-
-
-
-
- {detailApi.title}
- {detailApi.vote_average}
-
- {detailApi.overview}
-
-
+ <>
+
+
+
+
+
+ {tmdbDetail.title}
+ {tmdbDetail.vote_average}
+
+ {tmdbDetail.overview}
+
+
+ >
);
}
diff --git a/src/Page/MainPage.jsx b/src/pages/MainPage.jsx
similarity index 66%
rename from src/Page/MainPage.jsx
rename to src/pages/MainPage.jsx
index 4f8c01a5..7b983c1e 100644
--- a/src/Page/MainPage.jsx
+++ b/src/pages/MainPage.jsx
@@ -1,8 +1,9 @@
import styled from "styled-components";
+import Card from "./components/Card.jsx";
-import CardComponent from "../Component/CardComponent.jsx";
-import useTopApi from "../Api/TopApi.js";
-import useMainApi from "../Api/MainApi";
+import useTmdbTopData from "./data/hooks/useTmdbTopData.js";
+import useTmdbMainData from "./data/hooks/useTmdbMainData.js";
+import useTmdbKeywordData from "./data/hooks/useTmdbKeywordData.js";
import { Swiper, SwiperSlide } from "swiper/react";
import { Navigation, Pagination, Autoplay } from "swiper/modules";
@@ -10,18 +11,28 @@ import "swiper/css";
import "swiper/css/navigation";
import "swiper/css/pagination";
+import { useSearchParams } from "react-router-dom";
+import NavigationBar from "./components/NavigationBar.jsx";
+
// <-------------------- function -------------------->
export default function MainPage() {
- const topApi = useTopApi();
- const mainApi = useMainApi();
+ const [searchParams] = useSearchParams();
+ const query = searchParams.get("keyword")?.trim();
+
+ const tmdbTop = useTmdbTopData();
+ const tmdbMainData = useTmdbMainData();
+ const tmdbKeywordData = useTmdbKeywordData(query);
+
+ const tmdbData = query ? tmdbKeywordData : tmdbMainData;
// <-------------------- return -------------------->
return (
<>
+
- TOP 10 π
+ π TOP 10
- {topApi.slice(0, 10).map((api) => (
+ {tmdbTop.slice(0, 10).map((api) => (
-
+
))}
- Popular β¨
-
- {mainApi.map((api) => (
-
+ β¨ Popular
+
+ {tmdbData.map((movie) => (
+
))}
-
+
>
);
@@ -69,7 +80,7 @@ const Popular = styled.p`
padding-left: 100px;
`;
-const Mainapi = styled.div`
+const MainList = styled.div`
display: flex;
flex-wrap: wrap;
justify-content: center;
diff --git a/src/Component/CardComponent.jsx b/src/pages/components/Card.jsx
similarity index 91%
rename from src/Component/CardComponent.jsx
rename to src/pages/components/Card.jsx
index db059c4e..b0d07721 100644
--- a/src/Component/CardComponent.jsx
+++ b/src/pages/components/Card.jsx
@@ -3,9 +3,9 @@ import { Link } from "react-router-dom";
// <-------------------- function, return -------------------->
-export default function CardComponent({ movie }) {
+export default function Card({ movie }) {
return (
-
+
{movie.title}
{movie.vote_average}
-
+
);
}
// <-------------------- styled-components -------------------->
-const Card = styled.div`
+const Container = styled.div`
width: 18vw;
max-width: 200px;
min-width: 150px;
diff --git a/src/Component/NavigationBarComponent.jsx b/src/pages/components/NavigationBar.jsx
similarity index 52%
rename from src/Component/NavigationBarComponent.jsx
rename to src/pages/components/NavigationBar.jsx
index b9e10f1e..64e086c1 100644
--- a/src/Component/NavigationBarComponent.jsx
+++ b/src/pages/components/NavigationBar.jsx
@@ -1,14 +1,45 @@
import styled from "styled-components";
-import { Link } from "react-router-dom";
+import { Link, useSearchParams } from "react-router-dom";
+import { useEffect, useState } from "react";
+
+import useDebounce from "./hooks/useDebounce.js";
+import useTmdbKeywordData from "../data/hooks/useTmdbKeywordData.js";
+
+// <-------------------- function -------------------->
export default function NavigationBar() {
+ const [searchParams, setSearchParams] = useSearchParams();
+ const keywordParam = searchParams.get("keyword") || "";
+ const [keyword, setKeyword] = useState(keywordParam);
+
+ const debouncedKeyword = useDebounce(keyword, 100);
+ useTmdbKeywordData(debouncedKeyword);
+
+ useEffect(() => {
+ if (keyword.trim() === "") {
+ const params = new URLSearchParams(searchParams);
+ params.delete("keyword");
+ setSearchParams(params);
+ } else {
+ setSearchParams({ keyword });
+ }
+ }, [keyword, searchParams, setSearchParams]);
+
+ // <-------------------- return -------------------->
+
return (
π¬ β’ WISH MOVIE
+
-
+ setKeyword(e.target.value)}
+ />
λ‘κ·ΈμΈ
@@ -18,6 +49,8 @@ export default function NavigationBar() {
);
}
+// <-------------------- styled-components -------------------->
+
const Navigationbar = styled.nav`
width: 100%;
height: 60px;
@@ -55,6 +88,18 @@ const SearchBox = styled.div`
}
`;
+const SearchResults = styled.div`
+ position: absolute;
+ top: 70px;
+ background-color: #111;
+ width: 300px;
+ max-height: 400px;
+ overflow-y: auto;
+ color: white;
+ border-radius: 8px;
+ padding: 10px;
+`;
+
const Buttons = styled.div`
display: flex;
align-items: center;
diff --git a/src/pages/components/hooks/useDebounce.js b/src/pages/components/hooks/useDebounce.js
new file mode 100644
index 00000000..87659778
--- /dev/null
+++ b/src/pages/components/hooks/useDebounce.js
@@ -0,0 +1,17 @@
+import { useEffect, useState } from "react";
+
+export default function useDebounce(value, delay) {
+ const [debouncedValue, setDebouncedValue] = useState(value);
+
+ useEffect(() => {
+ const handler = setTimeout(() => {
+ setDebouncedValue(value);
+ }, delay);
+
+ return () => {
+ clearTimeout(handler);
+ };
+ }, [value, delay]);
+
+ return debouncedValue;
+}
diff --git a/src/Data/DetailData.json b/src/pages/data/DummyDetailData.json
similarity index 100%
rename from src/Data/DetailData.json
rename to src/pages/data/DummyDetailData.json
diff --git a/src/Data/MainData.json b/src/pages/data/DummyMainData.json
similarity index 100%
rename from src/Data/MainData.json
rename to src/pages/data/DummyMainData.json
diff --git a/src/Api/DetailApi.js b/src/pages/data/hooks/useTmdbDetailData.js
similarity index 73%
rename from src/Api/DetailApi.js
rename to src/pages/data/hooks/useTmdbDetailData.js
index d9ade3a3..33d5546c 100644
--- a/src/Api/DetailApi.js
+++ b/src/pages/data/hooks/useTmdbDetailData.js
@@ -1,13 +1,12 @@
import { useEffect, useState } from "react";
import axios from "axios";
-const apiToken = import.meta.env.VITE_TMDB_ACCESS_TOKEN;
+const apiToken = import.meta.env.VITE_TMDB_API_KEY;
// <-------------------- function -------------------->
-export default function useDetailApi(id) {
- const [detailApi, setDetailApi] = useState([]);
- // console.log(movieId);
+export default function useTmdbDetailData(id) {
+ const [tmdbDetailData, setTmdbDetailData] = useState([]);
// <-------------------- API : Details
@@ -25,12 +24,12 @@ export default function useDetailApi(id) {
axios
.request(options)
.then((res) => {
- setDetailApi(res.data);
+ setTmdbDetailData(res.data);
})
.catch((err) => console.error(err));
}, []);
// <-------------------- return -------------------->
- return detailApi;
+ return tmdbDetailData;
}
diff --git a/src/pages/data/hooks/useTmdbKeywordData.js b/src/pages/data/hooks/useTmdbKeywordData.js
new file mode 100644
index 00000000..78be6761
--- /dev/null
+++ b/src/pages/data/hooks/useTmdbKeywordData.js
@@ -0,0 +1,35 @@
+import { useEffect, useState } from "react";
+import axios from "axios";
+
+const apiToken = import.meta.env.VITE_TMDB_API_KEY;
+
+export default function useTmdbKeywordData(keyword) {
+ const [search, setSearch] = useState([]);
+
+ useEffect(() => {
+ console.log(keyword);
+
+ if (!keyword) return;
+
+ const options = {
+ method: "GET",
+ url: `https://api.themoviedb.org/3/search/movie`,
+ params: {
+ query: keyword,
+ language: "ko-KR",
+ page: 1,
+ },
+ headers: {
+ accept: "application/json",
+ Authorization: `Bearer ${apiToken}`,
+ },
+ };
+
+ axios
+ .request(options)
+ .then((res) => setSearch(res.data.results))
+ .catch((err) => console.error(err));
+ }, [keyword]);
+
+ return search;
+}
diff --git a/src/Api/MainApi.js b/src/pages/data/hooks/useTmdbMainData.js
similarity index 77%
rename from src/Api/MainApi.js
rename to src/pages/data/hooks/useTmdbMainData.js
index e8385c3f..53b8ca55 100644
--- a/src/Api/MainApi.js
+++ b/src/pages/data/hooks/useTmdbMainData.js
@@ -2,13 +2,13 @@ import { useEffect, useState } from "react";
// <-------------------- function -------------------->
-export default function useMainApi() {
- const [mainApi, setMainApi] = useState([]);
+export default function useTmdbMainData(keyword) {
+ const [tmdbMainData, setTmdbMainData] = useState([]);
// <-------------------- API : popular
useEffect(() => {
- const apiToken = import.meta.env.VITE_TMDB_ACCESS_TOKEN;
+ const apiToken = import.meta.env.VITE_TMDB_API_KEY;
const options = {
method: "GET",
headers: {
@@ -27,12 +27,12 @@ export default function useMainApi() {
(resData) => resData.adult === false
);
// console.log("β
TMDB μλ΅ λ°μ΄ν°:", filteredTmdbMovies);
- setMainApi(noAdultResData);
+ setTmdbMainData(noAdultResData);
})
.catch((err) => console.error(err));
- }, []);
+ }, [keyword]);
// <-------------------- return -------------------->
- return mainApi;
+ return tmdbMainData;
}
diff --git a/src/Api/TopApi.js b/src/pages/data/hooks/useTmdbTopData.js
similarity index 73%
rename from src/Api/TopApi.js
rename to src/pages/data/hooks/useTmdbTopData.js
index cf1b02c5..fb78954f 100644
--- a/src/Api/TopApi.js
+++ b/src/pages/data/hooks/useTmdbTopData.js
@@ -1,12 +1,12 @@
import { useEffect, useState } from "react";
import axios from "axios";
-const apiToken = import.meta.env.VITE_TMDB_ACCESS_TOKEN;
+const apiToken = import.meta.env.VITE_TMDB_API_KEY;
// <-------------------- function -------------------->
-export default function useTopApi() {
- const [topApi, setTopApi] = useState([]);
+export default function useTmdbTopData() {
+ const [tmdbTopData, setTmdbTopData] = useState([]);
// <-------------------- API : Top
@@ -24,12 +24,12 @@ export default function useTopApi() {
axios
.request(options)
.then((res) => {
- setTopApi(res.data.results);
+ setTmdbTopData(res.data.results);
})
.catch((err) => console.error(err));
- });
+ },[]);
// <-------------------- return -------------------->
- return topApi;
+ return tmdbTopData;
}