From 3dfb0dd2e4df232815c5b50dcceb05a139c88c44 Mon Sep 17 00:00:00 2001 From: ooherin <555ohr@naver.com> Date: Wed, 2 Oct 2024 19:50:21 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=EC=9D=B8=EA=B8=B0=EC=9E=88?= =?UTF-8?q?=EB=8A=94=20=EC=98=81=ED=99=94=20=EB=B3=B4=EB=82=B4=EC=A3=BC?= =?UTF-8?q?=EB=8A=94=20=EB=A1=9C=EC=A7=81=20=EC=99=84=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- csr/src/Constant.js | 6 +- csr/src/apis/movies.js | 8 ++ csr/src/hooks/useMovies.js | 7 +- ssr/README.md | 22 +++-- ssr/server/routes/index.js | 73 +++++++++++++++-- ssr/src/constant.js | 22 +++++ ssr/src/fetchMovies.js | 6 ++ static/index.html | 159 ++++++++++++++++++++++++++++++------- 8 files changed, 261 insertions(+), 42 deletions(-) create mode 100644 csr/src/apis/movies.js create mode 100644 ssr/src/constant.js create mode 100644 ssr/src/fetchMovies.js diff --git a/csr/src/Constant.js b/csr/src/Constant.js index 450f04b..0b10dc0 100644 --- a/csr/src/Constant.js +++ b/csr/src/Constant.js @@ -1,8 +1,10 @@ export const BASE_URL = "https://api.themoviedb.org/3/movie"; -export const TMDB_THUMBNAIL_URL = "https://media.themoviedb.org/t/p/w440_and_h660_face/"; +export const TMDB_THUMBNAIL_URL = + "https://media.themoviedb.org/t/p/w440_and_h660_face/"; export const TMDB_ORIGINAL_URL = "https://image.tmdb.org/t/p/original/"; -export const TMDB_BANNER_URL = "https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/"; +export const TMDB_BANNER_URL = + "https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/"; export const TMDB_MOVIE_LISTS = { popular: BASE_URL + "/popular?language=ko-KR&page=1", nowPlaying: BASE_URL + "/now_playing?language=ko-KR&page=1", diff --git a/csr/src/apis/movies.js b/csr/src/apis/movies.js new file mode 100644 index 0000000..7d754da --- /dev/null +++ b/csr/src/apis/movies.js @@ -0,0 +1,8 @@ +import { FETCH_OPTIONS, TMDB_MOVIE_LISTS } from "../Constant"; + +export const fetchMovies = async () => { + const response = await fetch(TMDB_MOVIE_LISTS.popular, FETCH_OPTIONS); + + console.log("response", response); + return await response.json(); +}; diff --git a/csr/src/hooks/useMovies.js b/csr/src/hooks/useMovies.js index 83665da..381da88 100644 --- a/csr/src/hooks/useMovies.js +++ b/csr/src/hooks/useMovies.js @@ -15,7 +15,12 @@ const useMovies = () => { const [upcomingMovies, setUpcomingMovies] = useAtom(upcomingMoviesAtom); const [focusedIndex, setFocusedIndex] = useAtom(focusedIndexAtom); - const movieLists = [nowPlayingMovies, popularMovies, topRatedMovies, upcomingMovies]; + const movieLists = [ + nowPlayingMovies, + popularMovies, + topRatedMovies, + upcomingMovies, + ]; const loadMovies = async (url, setter) => { const response = await fetch(url, FETCH_OPTIONS); diff --git a/ssr/README.md b/ssr/README.md index cdc2981..8f42037 100644 --- a/ssr/README.md +++ b/ssr/README.md @@ -25,9 +25,11 @@ npm run dev ```js export const BASE_URL = "https://api.themoviedb.org/3/movie"; - export const TMDB_THUMBNAIL_URL = "https://media.themoviedb.org/t/p/w440_and_h660_face/"; + export const TMDB_THUMBNAIL_URL = + "https://media.themoviedb.org/t/p/w440_and_h660_face/"; export const TMDB_ORIGINAL_URL = "https://image.tmdb.org/t/p/original/"; - export const TMDB_BANNER_URL = "https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/"; + export const TMDB_BANNER_URL = + "https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/"; export const TMDB_MOVIE_LISTS = { POPULAR: BASE_URL + "/popular?language=ko-KR&page=1", NOW_PLAYING: BASE_URL + "/now_playing?language=ko-KR&page=1", @@ -100,10 +102,14 @@ express 서버에서 `views/index.html` 파일을 활용하여 클라이언트 const templatePath = path.join(__dirname, "../../views", "index.html"); let template = fs.readFileSync(templatePath, "utf-8"); - template = template.replace("", moviesHTML); + template = template.replace( + "", + moviesHTML + ); template = template.replace( "${background-container}", - "https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/" + bestMovieItem.background + "https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/" + + bestMovieItem.background ); template = template.replace("${bestMovie.rate}", bestMovieItem.rate); template = template.replace("${bestMovie.title}", bestMovieItem.title); @@ -127,11 +133,15 @@ express 서버에서 `views/index.html` 파일을 활용하여 클라이언트 @@ -139,7 +166,11 @@

지금 인기 있는 영화

alt="인사이드 아웃 2" />
-

7.7

+

+ 7.7 +

인사이드 아웃 2
@@ -152,7 +183,11 @@

지금 인기 있는 영화

alt="인사이드 아웃 2" />
-

7.7

+

+ 7.7 +

인사이드 아웃 2
@@ -165,7 +200,11 @@

지금 인기 있는 영화

alt="인사이드 아웃 2" />
-

7.7

+

+ 7.7 +

인사이드 아웃 2
@@ -178,7 +217,11 @@

지금 인기 있는 영화

alt="인사이드 아웃 2" />
-

7.7

+

+ 7.7 +

인사이드 아웃 2
@@ -191,7 +234,11 @@

지금 인기 있는 영화

alt="인사이드 아웃 2" />
-

7.7

+

+ 7.7 +

인사이드 아웃 2
@@ -204,7 +251,11 @@

지금 인기 있는 영화

alt="인사이드 아웃 2" />
-

7.7

+

+ 7.7 +

인사이드 아웃 2
@@ -217,7 +268,11 @@

지금 인기 있는 영화

alt="인사이드 아웃 2" />
-

7.7

+

+ 7.7 +

인사이드 아웃 2
@@ -230,7 +285,11 @@

지금 인기 있는 영화

alt="인사이드 아웃 2" />
-

7.7

+

+ 7.7 +

인사이드 아웃 2
@@ -243,7 +302,11 @@

지금 인기 있는 영화

alt="인사이드 아웃 2" />
-

7.7

+

+ 7.7 +

인사이드 아웃 2
@@ -256,7 +319,11 @@

지금 인기 있는 영화

alt="인사이드 아웃 2" />
-

7.7

+

+ 7.7 +

인사이드 아웃 2
@@ -269,7 +336,11 @@

지금 인기 있는 영화

alt="인사이드 아웃 2" />
-

7.7

+

+ 7.7 +

인사이드 아웃 2
@@ -282,7 +353,11 @@

지금 인기 있는 영화

alt="인사이드 아웃 2" />
-

7.7

+

+ 7.7 +

인사이드 아웃 2
@@ -295,7 +370,11 @@

지금 인기 있는 영화

alt="인사이드 아웃 2" />
-

7.7

+

+ 7.7 +

인사이드 아웃 2
@@ -308,7 +387,11 @@

지금 인기 있는 영화

alt="인사이드 아웃 2" />
-

7.7

+

+ 7.7 +

인사이드 아웃 2
@@ -321,7 +404,11 @@

지금 인기 있는 영화

alt="인사이드 아웃 2" />
-

7.7

+

+ 7.7 +

인사이드 아웃 2
@@ -334,7 +421,11 @@

지금 인기 있는 영화

alt="인사이드 아웃 2" />
-

7.7

+

+ 7.7 +

인사이드 아웃 2
@@ -347,7 +438,11 @@

지금 인기 있는 영화

alt="인사이드 아웃 2" />
-

7.7

+

+ 7.7 +

인사이드 아웃 2
@@ -360,7 +455,11 @@

지금 인기 있는 영화

alt="인사이드 아웃 2" />
-

7.7

+

+ 7.7 +

인사이드 아웃 2
@@ -373,7 +472,11 @@

지금 인기 있는 영화

alt="인사이드 아웃 2" />
-

7.7

+

+ 7.7 +

인사이드 아웃 2
From 3d152f0a62066b095dce23fe8e2ef17d75343ff4 Mon Sep 17 00:00:00 2001 From: ooherin <555ohr@naver.com> Date: Thu, 3 Oct 2024 10:05:55 +0900 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20=ED=83=AD=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- csr/src/components/Container.jsx | 26 +- ssr/server/routes/index.js | 66 +++-- ssr/src/fetchMovies.js | 6 +- ssr/tab.js | 0 ssr/views/index.html | 16 +- static/index.html | 426 +------------------------------ 6 files changed, 82 insertions(+), 458 deletions(-) create mode 100644 ssr/tab.js diff --git a/csr/src/components/Container.jsx b/csr/src/components/Container.jsx index cfe7fc5..6361e01 100644 --- a/csr/src/components/Container.jsx +++ b/csr/src/components/Container.jsx @@ -47,18 +47,28 @@ function Container() { return (
- +

지금 인기 있는 영화

    - {lists[focusedIndex].map(({ id, title, vote_average, poster_path }) => ( -
  • - - - -
  • - ))} + {lists[focusedIndex].map( + ({ id, title, vote_average, poster_path }) => ( +
  • + + + +
  • + ) + )}
diff --git a/ssr/server/routes/index.js b/ssr/server/routes/index.js index 04b7d91..fa12450 100644 --- a/ssr/server/routes/index.js +++ b/ssr/server/routes/index.js @@ -3,33 +3,38 @@ import fs from "fs"; import path from "path"; import { fileURLToPath } from "url"; import { fetchMovies } from "../../src/fetchMovies.js"; +import { TMDB_MOVIE_LISTS } from "../../src/constant.js"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const router = Router(); -export const getFormattedMovies = async () => { - const movieData = await fetchMovies(); - +export const getFormattedMovies = async (endpoint) => { + const movieData = await fetchMovies(endpoint); const formattedMovieData = movieData.results.map((movie) => ({ id: movie.id, title: movie.title, thumbnail: movie.poster_path, rate: movie.vote_average, + background: movie.backdrop_path, })); return formattedMovieData; }; -const getMovieListHTML = (moviesData) => { +const rendermoviesTemplate = (moviesData, endpoint) => { const bestMovieItem = moviesData[0]; - const moviesHTML = rendermoviesData(moviesData).join(""); + const moviesHTML = getMoviesHTMLTemplate(moviesData).join(""); + const tabsHTML = getTabsHTMLTemplate(endpoint).join(""); + + console.log("tabsHTML", tabsHTML); const templatePath = path.join(__dirname, "../../views", "index.html"); let template = fs.readFileSync(templatePath, "utf-8"); template = template.replace("", moviesHTML); + template = template.replace(" ", tabsHTML); template = template.replace( "${background-container}", "https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/" + @@ -41,7 +46,7 @@ const getMovieListHTML = (moviesData) => { return template; }; -export const rendermoviesData = (movieItems = []) => +export const getMoviesHTMLTemplate = (movieItems = []) => movieItems.map( ({ id, title, thumbnail, rate }) => /*html*/ `
  • @@ -62,23 +67,48 @@ export const rendermoviesData = (movieItems = []) => ` ); -router.get("/", async (_, res) => { +const handleMovieRoute = async (res, category) => { + const endpoint = TMDB_MOVIE_LISTS[category]; try { - const templatePath = path.join(__dirname, "../../views", "index.html"); - const movieData = await getFormattedMovies(); - const moviesHTML = getMovieListHTML(movieData); - - const template = fs.readFileSync(templatePath, "utf-8"); - const renderedHTML = template.replace( - "", - moviesHTML - ); + const movieData = await getFormattedMovies(endpoint); + const moviesHTML = rendermoviesTemplate(movieData, category); - res.send(renderedHTML); + res.send(moviesHTML); } catch (error) { console.error("Error rendering page:", error); res.status(500).send("Internal Server Error"); } -}); +}; + +const getTabsHTMLTemplate = (selectedCategory) => { + const categories = { + NOW_PLAYING: "상영 중", + POPULAR: "인기순", + TOP_RATED: "평점순", + UPCOMING: "상영 예정", + }; + + return Object.entries(categories).map((category) => { + const isSelected = selectedCategory === category[0] ? "selected" : ""; + const href = `/${category[0].toLowerCase().replace("_", "-")}`; + + return ( + /*html*/ + `
  • + +

    ${category[1]}

    +
    +
  • ` + ); + }); +}; + +router.get("/", async (_, res) => handleMovieRoute(res, "NOW_PLAYING")); +router.get("/now-playing", async (_, res) => + handleMovieRoute(res, "NOW_PLAYING") +); +router.get("/popular", async (_, res) => handleMovieRoute(res, "POPULAR")); +router.get("/top-rated", async (_, res) => handleMovieRoute(res, "TOP_RATED")); +router.get("/upcoming", async (_, res) => handleMovieRoute(res, "UPCOMING")); export default router; diff --git a/ssr/src/fetchMovies.js b/ssr/src/fetchMovies.js index 2f091d7..dc79a17 100644 --- a/ssr/src/fetchMovies.js +++ b/ssr/src/fetchMovies.js @@ -1,6 +1,6 @@ -import { FETCH_OPTIONS, TMDB_MOVIE_LISTS } from "./constant.js"; +import { FETCH_OPTIONS } from "./constant.js"; -export const fetchMovies = async () => { - const response = await fetch(TMDB_MOVIE_LISTS.POPULAR, FETCH_OPTIONS); +export const fetchMovies = async (endpoint) => { + const response = await fetch(endpoint, FETCH_OPTIONS); return await response.json(); }; diff --git a/ssr/tab.js b/ssr/tab.js new file mode 100644 index 0000000..e69de29 diff --git a/ssr/views/index.html b/ssr/views/index.html index a052396..216470d 100644 --- a/ssr/views/index.html +++ b/ssr/views/index.html @@ -14,10 +14,15 @@
    -
    +
    -

    MovieList

    +

    + MovieList +

    @@ -32,8 +37,9 @@

    MovieList

    +

    지금 인기 있는 영화

    diff --git a/static/index.html b/static/index.html index 49c0ceb..54f1505 100644 --- a/static/index.html +++ b/static/index.html @@ -56,431 +56,7 @@

    지금 인기 있는 영화

      -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • -
    • -
      - 인사이드 아웃 2 -
      -

      - 7.7 -

      - 인사이드 아웃 2 -
      -
      -
    • +

    From fbade2a9381c35ef5d5013879a68e20ac6d0048d Mon Sep 17 00:00:00 2001 From: ooherin <555ohr@naver.com> Date: Thu, 3 Oct 2024 11:56:33 +0900 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20ssr=20=EB=AA=A8=EB=8B=AC=20?= =?UTF-8?q?=EB=9D=84=EC=9A=B0=EA=B8=B0=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- csr/src/apis/movies.js | 1 - ssr/server/routes/index.js | 141 +++++++++++++++++++++---------------- ssr/src/fetchMovies.js | 19 ++++- ssr/views/index.html | 27 ------- ssr/views/template.js | 83 ++++++++++++++++++++++ 5 files changed, 179 insertions(+), 92 deletions(-) create mode 100644 ssr/views/template.js diff --git a/csr/src/apis/movies.js b/csr/src/apis/movies.js index 7d754da..6421631 100644 --- a/csr/src/apis/movies.js +++ b/csr/src/apis/movies.js @@ -3,6 +3,5 @@ import { FETCH_OPTIONS, TMDB_MOVIE_LISTS } from "../Constant"; export const fetchMovies = async () => { const response = await fetch(TMDB_MOVIE_LISTS.popular, FETCH_OPTIONS); - console.log("response", response); return await response.json(); }; diff --git a/ssr/server/routes/index.js b/ssr/server/routes/index.js index fa12450..4c7685e 100644 --- a/ssr/server/routes/index.js +++ b/ssr/server/routes/index.js @@ -2,39 +2,54 @@ import { Router } from "express"; import fs from "fs"; import path from "path"; import { fileURLToPath } from "url"; -import { fetchMovies } from "../../src/fetchMovies.js"; -import { TMDB_MOVIE_LISTS } from "../../src/constant.js"; +import { fetchMovieDetail, fetchMovies } from "../../src/fetchMovies.js"; +import { + renderDetailModal, + renderMovieItems, + renderTabs, +} from "../../views/template.js"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const router = Router(); -export const getFormattedMovies = async (endpoint) => { - const movieData = await fetchMovies(endpoint); - const formattedMovieData = movieData.results.map((movie) => ({ - id: movie.id, - title: movie.title, - thumbnail: movie.poster_path, - rate: movie.vote_average, - background: movie.backdrop_path, - })); +const getMovieList = async (category) => { + const movieData = await fetchMovies(category); + return parseMovies(movieData); +}; - return formattedMovieData; +const getMovieDetail = async (movieId) => { + const movieDetailData = await fetchMovieDetail(movieId); + return parseMovieDetail(movieDetailData); }; -const rendermoviesTemplate = (moviesData, endpoint) => { - const bestMovieItem = moviesData[0]; - const moviesHTML = getMoviesHTMLTemplate(moviesData).join(""); - const tabsHTML = getTabsHTMLTemplate(endpoint).join(""); +const renderMoviesPage = async (category) => { + const movieList = await getMovieList(category); + const templatePath = path.join(__dirname, "../../views", "index.html"); + let template = fs.readFileSync(templatePath, "utf-8"); + return renderMoviesTemplate(template, movieList, category); +}; - console.log("tabsHTML", tabsHTML); +const renderMoviesDetailPage = async (category, movieId) => { + const movieList = await getMovieList(category); + const movieDetail = await getMovieDetail(movieId); const templatePath = path.join(__dirname, "../../views", "index.html"); let template = fs.readFileSync(templatePath, "utf-8"); + template = renderMoviesTemplate(template, movieList, category); + template = renderModalTemplate(template, movieDetail); + + return template; +}; + +export const renderMoviesTemplate = (template, movieList, category) => { + const bestMovieItem = movieList[0]; + const moviesHTML = renderMovieItems(movieList).join(""); + const tabsHTML = renderTabs(category).join(""); template = template.replace("", moviesHTML); - template = template.replace(" ", tabsHTML); + template = template.replace("", tabsHTML); template = template.replace( "${background-container}", "https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/" + @@ -46,61 +61,58 @@ const rendermoviesTemplate = (moviesData, endpoint) => { return template; }; -export const getMoviesHTMLTemplate = (movieItems = []) => - movieItems.map( - ({ id, title, thumbnail, rate }) => /*html*/ ` -
  • - -
    - ${title} -
    -

    ${rate}

    - ${title} -
    -
    -
    -
  • - ` +export const renderModalTemplate = (template, movieDetailItem) => { + return template.replace( + "", + renderDetailModal(movieDetailItem) ); +}; + +export const parseMovies = async (movieData) => { + const formattedMovieData = movieData.results.map((movie) => ({ + id: movie.id, + title: movie.title, + thumbnail: movie.poster_path, + rate: movie.vote_average, + background: movie.backdrop_path, + })); + + return formattedMovieData; +}; + +export const parseMovieDetail = async (movie) => { + return { + id: movie.id, + title: movie.title, + thumbnail: movie.poster_path, + releaseYear: movie.release_date, + genres: movie.genres.map((genre) => genre.name), + description: movie.overview, + rate: movie.vote_average, + }; +}; const handleMovieRoute = async (res, category) => { - const endpoint = TMDB_MOVIE_LISTS[category]; try { - const movieData = await getFormattedMovies(endpoint); - const moviesHTML = rendermoviesTemplate(movieData, category); - - res.send(moviesHTML); + let template = await renderMoviesPage(category); + res.send(template); } catch (error) { console.error("Error rendering page:", error); res.status(500).send("Internal Server Error"); } }; -const getTabsHTMLTemplate = (selectedCategory) => { - const categories = { - NOW_PLAYING: "상영 중", - POPULAR: "인기순", - TOP_RATED: "평점순", - UPCOMING: "상영 예정", - }; - - return Object.entries(categories).map((category) => { - const isSelected = selectedCategory === category[0] ? "selected" : ""; - const href = `/${category[0].toLowerCase().replace("_", "-")}`; - - return ( - /*html*/ - `
  • - -

    ${category[1]}

    -
    -
  • ` +const handleDetailRoute = async (res, movieId) => { + try { + const moviesPageTemplate = await renderMoviesDetailPage( + "NOW_PLAYING", + movieId ); - }); + res.send(moviesPageTemplate); + } catch (error) { + console.error("Error rendering page:", error); + res.status(500).send("Internal Server Error"); + } }; router.get("/", async (_, res) => handleMovieRoute(res, "NOW_PLAYING")); @@ -111,4 +123,9 @@ router.get("/popular", async (_, res) => handleMovieRoute(res, "POPULAR")); router.get("/top-rated", async (_, res) => handleMovieRoute(res, "TOP_RATED")); router.get("/upcoming", async (_, res) => handleMovieRoute(res, "UPCOMING")); +router.get("/detail/:id", async (req, res) => { + const { id } = req.params; + handleDetailRoute(res, id); +}); + export default router; diff --git a/ssr/src/fetchMovies.js b/ssr/src/fetchMovies.js index dc79a17..a9ca132 100644 --- a/ssr/src/fetchMovies.js +++ b/ssr/src/fetchMovies.js @@ -1,6 +1,21 @@ -import { FETCH_OPTIONS } from "./constant.js"; +import { + FETCH_OPTIONS, + TMDB_MOVIE_DETAIL_URL, + TMDB_MOVIE_LISTS, +} from "./constant.js"; -export const fetchMovies = async (endpoint) => { +export const fetchMovies = async (category) => { + const endpoint = TMDB_MOVIE_LISTS[category]; const response = await fetch(endpoint, FETCH_OPTIONS); return await response.json(); }; + +export const fetchMovieDetail = async (id) => { + const url = TMDB_MOVIE_DETAIL_URL + id; + const params = new URLSearchParams({ + language: "ko-KR", + }); + const response = await fetch(url + "?" + params, FETCH_OPTIONS); + + return await response.json(); +}; diff --git a/ssr/views/index.html b/ssr/views/index.html index 216470d..6542a40 100644 --- a/ssr/views/index.html +++ b/ssr/views/index.html @@ -38,33 +38,6 @@

    • -
    diff --git a/ssr/views/template.js b/ssr/views/template.js new file mode 100644 index 0000000..454d542 --- /dev/null +++ b/ssr/views/template.js @@ -0,0 +1,83 @@ +export const renderMovieItems = (movieItems = []) => + movieItems.map( + ({ id, title, thumbnail, rate }) => /*html*/ ` +
  • + +
    + ${title} +
    +

    ${rate}

    + ${title} +
    +
    +
    +
  • + ` + ); + +export const renderTabs = (selectedCategory) => { + const categories = { + NOW_PLAYING: "상영 중", + POPULAR: "인기순", + TOP_RATED: "평점순", + UPCOMING: "상영 예정", + }; + + return Object.entries(categories).map((category) => { + const isSelected = selectedCategory === category[0] ? "selected" : ""; + const href = `/${category[0].toLowerCase().replace("_", "-")}`; + + return ( + /*html*/ + `
  • + +

    ${category[1]}

    +
    +
  • ` + ); + }); +}; + +export const renderDetailModal = (movieDetail) => { + return /*html*/ ` + + + +`; +};