Latest changes

This commit is contained in:
“Henry-Hiles” 2022-10-31 10:56:38 -04:00
parent c66526241c
commit 18c6684fb2
10 changed files with 265 additions and 29 deletions

View file

@ -2,12 +2,14 @@ import { Routes, Route } from "react-router-dom"
import "./App.css"
import Home from "pages/Home"
import Movie from "pages/Movie"
import Actor from "pages/Actor"
const App = () => (
<div className="App">
<Routes>
<Route index element={<Home />} />
<Route path="/movie/:movieId" element={<Movie />} />
<Route path="/actor/:actorId" element={<Actor />} />
<Route path="*" element={<h1>404 - Not Found</h1>} />
</Routes>
</div>

View file

@ -1,12 +1,12 @@
import Card from "components/Card"
import styles from "styles/CardList.module.css"
import Card from "components/Card";
import styles from "styles/CardList.module.css";
const CardList = ({ movies }) => (
<div className={styles.CardList}>
{movies.map((movie) => (
<Card key={movie.id} movie={movie} />
))}
</div>
)
<div className={styles.CardList}>
{movies?.map((movie) => (
<Card key={movie.id} movie={movie} />
))}
</div>
);
export default CardList
export default CardList;

125
src/pages/Actor.jsx Normal file
View file

