From 036294471b296db09f8f9cda9d0b11da992ba8c0 Mon Sep 17 00:00:00 2001 From: kimsowon Date: Wed, 29 Oct 2025 20:01:02 +0900 Subject: [PATCH 1/4] =?UTF-8?q?3=EB=8B=A8=EA=B3=84=20=EC=8B=9C=EC=9E=91,?= =?UTF-8?q?=20=EA=B2=80=EC=83=89=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= =?UTF-8?q?=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.jsx | 4 +- src/Component/NavigationBarComponent.jsx | 81 ----------- src/Layout.jsx | 2 +- .../CardComponent.jsx => components/Card.jsx} | 8 +- src/components/NavigationBar.jsx | 136 ++++++++++++++++++ .../DummyDetailData.json} | 0 .../MainData.json => data/DummyMainData.json} | 0 src/data/hooks/useDebounce.js | 17 +++ .../hooks/useTmdbDetailData.js} | 9 +- src/data/hooks/useTmdbKeywordData.js | 33 +++++ .../hooks/useTmdbMainData.js} | 8 +- .../hooks/useTmdbTopData.js} | 8 +- src/{assets => images}/react.svg | 0 src/{Page => pages}/DetailPage.jsx | 14 +- src/{Page => pages}/MainPage.jsx | 21 +-- 15 files changed, 224 insertions(+), 117 deletions(-) delete mode 100644 src/Component/NavigationBarComponent.jsx rename src/{Component/CardComponent.jsx => components/Card.jsx} (91%) create mode 100644 src/components/NavigationBar.jsx rename src/{Data/DetailData.json => data/DummyDetailData.json} (100%) rename src/{Data/MainData.json => data/DummyMainData.json} (100%) create mode 100644 src/data/hooks/useDebounce.js rename src/{Api/DetailApi.js => data/hooks/useTmdbDetailData.js} (79%) create mode 100644 src/data/hooks/useTmdbKeywordData.js rename src/{Api/MainApi.js => data/hooks/useTmdbMainData.js} (84%) rename src/{Api/TopApi.js => data/hooks/useTmdbTopData.js} (81%) rename src/{assets => images}/react.svg (100%) rename src/{Page => pages}/DetailPage.jsx (77%) rename src/{Page => pages}/MainPage.jsx (80%) 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/Component/NavigationBarComponent.jsx b/src/Component/NavigationBarComponent.jsx deleted file mode 100644 index b9e10f1e..00000000 --- a/src/Component/NavigationBarComponent.jsx +++ /dev/null @@ -1,81 +0,0 @@ -import styled from "styled-components"; -import { Link } from "react-router-dom"; - -export default function NavigationBar() { - return ( - - - 🎬 β€’ WISH MOVIE - - - - - - 둜그인 - νšŒμ›κ°€μž… - - - ); -} - -const Navigationbar = styled.nav` - width: 100%; - height: 60px; - background-color: #1a1a1a; - color: white; - display: flex; - align-items: center; - justify-content: space-between; - padding: 0 40px; - box-sizing: border-box; - overflow: hidden; - gap: 50px; -`; - -const Logo = styled.h1` - font-size: 24px; - display: flex; - align-items: center; - flex-shrink: 0; - color: #757575; -`; - -const SearchBox = styled.div` - flex: 1; - display: flex; - justify-content: center; - input { - width: 100%; - height: 30px; - border-radius: 15px; - border: none; - padding: 0 15px; - font-size: 16px; - background-color: #bafd00; - } -`; - -const Buttons = styled.div` - display: flex; - align-items: center; - gap: 12px; - flex-shrink: 0; -`; - -const LoginBtn = styled.button` - background: none; - color: white; - border: 1px solid white; - border-radius: 15px; - padding: 5px 15px; - cursor: pointer; -`; - -const SignupBtn = styled.button` - background-color: white; - color: #141414; - border: none; - border-radius: 15px; - padding: 5px 15px; - cursor: pointer; -`; diff --git a/src/Layout.jsx b/src/Layout.jsx index 20ec962d..58c69d12 100644 --- a/src/Layout.jsx +++ b/src/Layout.jsx @@ -1,5 +1,5 @@ import { Outlet } from "react-router-dom"; -import NavigationBar from "./component/NavigationBarComponent"; +import NavigationBar from "./components/NavigationBar.jsx"; export default function Layout() { return ( diff --git a/src/Component/CardComponent.jsx b/src/components/Card.jsx similarity index 91% rename from src/Component/CardComponent.jsx rename to src/components/Card.jsx index db059c4e..b0d07721 100644 --- a/src/Component/CardComponent.jsx +++ b/src/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/components/NavigationBar.jsx b/src/components/NavigationBar.jsx new file mode 100644 index 00000000..da973acd --- /dev/null +++ b/src/components/NavigationBar.jsx @@ -0,0 +1,136 @@ +import styled from "styled-components"; +import { Link, useSearchParams } from "react-router-dom"; +import { useEffect, useState } from "react"; + +import useDebounce from "../data/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, 500); + const searchKeyword = useTmdbKeywordData(debouncedKeyword); + + useEffect(() => { + if (keyword.trim() === "") { + searchParams.delete("keyword"); + setSearchParams(searchParams); + } else { + setSearchParams({ keyword }); + } + }, [keyword]); + + // <-------------------- return --------------------> + + return ( + + + 🎬 β€’ WISH MOVIE + + + + setKeyword(e.target.value)} + /> + + + {/* <-------------------- 검색 κ²°κ³Ό ν‘œμ‹œ */} + + {searchKeyword && searchKeyword.length > 0 && ( + + {searchKeyword.map((movie) => ( +

{movie.title}

+ ))} +
+ )} + + + 둜그인 + νšŒμ›κ°€μž… + +
+ ); +} + +// <-------------------- styled-components --------------------> + +const Navigationbar = styled.nav` + width: 100%; + height: 60px; + background-color: #1a1a1a; + color: white; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 40px; + box-sizing: border-box; + overflow: hidden; + gap: 50px; +`; + +const Logo = styled.h1` + font-size: 24px; + display: flex; + align-items: center; + flex-shrink: 0; + color: #757575; +`; + +const SearchBox = styled.div` + flex: 1; + display: flex; + justify-content: center; + input { + width: 100%; + height: 30px; + border-radius: 15px; + border: none; + padding: 0 15px; + font-size: 16px; + background-color: #bafd00; + } +`; + +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; + gap: 12px; + flex-shrink: 0; +`; + +const LoginBtn = styled.button` + background: none; + color: white; + border: 1px solid white; + border-radius: 15px; + padding: 5px 15px; + cursor: pointer; +`; + +const SignupBtn = styled.button` + background-color: white; + color: #141414; + border: none; + border-radius: 15px; + padding: 5px 15px; + cursor: pointer; +`; diff --git a/src/Data/DetailData.json b/src/data/DummyDetailData.json similarity index 100% rename from src/Data/DetailData.json rename to src/data/DummyDetailData.json diff --git a/src/Data/MainData.json b/src/data/DummyMainData.json similarity index 100% rename from src/Data/MainData.json rename to src/data/DummyMainData.json diff --git a/src/data/hooks/useDebounce.js b/src/data/hooks/useDebounce.js new file mode 100644 index 00000000..87659778 --- /dev/null +++ b/src/data/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/Api/DetailApi.js b/src/data/hooks/useTmdbDetailData.js similarity index 79% rename from src/Api/DetailApi.js rename to src/data/hooks/useTmdbDetailData.js index d9ade3a3..ef93c15e 100644 --- a/src/Api/DetailApi.js +++ b/src/data/hooks/useTmdbDetailData.js @@ -5,9 +5,8 @@ const apiToken = import.meta.env.VITE_TMDB_ACCESS_TOKEN; // <-------------------- 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/data/hooks/useTmdbKeywordData.js b/src/data/hooks/useTmdbKeywordData.js new file mode 100644 index 00000000..fc1aa41c --- /dev/null +++ b/src/data/hooks/useTmdbKeywordData.js @@ -0,0 +1,33 @@ +import { useEffect, useState } from "react"; +import axios from "axios"; + +const apiToken = import.meta.env.VITE_TMDB_ACCESS_TOKEN; + +export default function useTmdbKeywordData(keyword) { + const [search, setSearch] = useState([]); + + useEffect(() => { + 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/data/hooks/useTmdbMainData.js similarity index 84% rename from src/Api/MainApi.js rename to src/data/hooks/useTmdbMainData.js index e8385c3f..9fd23afd 100644 --- a/src/Api/MainApi.js +++ b/src/data/hooks/useTmdbMainData.js @@ -2,8 +2,8 @@ import { useEffect, useState } from "react"; // <-------------------- function --------------------> -export default function useMainApi() { - const [mainApi, setMainApi] = useState([]); +export default function useTmdbMainData() { + const [tmdbMainData, setTmdbMainData] = useState([]); // <-------------------- API : popular @@ -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)); }, []); // <-------------------- return --------------------> - return mainApi; + return tmdbMainData; } diff --git a/src/Api/TopApi.js b/src/data/hooks/useTmdbTopData.js similarity index 81% rename from src/Api/TopApi.js rename to src/data/hooks/useTmdbTopData.js index cf1b02c5..455c3687 100644 --- a/src/Api/TopApi.js +++ b/src/data/hooks/useTmdbTopData.js @@ -5,8 +5,8 @@ const apiToken = import.meta.env.VITE_TMDB_ACCESS_TOKEN; // <-------------------- 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; } 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 77% rename from src/Page/DetailPage.jsx rename to src/pages/DetailPage.jsx index d3fba3fa..6d0c7f37 100644 --- a/src/Page/DetailPage.jsx +++ b/src/pages/DetailPage.jsx @@ -2,14 +2,14 @@ import styled from "styled-components"; 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 --------------------> @@ -17,15 +17,15 @@ export default function DetailPage() { - {detailApi.title} - {detailApi.vote_average} + {tmdbDetail.title} + {tmdbDetail.vote_average} - {detailApi.overview} + {tmdbDetail.overview} ); diff --git a/src/Page/MainPage.jsx b/src/pages/MainPage.jsx similarity index 80% rename from src/Page/MainPage.jsx rename to src/pages/MainPage.jsx index 4f8c01a5..42bd30a6 100644 --- a/src/Page/MainPage.jsx +++ b/src/pages/MainPage.jsx @@ -1,8 +1,10 @@ import styled from "styled-components"; -import CardComponent from "../Component/CardComponent.jsx"; -import useTopApi from "../Api/TopApi.js"; -import useMainApi from "../Api/MainApi"; +import Card from "../components/Card.jsx"; +import useTmdbTopData from "../data/hooks/useTmdbTopData.js"; +import useTmdbMainData from "../data/hooks/useTmdbMainData.js"; + +import NavigationBar from "../components/NavigationBar.jsx"; import { Swiper, SwiperSlide } from "swiper/react"; import { Navigation, Pagination, Autoplay } from "swiper/modules"; @@ -13,13 +15,14 @@ import "swiper/css/pagination"; // <-------------------- function --------------------> export default function MainPage() { - const topApi = useTopApi(); - const mainApi = useMainApi(); + const tmdbTop = useTmdbTopData(); + const tmdbMain = useTmdbMainData(); // <-------------------- return --------------------> return ( <> + TOP 10 πŸ† - {topApi.slice(0, 10).map((api) => ( + {tmdbTop.slice(0, 10).map((api) => ( - + ))} Popular ✨ - {mainApi.map((api) => ( - + {tmdbMain.map((api) => ( + ))} From 16195f65d431231c74977ced21cf2ffa356c3a2d Mon Sep 17 00:00:00 2001 From: the-eris-net Date: Wed, 29 Oct 2025 20:47:56 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feat:keyword=20=EC=B6=9C=EB=A0=A5=ED=95=98?= =?UTF-8?q?=EA=B2=8C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/NavigationBar.jsx | 8 -------- src/data/hooks/useTmdbDetailData.js | 2 +- src/data/hooks/useTmdbKeywordData.js | 5 ++++- src/data/hooks/useTmdbMainData.js | 6 +++--- src/data/hooks/useTmdbTopData.js | 4 ++-- src/pages/MainPage.jsx | 26 ++++++++++++++------------ 6 files changed, 24 insertions(+), 27 deletions(-) diff --git a/src/components/NavigationBar.jsx b/src/components/NavigationBar.jsx index da973acd..623079ea 100644 --- a/src/components/NavigationBar.jsx +++ b/src/components/NavigationBar.jsx @@ -43,14 +43,6 @@ export default function NavigationBar() { {/* <-------------------- 검색 κ²°κ³Ό ν‘œμ‹œ */} - {searchKeyword && searchKeyword.length > 0 && ( - - {searchKeyword.map((movie) => ( -

