From 828251895595b176cdb49aea35f0b7eb9b6a9fa3 Mon Sep 17 00:00:00 2001 From: jayming66 Date: Thu, 3 Oct 2024 17:29:12 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat(ssr):=20=EA=B0=81=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=EB=B3=84=20SSR=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ssr/api/movies.js | 21 +++++++++++++ ssr/constant.js | 30 ++++++++++++++++++ ssr/server/routes/index.js | 24 +++++--------- ssr/utils/round.js | 5 +++ ssr/views/getTemplates.js | 64 ++++++++++++++++++++++++++++++++++++++ ssr/views/render.js | 45 +++++++++++++++++++++++++++ 6 files changed, 173 insertions(+), 16 deletions(-) create mode 100644 ssr/api/movies.js create mode 100644 ssr/constant.js create mode 100644 ssr/utils/round.js create mode 100644 ssr/views/getTemplates.js create mode 100644 ssr/views/render.js diff --git a/ssr/api/movies.js b/ssr/api/movies.js new file mode 100644 index 0000000..468c892 --- /dev/null +++ b/ssr/api/movies.js @@ -0,0 +1,21 @@ +import { + FETCH_OPTIONS, + PATH_TO_API, + TMDB_MOVIE_DETAIL_URL, + TMDB_MOVIE_LISTS, +} from '../constant.js'; + +export const fetchMovies = async (endpoint) => { + const response = await fetch( + TMDB_MOVIE_LISTS[PATH_TO_API[endpoint]], + FETCH_OPTIONS + ); + + return await response.json(); +}; + +export const fetchMovieDetail = async (id) => { + const response = await fetch(`${TMDB_MOVIE_DETAIL_URL}${id}`, FETCH_OPTIONS); + + return await response.json(); +}; diff --git a/ssr/constant.js b/ssr/constant.js new file mode 100644 index 0000000..4fef897 --- /dev/null +++ b/ssr/constant.js @@ -0,0 +1,30 @@ +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_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_MOVIE_LISTS = { + POPULAR: BASE_URL + '/popular?language=ko-KR&page=1', + NOW_PLAYING: BASE_URL + '/now_playing?language=ko-KR&page=1', + TOP_RATED: BASE_URL + '/top_rated?language=ko-KR&page=1', + UPCOMING: BASE_URL + '/upcoming?language=ko-KR&page=1', +}; +export const TMDB_MOVIE_DETAIL_URL = 'https://api.themoviedb.org/3/movie/'; + +export const FETCH_OPTIONS = { + method: 'GET', + headers: { + accept: 'application/json', + Authorization: 'Bearer ' + process.env.TMDB_TOKEN, + }, +}; + +export const PATH_TO_API = { + '/': 'NOW_PLAYING', + '/now-playing': 'NOW_PLAYING', + '/popular': 'POPULAR', + '/top-rated': 'TOP_RATED', + '/upcoming': 'UPCOMING', +}; diff --git a/ssr/server/routes/index.js b/ssr/server/routes/index.js index 84d32f2..30eeb9d 100644 --- a/ssr/server/routes/index.js +++ b/ssr/server/routes/index.js @@ -1,21 +1,13 @@ -import { Router } from "express"; -import fs from "fs"; -import path from "path"; -import { fileURLToPath } from "url"; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); +import { Router } from 'express'; +import { renderMovieDetail, renderMovieList } from '../../views/render.js'; const router = Router(); -router.get("/", (_, res) => { - const templatePath = path.join(__dirname, "../../views", "index.html"); - const moviesHTML = "

들어갈 본문 작성

"; - - const template = fs.readFileSync(templatePath, "utf-8"); - const renderedHTML = template.replace("", moviesHTML); - - res.send(renderedHTML); -}); +router.get('/', renderMovieList); +router.get('/now-playing', renderMovieList); +router.get('/popular', renderMovieList); +router.get('/top-rated', renderMovieList); +router.get('/upcoming', renderMovieList); +router.get('/detail/:id', renderMovieDetail); export default router; diff --git a/ssr/utils/round.js b/ssr/utils/round.js new file mode 100644 index 0000000..8e7f987 --- /dev/null +++ b/ssr/utils/round.js @@ -0,0 +1,5 @@ +export const round = (value, decimals = 0) => { + const factor = 10 ** decimals; + + return Math.round(value * factor) / factor; +}; diff --git a/ssr/views/getTemplates.js b/ssr/views/getTemplates.js new file mode 100644 index 0000000..9360c7b --- /dev/null +++ b/ssr/views/getTemplates.js @@ -0,0 +1,64 @@ +import { round } from '../utils/round.js'; + +export const getMovieItemsHTML = (movieItems) => { + return movieItems.map((movie) => { + const thumbnailUrl = `https://image.tmdb.org/t/p/w200${movie.poster_path}`; + const roundedRate = round(movie.vote_average, 1); + + return /*html*/ ` +
  • + + ${movie.title} +
    +

    + + ${roundedRate} +

    + ${movie.title} +
    +
    +
  • + `; + }); +}; + +export const getMovieDetailModalHTML = (moviesPageTemplate, movieDetail) => { + return moviesPageTemplate.replace( + '', + /*html*/ ` + + + + ` + ); +}; diff --git a/ssr/views/render.js b/ssr/views/render.js new file mode 100644 index 0000000..9a9b9e4 --- /dev/null +++ b/ssr/views/render.js @@ -0,0 +1,45 @@ +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +import { fetchMovieDetail, fetchMovies } from '../api/movies.js'; +import { getMovieDetailModalHTML, getMovieItemsHTML } from './getTemplates.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +export const renderMovieList = async (req, res) => { + const endpoint = req.path; + const movieItems = await fetchMovies(endpoint).then((data) => data.results); + const bestMovieItem = movieItems[0]; + const moviesHTML = getMovieItemsHTML(movieItems).join(''); + + const templatePath = path.join(__dirname, './', 'index.html'); + let template = fs.readFileSync(templatePath, 'utf-8'); + + template = template.replace('', moviesHTML); + template = template.replace( + '${background-container}', + '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); + + res.send(template); +}; + +export const renderMovieDetail = async (req, res) => { + const { id: movieId } = req.params; + const movieDetailItem = await fetchMovieDetail(movieId).then((data) => data); + console.log('movieDetailItem', movieDetailItem); + const templatePath = path.join(__dirname, './', 'index.html'); + let template = fs.readFileSync(templatePath, 'utf-8'); + + const movieDetailModalHTML = getMovieDetailModalHTML( + template, + movieDetailItem + ); + + res.send(movieDetailModalHTML); +}; From d38be214e8361db0b095548766216ad0b5ca5a06 Mon Sep 17 00:00:00 2001 From: jayming66 Date: Thu, 3 Oct 2024 18:16:16 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat(ssr):=20=EB=AA=A8=EB=8B=AC=20=EB=B0=8F?= =?UTF-8?q?=20tab=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ssr/server/routes/index.js | 51 ++++++++++++++++++++++++++++++++------ ssr/views/getTemplates.js | 13 ++++------ ssr/views/index.html | 21 ++++++++++------ ssr/views/render.js | 38 ++++++++++++++++++---------- 4 files changed, 87 insertions(+), 36 deletions(-) diff --git a/ssr/server/routes/index.js b/ssr/server/routes/index.js index 30eeb9d..23b0612 100644 --- a/ssr/server/routes/index.js +++ b/ssr/server/routes/index.js @@ -1,13 +1,50 @@ import { Router } from 'express'; -import { renderMovieDetail, renderMovieList } from '../../views/render.js'; +import { renderMovieDetailModal, renderMovieList } from '../../views/render.js'; const router = Router(); -router.get('/', renderMovieList); -router.get('/now-playing', renderMovieList); -router.get('/popular', renderMovieList); -router.get('/top-rated', renderMovieList); -router.get('/upcoming', renderMovieList); -router.get('/detail/:id', renderMovieDetail); +router.get('/', async (req, res) => { + const endpoint = '/now-playing'; + const template = await renderMovieList(endpoint, res); + + res.send(template); +}); + +router.get('/now-playing', async (req, res) => { + const endpoint = req.path; + const template = await renderMovieList(endpoint, res); + + res.send(template); +}); + +router.get('/popular', async (req, res) => { + const endpoint = req.path; + const template = await renderMovieList(endpoint, res); + + res.send(template); +}); + +router.get('/top-rated', async (req, res) => { + const endpoint = req.path; + const template = await renderMovieList(endpoint, res); + + res.send(template); +}); + +router.get('/upcoming', async (req, res) => { + const endpoint = req.path; + const template = await renderMovieList(endpoint, res); + + res.send(template); +}); + +router.get('/detail/:id', async (req, res) => { + let template = await renderMovieList('/now-playing', res); + const modal = await renderMovieDetailModal(req, res); + + template = template.replace('', modal); + + res.send(template); +}); export default router; diff --git a/ssr/views/getTemplates.js b/ssr/views/getTemplates.js index 9360c7b..79b98b4 100644 --- a/ssr/views/getTemplates.js +++ b/ssr/views/getTemplates.js @@ -22,13 +22,11 @@ export const getMovieItemsHTML = (movieItems) => { }); }; -export const getMovieDetailModalHTML = (moviesPageTemplate, movieDetail) => { - return moviesPageTemplate.replace( - '', - /*html*/ ` +export const getMovieDetailModalHTML = (movieDetail) => { + return /*html*/ `