mirror of
https://github.com/Nezumi-2711/react-training.git
synced 2026-09-22 20:01:59 +00:00
Update sample code
This commit is contained in:
@@ -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>
|
||||||
<WatchedSummary watched={watched} />
|
{selectedId ? (
|
||||||
<WatchMovieList watched={watched} />
|
<MovieDetails
|
||||||
|
selectedId={selectedId}
|
||||||
|
onCloseMovie={handleCloseMovie}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<WatchedSummary 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}>
|
||||||
|
←
|
||||||
|
</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));
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user