{movie.title}

- ))} -
- )} - 둜그인 νšŒμ›κ°€μž… diff --git a/src/data/hooks/useTmdbDetailData.js b/src/data/hooks/useTmdbDetailData.js index ef93c15e..33d5546c 100644 --- a/src/data/hooks/useTmdbDetailData.js +++ b/src/data/hooks/useTmdbDetailData.js @@ -1,7 +1,7 @@ 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 --------------------> diff --git a/src/data/hooks/useTmdbKeywordData.js b/src/data/hooks/useTmdbKeywordData.js index fc1aa41c..819f68d4 100644 --- a/src/data/hooks/useTmdbKeywordData.js +++ b/src/data/hooks/useTmdbKeywordData.js @@ -1,12 +1,15 @@ 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; export default function useTmdbKeywordData(keyword) { const [search, setSearch] = useState([]); useEffect(() => { + if(typeof keyword !== "string") { + keyword = keyword.get("keyword") || ""; + } if (!keyword) return; const options = { diff --git a/src/data/hooks/useTmdbMainData.js b/src/data/hooks/useTmdbMainData.js index 9fd23afd..53b8ca55 100644 --- a/src/data/hooks/useTmdbMainData.js +++ b/src/data/hooks/useTmdbMainData.js @@ -2,13 +2,13 @@ import { useEffect, useState } from "react"; // <-------------------- function --------------------> -export default function useTmdbMainData() { +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: { @@ -30,7 +30,7 @@ export default function useTmdbMainData() { setTmdbMainData(noAdultResData); }) .catch((err) => console.error(err)); - }, []); + }, [keyword]); // <-------------------- return --------------------> diff --git a/src/data/hooks/useTmdbTopData.js b/src/data/hooks/useTmdbTopData.js index 455c3687..fb78954f 100644 --- a/src/data/hooks/useTmdbTopData.js +++ b/src/data/hooks/useTmdbTopData.js @@ -1,7 +1,7 @@ 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 --------------------> @@ -27,7 +27,7 @@ export default function useTmdbTopData() { setTmdbTopData(res.data.results); }) .catch((err) => console.error(err)); - }); + },[]); // <-------------------- return --------------------> diff --git a/src/pages/MainPage.jsx b/src/pages/MainPage.jsx index 42bd30a6..77ef5b84 100644 --- a/src/pages/MainPage.jsx +++ b/src/pages/MainPage.jsx @@ -1,28 +1,30 @@ -import styled from "styled-components"; +import styled from 'styled-components'; -import Card from "../components/Card.jsx"; -import useTmdbTopData from "../data/hooks/useTmdbTopData.js"; -import useTmdbMainData from "../data/hooks/useTmdbMainData.js"; +import Card from '../components/Card.jsx'; +import useTmdbTopData from '../data/hooks/useTmdbTopData.js'; +import useTmdbMainData from '../data/hooks/useTmdbMainData.js'; +import useTmdbKeywordData from '../data/hooks/useTmdbKeywordData.js'; -import NavigationBar from "../components/NavigationBar.jsx"; +import NavigationBar from '../components/NavigationBar.jsx'; -import { Swiper, SwiperSlide } from "swiper/react"; -import { Navigation, Pagination, Autoplay } from "swiper/modules"; -import "swiper/css"; -import "swiper/css/navigation"; -import "swiper/css/pagination"; +import { Swiper, SwiperSlide } from 'swiper/react'; +import { Navigation, Pagination, Autoplay } from 'swiper/modules'; +import 'swiper/css'; +import 'swiper/css/navigation'; +import 'swiper/css/pagination'; +import { useSearchParams } from 'react-router-dom'; // <-------------------- function --------------------> export default function MainPage() { + const [keyword, setKeyword] = useSearchParams(); const tmdbTop = useTmdbTopData(); - const tmdbMain = useTmdbMainData(); + const tmdbMain = keyword.get("keyword")?.trim() ? useTmdbKeywordData(keyword) : useTmdbMainData(); // <-------------------- return --------------------> return ( <> - TOP 10 πŸ† Date: Wed, 29 Oct 2025 20:54:31 +0900 Subject: [PATCH 3/4] feat: keyword --- src/data/hooks/useTmdbKeywordData.js | 5 ++--- src/pages/MainPage.jsx | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/data/hooks/useTmdbKeywordData.js b/src/data/hooks/useTmdbKeywordData.js index 819f68d4..78be6761 100644 --- a/src/data/hooks/useTmdbKeywordData.js +++ b/src/data/hooks/useTmdbKeywordData.js @@ -7,9 +7,8 @@ export default function useTmdbKeywordData(keyword) { const [search, setSearch] = useState([]); useEffect(() => { - if(typeof keyword !== "string") { - keyword = keyword.get("keyword") || ""; - } + console.log(keyword); + if (!keyword) return; const options = { diff --git a/src/pages/MainPage.jsx b/src/pages/MainPage.jsx index 77ef5b84..4acd5c28 100644 --- a/src/pages/MainPage.jsx +++ b/src/pages/MainPage.jsx @@ -19,7 +19,8 @@ import { useSearchParams } from 'react-router-dom'; export default function MainPage() { const [keyword, setKeyword] = useSearchParams(); const tmdbTop = useTmdbTopData(); - const tmdbMain = keyword.get("keyword")?.trim() ? useTmdbKeywordData(keyword) : useTmdbMainData(); + const query = keyword.get("keyword")?.trim(); + const tmdbMain = query ? useTmdbKeywordData(query) : useTmdbMainData(query); // <-------------------- return --------------------> From 2a8efa29b94b97479e9618853a7cfbfa0cbcda17 Mon Sep 17 00:00:00 2001 From: kimsowon Date: Tue, 4 Nov 2025 01:15:55 +0900 Subject: [PATCH 4/4] =?UTF-8?q?feat(search):=20=ED=82=A4=EC=9B=8C=EB=93=9C?= =?UTF-8?q?=20=EA=B2=80=EC=83=89=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= =?UTF-8?q?=20(TMDB=20=EC=97=B0=EB=8F=99,=20=EB=94=94=EB=B0=94=EC=9A=B4?= =?UTF-8?q?=EC=8A=A4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Layout.jsx | 2 - src/pages/DetailPage.jsx | 35 +++++++------ src/pages/MainPage.jsx | 49 ++++++++++--------- src/{ => pages}/components/Card.jsx | 0 src/{ => pages}/components/NavigationBar.jsx | 16 +++--- .../components}/hooks/useDebounce.js | 0 src/{ => pages}/data/DummyDetailData.json | 0 src/{ => pages}/data/DummyMainData.json | 0 .../data/hooks/useTmdbDetailData.js | 0 .../data/hooks/useTmdbKeywordData.js | 0 src/{ => pages}/data/hooks/useTmdbMainData.js | 0 src/{ => pages}/data/hooks/useTmdbTopData.js | 0 12 files changed, 54 insertions(+), 48 deletions(-) rename src/{ => pages}/components/Card.jsx (100%) rename src/{ => pages}/components/NavigationBar.jsx (88%) rename src/{data => pages/components}/hooks/useDebounce.js (100%) rename src/{ => pages}/data/DummyDetailData.json (100%) rename src/{ => pages}/data/DummyMainData.json (100%) rename src/{ => pages}/data/hooks/useTmdbDetailData.js (100%) rename src/{ => pages}/data/hooks/useTmdbKeywordData.js (100%) rename src/{ => pages}/data/hooks/useTmdbMainData.js (100%) rename src/{ => pages}/data/hooks/useTmdbTopData.js (100%) diff --git a/src/Layout.jsx b/src/Layout.jsx index 58c69d12..df6005bd 100644 --- a/src/Layout.jsx +++ b/src/Layout.jsx @@ -1,10 +1,8 @@ import { Outlet } from "react-router-dom"; -import NavigationBar from "./components/NavigationBar.jsx"; export default function Layout() { return (
-
diff --git a/src/pages/DetailPage.jsx b/src/pages/DetailPage.jsx index 6d0c7f37..12b916d7 100644 --- a/src/pages/DetailPage.jsx +++ b/src/pages/DetailPage.jsx @@ -1,8 +1,10 @@ import styled from "styled-components"; +import NavigationBar from "./components/NavigationBar"; + import { useParams } from "react-router-dom"; -import useTmdbDetailData from "../data/hooks/useTmdbDetailData"; +import useTmdbDetailData from "./data/hooks/useTmdbDetailData"; // <-------------------- function --------------------> @@ -14,20 +16,23 @@ export default function DetailPage() { // <-------------------- return --------------------> return ( - - - - - {tmdbDetail.title} - {tmdbDetail.vote_average} - - {tmdbDetail.overview} - - + <> + + + + + + {tmdbDetail.title} + {tmdbDetail.vote_average} + + {tmdbDetail.overview} + + + ); } diff --git a/src/pages/MainPage.jsx b/src/pages/MainPage.jsx index 4acd5c28..7b983c1e 100644 --- a/src/pages/MainPage.jsx +++ b/src/pages/MainPage.jsx @@ -1,33 +1,38 @@ -import styled from 'styled-components'; +import styled from "styled-components"; +import Card from "./components/Card.jsx"; -import Card from '../components/Card.jsx'; -import useTmdbTopData from '../data/hooks/useTmdbTopData.js'; -import useTmdbMainData from '../data/hooks/useTmdbMainData.js'; -import useTmdbKeywordData from '../data/hooks/useTmdbKeywordData.js'; +import useTmdbTopData from "./data/hooks/useTmdbTopData.js"; +import useTmdbMainData from "./data/hooks/useTmdbMainData.js"; +import useTmdbKeywordData from "./data/hooks/useTmdbKeywordData.js"; -import NavigationBar from '../components/NavigationBar.jsx'; +import { Swiper, SwiperSlide } from "swiper/react"; +import { Navigation, Pagination, Autoplay } from "swiper/modules"; +import "swiper/css"; +import "swiper/css/navigation"; +import "swiper/css/pagination"; -import { Swiper, SwiperSlide } from 'swiper/react'; -import { Navigation, Pagination, Autoplay } from 'swiper/modules'; -import 'swiper/css'; -import 'swiper/css/navigation'; -import 'swiper/css/pagination'; -import { useSearchParams } from 'react-router-dom'; +import { useSearchParams } from "react-router-dom"; +import NavigationBar from "./components/NavigationBar.jsx"; // <-------------------- function --------------------> export default function MainPage() { - const [keyword, setKeyword] = useSearchParams(); + const [searchParams] = useSearchParams(); + const query = searchParams.get("keyword")?.trim(); + const tmdbTop = useTmdbTopData(); - const query = keyword.get("keyword")?.trim(); - const tmdbMain = query ? useTmdbKeywordData(query) : useTmdbMainData(query); + const tmdbMainData = useTmdbMainData(); + const tmdbKeywordData = useTmdbKeywordData(query); + + const tmdbData = query ? tmdbKeywordData : tmdbMainData; // <-------------------- return --------------------> return ( <> + - TOP 10 πŸ† + πŸ† TOP 10 - Popular ✨ - - {tmdbMain.map((api) => ( - + ✨ Popular + + {tmdbData.map((movie) => ( + ))} - + ); @@ -75,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/components/Card.jsx b/src/pages/components/Card.jsx similarity index 100% rename from src/components/Card.jsx rename to src/pages/components/Card.jsx diff --git a/src/components/NavigationBar.jsx b/src/pages/components/NavigationBar.jsx similarity index 88% rename from src/components/NavigationBar.jsx rename to src/pages/components/NavigationBar.jsx index 623079ea..64e086c1 100644 --- a/src/components/NavigationBar.jsx +++ b/src/pages/components/NavigationBar.jsx @@ -2,7 +2,7 @@ import styled from "styled-components"; import { Link, useSearchParams } from "react-router-dom"; import { useEffect, useState } from "react"; -import useDebounce from "../data/hooks/useDebounce.js"; +import useDebounce from "./hooks/useDebounce.js"; import useTmdbKeywordData from "../data/hooks/useTmdbKeywordData.js"; // <-------------------- function --------------------> @@ -12,17 +12,18 @@ export default function NavigationBar() { const keywordParam = searchParams.get("keyword") || ""; const [keyword, setKeyword] = useState(keywordParam); - const debouncedKeyword = useDebounce(keyword, 500); - const searchKeyword = useTmdbKeywordData(debouncedKeyword); + const debouncedKeyword = useDebounce(keyword, 100); + useTmdbKeywordData(debouncedKeyword); useEffect(() => { if (keyword.trim() === "") { - searchParams.delete("keyword"); - setSearchParams(searchParams); + const params = new URLSearchParams(searchParams); + params.delete("keyword"); + setSearchParams(params); } else { setSearchParams({ keyword }); } - }, [keyword]); + }, [keyword, searchParams, setSearchParams]); // <-------------------- return --------------------> @@ -40,9 +41,6 @@ export default function NavigationBar() { onChange={(e) => setKeyword(e.target.value)} /> - - {/* <-------------------- 검색 κ²°κ³Ό ν‘œμ‹œ */} - 둜그인 νšŒμ›κ°€μž… diff --git a/src/data/hooks/useDebounce.js b/src/pages/components/hooks/useDebounce.js similarity index 100% rename from src/data/hooks/useDebounce.js rename to src/pages/components/hooks/useDebounce.js diff --git a/src/data/DummyDetailData.json b/src/pages/data/DummyDetailData.json similarity index 100% rename from src/data/DummyDetailData.json rename to src/pages/data/DummyDetailData.json diff --git a/src/data/DummyMainData.json b/src/pages/data/DummyMainData.json similarity index 100% rename from src/data/DummyMainData.json rename to src/pages/data/DummyMainData.json diff --git a/src/data/hooks/useTmdbDetailData.js b/src/pages/data/hooks/useTmdbDetailData.js similarity index 100% rename from src/data/hooks/useTmdbDetailData.js rename to src/pages/data/hooks/useTmdbDetailData.js diff --git a/src/data/hooks/useTmdbKeywordData.js b/src/pages/data/hooks/useTmdbKeywordData.js similarity index 100% rename from src/data/hooks/useTmdbKeywordData.js rename to src/pages/data/hooks/useTmdbKeywordData.js diff --git a/src/data/hooks/useTmdbMainData.js b/src/pages/data/hooks/useTmdbMainData.js similarity index 100% rename from src/data/hooks/useTmdbMainData.js rename to src/pages/data/hooks/useTmdbMainData.js diff --git a/src/data/hooks/useTmdbTopData.js b/src/pages/data/hooks/useTmdbTopData.js similarity index 100% rename from src/data/hooks/useTmdbTopData.js rename to src/pages/data/hooks/useTmdbTopData.js