+
+
+
지금 인기 있는 영화
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 @@
지금 인기 있는 영화
- -
-
-

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

-
-
-
7.7
-
-
인사이드 아웃 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*/ `
-
-
-
-

-
-
${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*/ `
+
+
+
+

+
+
${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*/ `
+
+
+
+
+
+

+
+
+
${movieDetail.title}
+
${
+ movieDetail.releaseYear
+ } · ${movieDetail.genres.join(", ")}
+
${
+ movieDetail.rate
+ }
+
+
+ ${movieDetail.description}
+
+
+
+
+
+
+
+`;
+};