@ -0,0 +1,125 @@
import { useEffect, useState } from "react"
import config from "config"
import styles from "styles/Actor.module.css"
import { Link, useParams } from "react-router-dom"
import { GENRES } from "../constants"
import Card from "components/Card"
const Actor = () => {
const { actorId } = useParams()
const [actor, setActor] = useState()
const [images, setImages] = useState()
const [collapsed, setCollapsed] = useState(true)
const [credits, setCredits] = useState()
useEffect(() => {
const run = async () => {
const response = await fetch(
`https://api.themoviedb.org/3/person/${actorId}?api_key=${config.apiKey}`
)
const data = await response.json()
setActor(data)
}
run()
}, [actorId])
useEffect(() => {
const run = async () => {
const response = await fetch(
`https://api.themoviedb.org/3/person/${actorId}/images?api_key=${config.apiKey}`
)
const data = await response.json()
setImages(data)
}
run()
}, [actorId])
useEffect(() => {
const run = async () => {
const response = await fetch(
`https://api.themoviedb.org/3/person/${actorId}/movie_credits?api_key=${config.apiKey}`
)
const data = await response.json()
setCredits(
data.cast.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()
}, [actorId])
return (
<div className={styles.Container}>
<h1>{actor?.name}</h1>
<div className={styles.Section}>
<h2>Biography</h2>
<div className={styles.Description}>
{actor?.biography ? (
<a
href="#"
className={styles.Collapse}
onClick={() =>
setCollapsed((collapsed) => !collapsed)
}
>
<p className={collapsed ? styles.Collapsed : ""}>
{actor.biography}
</p>
<p className={styles.ReadMore}>
{collapsed ? "Read More" : "Read Less"}
</p>
<p>{collapsed}</p>
</a>
) : (
<p>No biography available.</p>
)}
</div>
</div>
<div className={styles.Section}>
<h2>Images</h2>
<div className={styles.Images}>
{images?.profiles.map((image) => (
<img
key={image.file_path}
className={styles.Image}
src={`https://image.tmdb.org/t/p/w300${image.file_path}`}
/>
))}
</div>
</div>
<div className={styles.Section}>
<h2>Movies</h2>
<div className={styles.Credits}>
{credits?.map((movie) => (
<Link
to={`/movie/${movie.id}`}
key={movie.id}
className={styles.Movie}
>
<img src={movie.posterUrl} />
<span>{movie.title}</span>
</Link>
))}
</div>
</div>
</div>
)
}
export default Actor

View file

@ -1,10 +1,10 @@
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"
import Card from "components/Card"
const Home = () => {
const [movies, setMovies] = useState([])
@ -48,7 +48,11 @@ const Home = () => {
return (
<div className={styles.Container}>
<TopBar search={search} setSearch={setSearch} />
<CardList movies={movies} />
<div className={styles.CardList}>
{movies?.map((movie) => (
<Card key={movie.id} movie={movie} />
))}
</div>
</div>
)
}

View file

@ -1,5 +1,5 @@
import { useEffect, useState } from "react"
import { useParams } from "react-router-dom"
import { Link, useParams } from "react-router-dom"
import styles from "styles/Movie.module.css"
import config from "config"
@ -66,7 +66,9 @@ const Movie = () => {
<p>{genre}</p>
))}
<p className={styles.Average}>
{movie.averageVote}
<span>
Average Rating: {movie.averageVote.toFixed(1)}
</span>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
@ -77,13 +79,34 @@ const Movie = () => {
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z" />
</svg>
</p>
{false ? (
<p className={styles.Average}>
<span>Average Rating: {movie.averageVote}</span>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
fill="currentColor"
viewBox="0 0 16 16"
>
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z" />
</svg>
</p>
) : (
<p>Rate this movie</p>
)}
</div>
<div className={styles.Section}></div>
<div className={styles.Section}>
<h1 className={styles.Header}>Actors</h1>
<div className={styles.Actors}>
{cast?.map((actor) => (
<div key={actor.id}>
<Link
key={actor.id}
to={`/actor/${actor.id}`}
className={styles.Actor}
>
{actor.profile_path ? (
<img
src={`https://image.tmdb.org/t/p/w200${actor.profile_path}`}
@ -94,7 +117,7 @@ const Movie = () => {
)}
<h3>{actor.name}</h3>
</div>
</Link>
))}
</div>
</div>

View file

@ -0,0 +1,64 @@
.Container {
display: flex;
flex-direction: column;
padding: 15px;
color: white;
}
.Images {
display: flex;
overflow: scroll;
align-items: start;
gap: 15px;
height: 200px;
}
.Image {
height: 100%;
}
.Section div {
margin-left: 10px;
}
.Collapsed {
-webkit-line-clamp: 5;
-webkit-box-orient: vertical;
display: -webkit-box;
overflow: hidden;
text-overflow: ellipsis;
overflow-wrap: break-word;
}
.Collapse {
color: white;
}
.Credits {
display: flex;
width: 100%;
gap: 20px;
height: 500px;
overflow: scroll;
}
.ReadMore {
text-decoration: underline;
}
.Movie {
display: flex;
flex-direction: column;
text-decoration: none;
color: white;
align-items: center;
gap: 5px;
}
.Movie:hover {
text-decoration: underline;
}
.Movie img {
height: 300px;
}

View file

@ -18,6 +18,8 @@
border-radius: 7px;
display: flex;
gap: 5px;
width: 100%;
height: 100%;
flex-direction: column;
}

View file

@ -4,3 +4,13 @@
flex-direction: column;
gap: 1.5em;
}
.CardList {
display: grid;
justify-items: center;
width: 85%;
margin: 0 100px;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
text-align: center;
}

View file

@ -35,10 +35,16 @@
display: flex;
overflow: scroll;
align-items: start;
gap: 15px;
}
.Actors > * {
.Actor {
text-align: center;
color: white;
}
.Actor:not(:hover) {
text-decoration: none;
}
.Tags {

View file

@ -1,16 +1,16 @@
import { defineConfig } from "vite"
import react from "@vitejs/plugin-react"
import path from "path"
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import path from "path";
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
config: path.resolve(__dirname, "/src/config.json"),
styles: path.resolve(__dirname, "/src/styles"),
components: path.resolve(__dirname, "/src/components"),
hooks: path.resolve(__dirname, "/src/hooks"),
pages: path.resolve(__dirname, "/src/pages"),
},
plugins: [react()],
resolve: {
alias: {
config: path.resolve(__dirname, "/src/config.json"),
styles: path.resolve(__dirname, "/src/styles"),
components: path.resolve(__dirname, "/src/components"),
hooks: path.resolve(__dirname, "/src/hooks"),
pages: path.resolve(__dirname, "/src/pages"),
},
})
},
});