Added ratings page
This commit is contained in:
parent
e9cb1d9d54
commit
93c6bc7e80
16 changed files with 127 additions and 58 deletions
|
@ -1,15 +1,19 @@
|
|||
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"
|
||||
import Ratings from "pages/Ratings"
|
||||
import styles from "styles/App.module.css"
|
||||
import TopBar from "components/TopBar"
|
||||
|
||||
const App = () => (
|
||||
<div className="App">
|
||||
<div className={styles.App}>
|
||||
<TopBar />
|
||||
<Routes>
|
||||
<Route index element={<Home />} />
|
||||
<Route path="/movie/:movieId" element={<Movie />} />
|
||||
<Route path="/actor/:actorId" element={<Actor />} />
|
||||
<Route path="/ratings" element={<Ratings />} />
|
||||
<Route path="*" element={<h1>404 - Not Found</h1>} />
|
||||
</Routes>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { Link } from "react-router-dom"
|
||||
import styles from "styles/Card.module.css"
|
||||
import Rate from "./Rate"
|
||||
|
||||
const Card = ({ movie }) => (
|
||||
const Card = ({ movie, setRating }) => (
|
||||
<Link to={`/movie/${movie.id}`} className={styles.Link}>
|
||||
<div className={styles.Card}>
|
||||
<img
|
||||
|
@ -13,18 +14,22 @@ const Card = ({ movie }) => (
|
|||
<p className={styles.Title}>
|
||||
{movie.title} - {movie.year}
|
||||
</p>
|
||||
<p className={styles.Average}>
|
||||
{movie.averageVote}{" "}
|
||||
<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>
|
||||
{movie.rating ? (
|
||||
<Rate rating={movie.rating} setRating={setRating} />
|
||||
) : (
|
||||
<p className={styles.Average}>
|
||||
Average rating: {movie.averageVote}{" "}
|
||||
<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 className={styles.Overview}>{movie.overview}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
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>
|
||||
);
|
||||
|
||||
export default CardList;
|
|
@ -3,7 +3,6 @@ import styles from "styles/Rate.module.css"
|
|||
|
||||
const Rate = ({ rating, setRating }) => {
|
||||
const [hover, setHover] = useState()
|
||||
|
||||
return (
|
||||
<div>
|
||||
{[...Array(5)].map((_, index) => {
|
||||
|
@ -15,7 +14,10 @@ const Rate = ({ rating, setRating }) => {
|
|||
className={`${styles.Star} ${
|
||||
index <= (hover || rating) ? styles.On : styles.Off
|
||||
}`}
|
||||
onClick={() => setRating(index)}
|
||||
onClick={(event) => {
|
||||
event.preventDefault()
|
||||
setRating(index)
|
||||
}}
|
||||
onMouseEnter={() => setHover(index)}
|
||||
onMouseLeave={() => setHover()}
|
||||
>
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
import { Link } from "react-router-dom"
|
||||
import styles from "styles/TopBar.module.css"
|
||||
|
||||
const TopBar = ({ search, setSearch }) => (
|
||||
const TopBar = () => (
|
||||
<div className={styles.Container}>
|
||||
<h1 className={styles.Title}>React Movie Finder</h1>
|
||||
<input
|
||||
type="text"
|
||||
className={styles.Search}
|
||||
value={search}
|
||||
autoFocus
|
||||
placeholder="Search for movies..."
|
||||
onChange={({ target }) => setSearch(target.value)}
|
||||
/>
|
||||
<Link to="/">
|
||||
<h1 className={styles.Title}>React Movie Finder</h1>
|
||||
</Link>
|
||||
<Link to="/ratings">
|
||||
<h1>Your ratings</h1>
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ button {
|
|||
}
|
||||
|
||||
hr {
|
||||
width: 97%;
|
||||
width: 100%;
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,8 @@ const Actor = () => {
|
|||
|
||||
return (
|
||||
<div className={styles.Container}>
|
||||
<h1>{actor?.name}</h1>
|
||||
<hr />
|
||||
<h1 className={styles.Name}>{actor?.name}</h1>
|
||||
<div className={styles.Section}>
|
||||
<h2>Biography</h2>
|
||||
<div className={styles.Description}>
|
||||
|
|
|
@ -47,7 +47,14 @@ const Home = () => {
|
|||
|
||||
return (
|
||||
<div className={styles.Container}>
|
||||
<TopBar search={search} setSearch={setSearch} />
|
||||
<input
|
||||
type="text"
|
||||
className={styles.Search}
|
||||
value={search}
|
||||
autoFocus
|
||||
placeholder="Search for movies..."
|
||||
onChange={({ target }) => setSearch(target.value)}
|
||||
/>
|
||||
<div className={styles.CardList}>
|
||||
{movies?.map((movie) => (
|
||||
<Card key={movie.id} movie={movie} />
|
||||
|
|
|
@ -93,6 +93,10 @@ const Movie = () => {
|
|||
<div className={styles.Section}>
|
||||
<h1 className={styles.Header}>Your Rating</h1>
|
||||
<Rate rating={rating} setRating={setRating} />
|
||||
<br />
|
||||
<Link to="/ratings" className={styles.RatingsLink}>
|
||||
Go to ratings
|
||||
</Link>
|
||||
</div>
|
||||
<div className={styles.Section}>
|
||||
<h1 className={styles.Header}>Actors</h1>
|
||||
|
|
29
src/pages/Ratings.jsx
Normal file
29
src/pages/Ratings.jsx
Normal file
|
@ -0,0 +1,29 @@
|
|||
import Card from "components/Card"
|
||||
import useLocalStorage from "hooks/useLocalStorage"
|
||||
import styles from "styles/Ratings.module.css"
|
||||
|
||||
const Ratings = () => {
|
||||
const [ratings, setRatings] = useLocalStorage("ratings", [])
|
||||
const setRating = (rating, movie) =>
|
||||
setRatings((currentRatings) => [
|
||||
...currentRatings.filter(({ id }) => id != movie.id),
|
||||
{ ...movie, rating },
|
||||
])
|
||||
|
||||
return (
|
||||
<div className={styles.Container}>
|
||||
<hr />
|
||||
<div className={styles.CardList}>
|
||||
{ratings?.map((movie) => (
|
||||
<Card
|
||||
key={movie.id}
|
||||
movie={movie}
|
||||
setRating={(rating) => setRating(rating, movie)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Ratings
|
|
@ -3,6 +3,10 @@
|
|||
flex-direction: column;
|
||||
padding: 15px;
|
||||
color: white;
|
||||
padding-top: 80px;
|
||||
}
|
||||
.Name {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.Images {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
align-items: center;
|
||||
flex-direction: column;
|
||||
gap: 1.5em;
|
||||
padding-top: 30px;
|
||||
}
|
||||
|
||||
.CardList {
|
||||
|
@ -14,3 +15,14 @@
|
|||
gap: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.Search {
|
||||
padding: 0.5em;
|
||||
border: 2px solid white;
|
||||
color: white;
|
||||
font: inherit;
|
||||
width: 20em;
|
||||
height: 3em;
|
||||
border-radius: 10px;
|
||||
background-color: var(--secondary);
|
||||
}
|
||||
|
|
|
@ -66,3 +66,7 @@
|
|||
.Rate {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.RatingsLink {
|
||||
color: white;
|
||||
}
|
||||
|
|
19
src/styles/Ratings.module.css
Normal file
19
src/styles/Ratings.module.css
Normal file
|
@ -0,0 +1,19 @@
|
|||
.Container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
gap: 1.5em;
|
||||
color: white;
|
||||
padding: 10px;
|
||||
padding-top: 90px;
|
||||
}
|
||||
|
||||
.CardList {
|
||||
display: grid;
|
||||
justify-items: center;
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 300px));
|
||||
gap: 20px;
|
||||
text-align: center;
|
||||
}
|
|
@ -1,21 +1,13 @@
|
|||
.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 {
|
||||
justify-content: space-between;
|
||||
padding: 10px 20px;
|
||||
background-color: transparent;
|
||||
position: absolute;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.Container h1 {
|
||||
color: white;
|
||||
}
|
||||
|
|
Reference in a new issue