Added rating system
This commit is contained in:
parent
18c6684fb2
commit
e9cb1d9d54
6 changed files with 101 additions and 20 deletions
38
src/components/Rate.jsx
Normal file
38
src/components/Rate.jsx
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import { useState } from "react"
|
||||||
|
import styles from "styles/Rate.module.css"
|
||||||
|
|
||||||
|
const Rate = ({ rating, setRating }) => {
|
||||||
|
const [hover, setHover] = useState()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{[...Array(5)].map((_, index) => {
|
||||||
|
index++
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
key={index}
|
||||||
|
className={`${styles.Star} ${
|
||||||
|
index <= (hover || rating) ? styles.On : styles.Off
|
||||||
|
}`}
|
||||||
|
onClick={() => setRating(index)}
|
||||||
|
onMouseEnter={() => setHover(index)}
|
||||||
|
onMouseLeave={() => setHover()}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="30"
|
||||||
|
height="30"
|
||||||
|
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>
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Rate
|
30
src/hooks/useLocalStorage.jsx
Normal file
30
src/hooks/useLocalStorage.jsx
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import { useEffect, useState } from "react"
|
||||||
|
|
||||||
|
const useLocalStorage = (key, defaultValue) => {
|
||||||
|
const [storedValue, setStoredValue] = useState(() => {
|
||||||
|
try {
|
||||||
|
const value = window.localStorage.getItem(key)
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
return JSON.parse(value)
|
||||||
|
} else {
|
||||||
|
window.localStorage.setItem(key, JSON.stringify(defaultValue))
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
try {
|
||||||
|
window.localStorage.setItem(key, JSON.stringify(storedValue))
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
|
}, [storedValue])
|
||||||
|
|
||||||
|
return [storedValue, setStoredValue]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useLocalStorage
|
|
@ -3,7 +3,6 @@ import config from "config"
|
||||||
import styles from "styles/Actor.module.css"
|
import styles from "styles/Actor.module.css"
|
||||||
import { Link, useParams } from "react-router-dom"
|
import { Link, useParams } from "react-router-dom"
|
||||||
import { GENRES } from "../constants"
|
import { GENRES } from "../constants"
|
||||||
import Card from "components/Card"
|
|
||||||
|
|
||||||
const Actor = () => {
|
const Actor = () => {
|
||||||
const { actorId } = useParams()
|
const { actorId } = useParams()
|
||||||
|
|
|
@ -2,11 +2,21 @@ import { useEffect, useState } from "react"
|
||||||
import { Link, useParams } from "react-router-dom"
|
import { Link, useParams } from "react-router-dom"
|
||||||
import styles from "styles/Movie.module.css"
|
import styles from "styles/Movie.module.css"
|
||||||
import config from "config"
|
import config from "config"
|
||||||
|
import useLocalStorage from "hooks/useLocalStorage"
|
||||||
|
import Rate from "components/Rate"
|
||||||
|
|
||||||
const Movie = () => {
|
const Movie = () => {
|
||||||
const { movieId } = useParams()
|
const { movieId } = useParams()
|
||||||
const [movie, setMovie] = useState()
|
const [movie, setMovie] = useState()
|
||||||
const [cast, setCast] = useState()
|
const [cast, setCast] = useState()
|
||||||
|
const [ratings, setRatings] = useLocalStorage("ratings", [])
|
||||||
|
const rating = ratings.find(({ id }) => id == movieId)?.rating
|
||||||
|
|
||||||
|
const setRating = (rating) =>
|
||||||
|
setRatings((currentRatings) => [
|
||||||
|
...currentRatings.filter(({ id }) => id != movieId),
|
||||||
|
{ ...movie, rating },
|
||||||
|
])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const run = async () => {
|
const run = async () => {
|
||||||
|
@ -63,7 +73,7 @@ const Movie = () => {
|
||||||
<div className={styles.Bottom}>
|
<div className={styles.Bottom}>
|
||||||
<div className={styles.Tags}>
|
<div className={styles.Tags}>
|
||||||
{movie.genres.map((genre) => (
|
{movie.genres.map((genre) => (
|
||||||
<p>{genre}</p>
|
<p key={genre}>{genre}</p>
|
||||||
))}
|
))}
|
||||||
<p className={styles.Average}>
|
<p className={styles.Average}>
|
||||||
<span>
|
<span>
|
||||||
|
@ -79,25 +89,11 @@ 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" />
|
<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>
|
</svg>
|
||||||
</p>
|
</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>
|
||||||
<div className={styles.Section}></div>
|
<div className={styles.Section}>
|
||||||
|
<h1 className={styles.Header}>Your Rating</h1>
|
||||||
|
<Rate rating={rating} setRating={setRating} />
|
||||||
|
</div>
|
||||||
<div className={styles.Section}>
|
<div className={styles.Section}>
|
||||||
<h1 className={styles.Header}>Actors</h1>
|
<h1 className={styles.Header}>Actors</h1>
|
||||||
<div className={styles.Actors}>
|
<div className={styles.Actors}>
|
||||||
|
|
|
@ -62,3 +62,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Rate {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
14
src/styles/Rate.module.css
Normal file
14
src/styles/Rate.module.css
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
.Star {
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Off {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.On {
|
||||||
|
color: gold;
|
||||||
|
}
|
Reference in a new issue