Update sample code

This commit is contained in:
2023-10-11 17:35:56 +07:00
parent 002e357532
commit db56b62030
4 changed files with 116 additions and 82 deletions
+91 -58
View File
@@ -1,80 +1,103 @@
import { useEffect } from "react";
import { useState } from "react"; import { useState } from "react";
const tempMovieData = [
{
imdbID: "tt1375666",
Title: "Inception",
Year: "2010",
Poster:
"https://m.media-amazon.com/images/M/MV5BMjAxMzY3NjcxNF5BMl5BanBnXkFtZTcwNTI5OTM0Mw@@._V1_SX300.jpg",
},
{
imdbID: "tt0133093",
Title: "The Matrix",
Year: "1999",
Poster:
"https://m.media-amazon.com/images/M/MV5BNzQzOTk3OTAtNDQ0Zi00ZTVkLWI0MTEtMDllZjNkYzNjNTc4L2ltYWdlXkEyXkFqcGdeQXVyNjU0OTQ0OTY@._V1_SX300.jpg",
},
{
imdbID: "tt6751668",
Title: "Parasite",
Year: "2019",
Poster:
"https://m.media-amazon.com/images/M/MV5BYWZjMjk3ZTItODQ2ZC00NTY5LWE0ZDYtZTI3MjcwN2Q5NTVkXkEyXkFqcGdeQXVyODk4OTc3MTY@._V1_SX300.jpg",
},
];
const tempWatchedData = [
{
imdbID: "tt1375666",
Title: "Inception",
Year: "2010",
Poster:
"https://m.media-amazon.com/images/M/MV5BMjAxMzY3NjcxNF5BMl5BanBnXkFtZTcwNTI5OTM0Mw@@._V1_SX300.jpg",
runtime: 148,
imdbRating: 8.8,
userRating: 10,
},
{
imdbID: "tt0088763",
Title: "Back to the Future",
Year: "1985",
Poster:
"https://m.media-amazon.com/images/M/MV5BZmU0M2Y1OGUtZjIxNi00ZjBkLTg1MjgtOWIyNThiZWIwYjRiXkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SX300.jpg",
runtime: 116,
imdbRating: 8.5,
userRating: 9,
},
];
const average = (arr) => const average = (arr) =>
arr.reduce((acc, cur, i, arr) => acc + cur / arr.length, 0); arr.reduce((acc, cur, i, arr) => acc + cur / arr.length, 0);
const KEY = "68ff4a55";
const BASE_URL = "http://www.omdbapi.com/";
export default function App() { export default function App() {
const [movies, setMovies] = useState(tempMovieData); const [query, setQuery] = useState("");
const [watched, setWatched] = useState(tempWatchedData); const [movies, setMovies] = useState([]);
const [watched, setWatched] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState("");
const [selectedId, setSelectedId] = useState(null);
const handleSelectMovie = (id) => {
setSelectedId((selectedId) => (id === selectedId ? null : id));
};
const handleCloseMovie = () => {
setSelectedId(null);
};
useEffect(() => {
const fetchMovies = async () => {
try {
setIsLoading(true);
setError("");
const res = await fetch(BASE_URL + `?apikey=${KEY}&s=${query}`);
if (!res.ok)
throw new Error("Something went wrong with fetching movies");
const data = await res.json();
if (data.Response === "False") throw new Error("Movie not found!");
setMovies(data.Search);
} catch (err) {
setError(err.message);
} finally {
setIsLoading(false);
}
};
if (query.length < 3) {
setMovies([]);
setError("");
return;
}
fetchMovies();
}, [query]);
return ( return (
<> <>
<NavBar> <NavBar>
<Search /> <Search query={query} setQuery={setQuery} />
<NumResults movies={movies} /> <NumResults movies={movies} />
</NavBar> </NavBar>
<Main> <Main>
<Box> <Box>
<MovieList movies={movies} /> {/* {isLoading ? <Loader /> : <MovieList movies={movies} />} */}
{isLoading && <Loader />}
{!isLoading && !error && (
<MovieList movies={movies} onSelectMovie={handleSelectMovie} />
)}
{error && <ErrorMessage message={error} />}
</Box> </Box>
<Box> <Box>
{selectedId ? (
<MovieDetails
selectedId={selectedId}
onCloseMovie={handleCloseMovie}
/>
) : (
<>
<WatchedSummary watched={watched} /> <WatchedSummary watched={watched} />
<WatchMovieList watched={watched} /> <WatchMovieList watched={watched} />
</>
)}
</Box> </Box>
</Main> </Main>
</> </>
); );
} }
function Loader() {
return <p className="loader">Loading...</p>;
}
function ErrorMessage({ message }) {
return <p className="error">{message}</p>;
}
function NavBar({ children }) { function NavBar({ children }) {
return ( return (
<nav className="nav-bar"> <nav className="nav-bar">
@@ -93,8 +116,7 @@ function Logo() {
); );
} }
function Search() { function Search({ query, setQuery }) {
const [query, setQuery] = useState("");
return ( return (
<input <input
className="search" className="search"
@@ -153,19 +175,19 @@ function Box({ children }) {
// ); // );
// } // }
function MovieList({ movies }) { function MovieList({ movies, onSelectMovie }) {
return ( return (
<ul className="list"> <ul className="list list-movies">
{movies?.map((movie) => ( {movies?.map((movie) => (
<Movie movie={movie} key={movie.imdbID} /> <Movie movie={movie} key={movie.imdbID} onSelectMovie={onSelectMovie} />
))} ))}
</ul> </ul>
); );
} }
function Movie({ movie }) { function Movie({ movie, onSelectMovie }) {
return ( return (
<li key={movie.imdbID}> <li key={movie.imdbID} onClick={() => onSelectMovie(movie.imdbID)}>
<img src={movie.Poster} alt={`${movie.Title} poster`} /> <img src={movie.Poster} alt={`${movie.Title} poster`} />
<h3>{movie.Title}</h3> <h3>{movie.Title}</h3>
<div> <div>
@@ -178,6 +200,17 @@ function Movie({ movie }) {
); );
} }
function MovieDetails({ selectedId, onCloseMovie }) {
return (
<div className="details">
<button className="btn-back" onClick={onCloseMovie}>
&larr;
</button>
{selectedId}
</div>
);
}
function WatchedSummary({ watched }) { function WatchedSummary({ watched }) {
const avgImdbRating = average(watched.map((movie) => movie.imdbRating)); const avgImdbRating = average(watched.map((movie) => movie.imdbRating));
const avgUserRating = average(watched.map((movie) => movie.userRating)); const avgUserRating = average(watched.map((movie) => movie.userRating));
+11
View File
@@ -10,6 +10,17 @@ const containerStyle = {
const starContainerStyle = { const starContainerStyle = {
display: "flex", display: "flex",
}; };
StarRating.propTypes = {
maxRating: PropTypes.number,
defaultRating: PropTypes.number,
color: PropTypes.string,
size: PropTypes.number,
messages: PropTypes.array,
className: PropTypes.string,
onSetRating: PropTypes.func,
};
export default function StarRating({ export default function StarRating({
maxRating = 5, maxRating = 5,
color = "#fcc419", color = "#fcc419",
+10 -2
View File
@@ -54,8 +54,12 @@ body {
max-width: 42rem; max-width: 42rem;
background-color: var(--color-background-500); background-color: var(--color-background-500);
border-radius: 0.9rem; border-radius: 0.9rem;
/* overflow: scroll; */
position: relative; position: relative;
overflow: scroll;
}
.box::-webkit-scrollbar {
display: none;
} }
.loader { .loader {
@@ -138,7 +142,11 @@ body {
.list { .list {
list-style: none; list-style: none;
padding: 0.8rem 0; padding: 0.8rem 0;
/* overflow: scroll; */ overflow: scroll;
}
.list::-webkit-scrollbar {
display: none;
} }
.list-watched { .list-watched {
+2 -20
View File
@@ -1,28 +1,10 @@
import React from "react"; import React from "react";
import ReactDOM from "react-dom/client"; import ReactDOM from "react-dom/client";
import App from "./App.jsx"; import App from "./App.jsx";
// import "./index.css"; import "./index.css";
import StarRating from "./StarRating.jsx";
import { useState } from "react";
function Test() {
const [movieRating, setMovieRating] = useState(0);
return (
<div>
<StarRating color="blue" maxRating={10} />
<p>The move was rated {movieRating} stars</p>
</div>
);
}
ReactDOM.createRoot(document.getElementById("root")).render( ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode> <React.StrictMode>
{/* <App /> */} <App />
<StarRating
maxRating={5}
messages={["Terrible", "Bad", "Okay", "Good", "Amazing"]}
/>
<StarRating size={24} color="red" className="test" defaultRating={3} />
</React.StrictMode> </React.StrictMode>
); );