From c66526241c38eb1791420ae3a6148ffde3032e8d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E2=80=9CHenry-Hiles=E2=80=9D?= <“henry@henryhiles.com”>
Date: Thu, 27 Oct 2022 13:48:50 -0400
Subject: [PATCH] Lots of changes
---
jsconfig.json | 1 -
src/App.css | 1 -
src/components/Card.jsx | 5 +-
src/components/TopBar.jsx | 9 ++-
src/constants.js | 21 ++++++
src/contexts/MoviesContext.jsx | 71 -------------------
src/hooks/useDebounce.jsx | 14 ++++
src/index.css | 16 +++--
src/main.jsx | 9 +--
src/pages/Home.jsx | 43 +++++++++++-
src/pages/Movie.jsx | 120 ++++++++++++++++++++++++++-------
src/styles/Card.module.css | 9 +++
src/styles/Home.module.css | 1 +
src/styles/Movie.module.css | 58 ++++++++++++++++
src/styles/TopBar.module.css | 21 ++++++
vite.config.js | 1 -
16 files changed, 286 insertions(+), 114 deletions(-)
create mode 100644 src/constants.js
delete mode 100644 src/contexts/MoviesContext.jsx
create mode 100644 src/hooks/useDebounce.jsx
create mode 100644 src/styles/Movie.module.css
create mode 100644 src/styles/TopBar.module.css
diff --git a/jsconfig.json b/jsconfig.json
index c927f2a..c598157 100644
--- a/jsconfig.json
+++ b/jsconfig.json
@@ -5,7 +5,6 @@
"styles/*": ["styles/*"],
"components/*": ["components/*"],
"hooks/*": ["hooks/*"],
- "contexts/*": ["contexts/*"],
"pages/*": ["pages/*"]
}
}
diff --git a/src/App.css b/src/App.css
index 2e75c1f..1cfffd2 100644
--- a/src/App.css
+++ b/src/App.css
@@ -1,4 +1,3 @@
-#root,
.App {
width: 100%;
height: 100%;
diff --git a/src/components/Card.jsx b/src/components/Card.jsx
index 1a9f6d1..f8c9549 100644
--- a/src/components/Card.jsx
+++ b/src/components/Card.jsx
@@ -10,7 +10,9 @@ const Card = ({ movie }) => (
className={styles.Image}
/>
-
React Movie Finder
+
+
React Movie Finder
setSearch(target.value)}
/>
diff --git a/src/constants.js b/src/constants.js
new file mode 100644
index 0000000..c5bb65e
--- /dev/null
+++ b/src/constants.js
@@ -0,0 +1,21 @@
+export const GENRES = [
+ { id: 28, name: "Action" },
+ { id: 12, name: "Adventure" },
+ { id: 16, name: "Animation" },
+ { id: 35, name: "Comedy" },
+ { id: 80, name: "Crime" },
+ { id: 99, name: "Documentary" },
+ { id: 18, name: "Drama" },
+ { id: 10751, name: "Family" },
+ { id: 14, name: "Fantasy" },
+ { id: 36, name: "History" },
+ { id: 27, name: "Horror" },
+ { id: 10402, name: "Music" },
+ { id: 9648, name: "Mystery" },
+ { id: 10749, name: "Romance" },
+ { id: 878, name: "Science Fiction" },
+ { id: 10770, name: "TV Movie" },
+ { id: 53, name: "Thriller" },
+ { id: 10752, name: "War" },
+ { id: 37, name: "Western" },
+]
diff --git a/src/contexts/MoviesContext.jsx b/src/contexts/MoviesContext.jsx
deleted file mode 100644
index 12e2e50..0000000
--- a/src/contexts/MoviesContext.jsx
+++ /dev/null
@@ -1,71 +0,0 @@
-import { createContext, useContext, useEffect, useState } from "react"
-import config from "config"
-
-const MoviesContext = createContext()
-
-export const useMovies = () => useContext(MoviesContext)
-
-export const MoviesProvider = ({ children }) => {
- const [movies, setMovies] = useState([])
- const [genres, setGenres] = useState({})
- const [page, setPage] = useState(1)
- const [search, setSearch] = useState("")
-
- useEffect(() => {
- const run = async () => {
- const genresResponse = await fetch(
- `https://api.themoviedb.org/3/genre/movie/list?api_key=${config.apiKey}`
- )
- const genresData = await genresResponse.json()
- genresData.genres.forEach((genre) =>
- setGenres((current) => {
- const copy = {}
- Object.assign(copy, current)
- copy[genre.id] = genre.name
- return copy
- })
- )
- }
- run()
- })
-
- useEffect(() => {
- const run = async () => {
- const response = await fetch(
- `https://api.themoviedb.org/3/${
- search ? "search" : "discover"
- }/movie?api_key=${
- config.apiKey
- }&page=${page}&query=${encodeURIComponent(search)}`
- )
- const data = await response.json()
- setMovies(
- data.results.map((movie) => ({
- id: movie.id,
- overview: movie.overview,
- adult: movie.adult,
- posterUrl: `https://image.tmdb.org/t/p/w342/${movie.poster_path}`,
- backdropUrl: `https://image.tmdb.org/t/p/original/${movie.backdrop_path}`,
- genres: movie.genre_ids.map((genreId) => genres[genreId]),
- title: movie.title,
- releaseDate: movie.release_date,
- averageVote: movie.vote_average,
- voteCount: movie.vote_count,
- popularity: movie.popularity,
- }))
- )
- }
-
- run()
- }, [page, genres])
-
- const nextPage = () => setPage((page) => page + 1)
-
- return (
-
- {children}
-
- )
-}
diff --git a/src/hooks/useDebounce.jsx b/src/hooks/useDebounce.jsx
new file mode 100644
index 0000000..c172c28
--- /dev/null
+++ b/src/hooks/useDebounce.jsx
@@ -0,0 +1,14 @@
+import { useState, useEffect } from "react"
+
+export default function useDebounce(value, delay = 500) {
+ const [debouncedValue, setDebouncedValue] = useState(value)
+
+ useEffect(() => {
+ const timeout = setTimeout(() => {
+ setDebouncedValue(value)
+ }, delay)
+ return () => clearTimeout(timeout)
+ }, [value, delay])
+
+ return debouncedValue
+}
diff --git a/src/index.css b/src/index.css
index 0c99d4c..b2f5e28 100644
--- a/src/index.css
+++ b/src/index.css
@@ -10,14 +10,12 @@
}
body {
- background-color: var(--secondary);
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
"Helvetica Neue", sans-serif;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- height: 100%;
+ margin: 0;
+ background-color: var(--secondary);
}
code {
@@ -28,3 +26,13 @@ code {
button {
cursor: pointer;
}
+
+hr {
+ width: 97%;
+ color: white;
+}
+
+#root,
+body {
+ height: 100%;
+}
diff --git a/src/main.jsx b/src/main.jsx
index 76e4499..b3eda51 100644
--- a/src/main.jsx
+++ b/src/main.jsx
@@ -2,15 +2,12 @@ import React from "react"
import ReactDOM from "react-dom/client"
import App from "./App"
import "./index.css"
-import { MoviesProvider } from "contexts/MoviesContext"
import { BrowserRouter } from "react-router-dom"
ReactDOM.createRoot(document.getElementById("root")).render(
-
-
-
-
-
+
+
+
)
diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx
index 3730213..acf5f89 100644
--- a/src/pages/Home.jsx
+++ b/src/pages/Home.jsx
@@ -1,10 +1,49 @@
-import { useMovies } from "contexts/MoviesContext"
import CardList from "components/CardList"
import TopBar from "components/TopBar"
+import useDebounce from "hooks/useDebounce"
+import { useEffect, useState } from "react"
import styles from "styles/Home.module.css"
+import config from "config"
+import { GENRES } from "../constants"
const Home = () => {
- const [movies, page, search, { nextPage, setSearch }] = useMovies()
+ const [movies, setMovies] = useState([])
+ const [page, setPage] = useState(1)
+ const [search, setSearch] = useState("")
+ const debouncedSearch = useDebounce(search)
+
+ useEffect(() => {
+ const run = async () => {
+ const response = await fetch(
+ `https://api.themoviedb.org/3/${
+ debouncedSearch ? "search" : "discover"
+ }/movie?api_key=${
+ config.apiKey
+ }&page=${page}&query=${encodeURIComponent(debouncedSearch)}`
+ )
+ const data = await response.json()
+ setMovies(
+ data.results.map((movie) => ({
+ id: movie.id,
+ overview: movie.overview,
+ adult: movie.adult,
+ posterUrl: `https://image.tmdb.org/t/p/w342${movie.poster_path}`,
+ backdropUrl: `https://image.tmdb.org/t/p/original${movie.backdrop_path}`,
+ genres: movie.genre_ids.map((genreId) =>
+ GENRES.find((genre) => genre.id == genreId)
+ ),
+ title: movie.title,
+ releaseDate: movie.release_date,
+ year: movie.release_date.split("-")[0],
+ averageVote: movie.vote_average,
+ voteCount: movie.vote_count,
+ popularity: movie.popularity,
+ }))
+ )
+ }
+
+ run()
+ }, [page, debouncedSearch])
return (
diff --git a/src/pages/Movie.jsx b/src/pages/Movie.jsx
index 34fd4d1..ec3de73 100644
--- a/src/pages/Movie.jsx
+++ b/src/pages/Movie.jsx
@@ -1,37 +1,107 @@
import { useEffect, useState } from "react"
import { useParams } from "react-router-dom"
-import { useMovies } from "contexts/MoviesContext"
+import styles from "styles/Movie.module.css"
+import config from "config"
const Movie = () => {
- const [movie, setMovie] = useState()
- const [movies] = useMovies()
const { movieId } = useParams()
+ const [movie, setMovie] = useState()
+ const [cast, setCast] = useState()
- useEffect(
- () => setMovie(movies.find((movie) => movie.id === parseInt(movieId))),
- [movieId, movies]
- )
+ useEffect(() => {
+ const run = async () => {
+ const response = await fetch(
+ `https://api.themoviedb.org/3/movie/${movieId}?api_key=${config.apiKey}`
+ )
+ const data = await response.json()
+ setMovie({
+ id: data.id,
+ overview: data.overview,
+ adult: data.adult,
+ posterUrl: `https://image.tmdb.org/t/p/w342${data.poster_path}`,
+ backdropUrl: `https://image.tmdb.org/t/p/original${data.backdrop_path}`,
+ genres: data.genres.map((genre) => genre.name),
+ title: data.title,
+ releaseDate: data.release_date,
+ year: data.release_date.split("-")[0],
+ averageVote: data.vote_average,
+ voteCount: data.vote_count,
+ popularity: data.popularity,
+ tagline: data.tagline,
+ })
+ }
+ run()
+ }, [movieId])
- return (
-
-

-
-
{movie?.title}
-
- {movie?.averageVote}{" "}
-
-
+ useEffect(() => {
+ const run = async () => {
+ const response = await fetch(
+ `https://api.themoviedb.org/3/movie/${movieId}/credits?api_key=${config.apiKey}`
+ )
+ const data = await response.json()
+ setCast(data.cast)
+ }
+ run()
+ }, [movieId])
+
+ return movie ? (
+
+
+
+
+ {movie.title} - {movie.year}
+
+
{movie.tagline}
+
{movie.overview}
+
+
+
+
+ {movie.genres.map((genre) => (
+
{genre}
+ ))}
+
+ {movie.averageVote}
+
+
+
+
+
+
Actors
+
+ {cast?.map((actor) => (
+
+ {actor.profile_path ? (
+

+ ) : (
+
Image Unavailable
+ )}
+
+
{actor.name}
+
+ ))}
+
+
+ ) : (
+
)
}
diff --git a/src/styles/Card.module.css b/src/styles/Card.module.css
index 19b888c..5175c7d 100644
--- a/src/styles/Card.module.css
+++ b/src/styles/Card.module.css
@@ -21,6 +21,15 @@
flex-direction: column;
}
+.Overview {
+ text-overflow: ellipsis;
+ overflow: hidden;
+ display: -webkit-box !important;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ white-space: normal;
+}
+
.Title,
.Average {
margin: 0;
diff --git a/src/styles/Home.module.css b/src/styles/Home.module.css
index 75f6177..5c9bdc6 100644
--- a/src/styles/Home.module.css
+++ b/src/styles/Home.module.css
@@ -2,4 +2,5 @@
display: flex;
align-items: center;
flex-direction: column;
+ gap: 1.5em;
}
diff --git a/src/styles/Movie.module.css b/src/styles/Movie.module.css
new file mode 100644
index 0000000..32c3e37
--- /dev/null
+++ b/src/styles/Movie.module.css
@@ -0,0 +1,58 @@
+.Container {
+ color: white;
+}
+
+.Top {
+ height: 100vh;
+ display: flex;
+
+ background-size: cover;
+ background-position: center;
+ background-repeat: no-repeat;
+ flex-direction: column;
+ justify-content: flex-end;
+}
+
+.Summary {
+ background: linear-gradient(#00000035, black);
+ height: 15%;
+ text-align: center;
+}
+
+.Bottom {
+ background-color: black;
+ height: 100vh;
+ display: flex;
+ padding: 20px 40px;
+ flex-direction: column;
+}
+
+.Section div {
+ margin-left: 10px;
+}
+
+.Actors {
+ display: flex;
+ overflow: scroll;
+ align-items: start;
+}
+
+.Actors > * {
+ text-align: center;
+}
+
+.Tags {
+ display: flex;
+ gap: 10px;
+}
+
+.Tags > * {
+ background-color: var(--primary);
+ padding: 5px 7px;
+ border-radius: 10px;
+}
+
+.Average {
+ display: flex;
+ gap: 5px;
+}
diff --git a/src/styles/TopBar.module.css b/src/styles/TopBar.module.css
new file mode 100644
index 0000000..57dd76d
--- /dev/null
+++ b/src/styles/TopBar.module.css
@@ -0,0 +1,21 @@
+.Container {
+ display: flex;
+ width: 100%;
+ flex-direction: column;
+ align-items: center;
+}
+
+.Search {
+ padding: 0.5em;
+ border: 2px solid white;
+ color: white;
+ font: inherit;
+ width: 20em;
+ height: 3em;
+ border-radius: 10px;
+ background-color: var(--secondary);
+}
+
+.Title {
+ color: white;
+}
diff --git a/vite.config.js b/vite.config.js
index 707b980..a3b705d 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -10,7 +10,6 @@ export default defineConfig({
styles: path.resolve(__dirname, "/src/styles"),
components: path.resolve(__dirname, "/src/components"),
hooks: path.resolve(__dirname, "/src/hooks"),
- contexts: path.resolve(__dirname, "/src/contexts"),
pages: path.resolve(__dirname, "/src/pages"),
},
},