diff --git a/package-lock.json b/package-lock.json index 9b4dbf7..7641a5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "prop-types": "^15.8.1", "react": "^18.2.0", "react-dom": "^18.2.0" }, @@ -1581,6 +1582,14 @@ "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", "dev": true }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ordered-binary": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.1.tgz", @@ -1615,6 +1624,16 @@ "node": ">= 0.6.0" } }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, "node_modules/react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", @@ -1638,6 +1657,11 @@ "react": "^18.2.0" } }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", diff --git a/package.json b/package.json index ffcb0c2..48071b1 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "license": "ISC", "dependencies": { "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "prop-types": "^15.8.1" }, "devDependencies": { "@parcel/transformer-sass": "^2.12.0", diff --git a/src/components/main-view/main-view.jsx b/src/components/main-view/main-view.jsx index 5f3a89d..acc443a 100644 --- a/src/components/main-view/main-view.jsx +++ b/src/components/main-view/main-view.jsx @@ -1,60 +1,61 @@ -import { useState } from "react"; +import { useState, useEffect } from "react"; import { MovieCard } from "../movie-card/movie-card"; import { MovieView } from "../movie-view/movie-view"; export const MainView = () => { - const [movies, setMovies] = useState([ - { - id: 1, - title: "Fight Club", - description: "An insomniac office worker and a devil-may-care soap maker form an underground fight club that evolves...", - genre: { name: "Drama" }, - director: { name: "David Fincher" }, - image: - "https://upload.wikimedia.org/wikipedia/en/f/fc/Fight_Club_poster.jpg", - }, - { - id: 2, - title: "Schindler's List", - description: "In German-occupied Poland during World War II, industrialist Oskar Schindler gradually becomes concerned...", - genre: { name: "Biography" }, - director: { name: "Steven Spielberg" }, - image: - "https://upload.wikimedia.org/wikipedia/en/3/38/Schindler%27s_List_movie.jpg", - }, - { - id: 3, - title: "The Shawshank Redemption", - description: "Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common...", - genre: { name: "Drama" }, - director: { name: "Frank Darabont" }, - image: - "https://upload.wikimedia.org/wikipedia/en/8/81/ShawshankRedemptionMoviePoster.jpg", - }, - { - id: 4, - title: "The Dark Knight", - description: "When the menace known as the Joker wreaks havoc and chaos on the people of Gotham, Batman must accept...", - genre: { name: "Action" }, - director: { name: "Christopher Nolan" }, - image: - "https://upload.wikimedia.org/wikipedia/en/1/1c/The_Dark_Knight_%282008_film%29.jpg", - }, - { - id: 5, - title: "The Matrix", - description: "A computer hacker learns from mysterious rebels about the true nature of his reality and his role in the war...", - genre: { name: "Sci-Fi" }, - director: { name: "Lana Wachowski" }, - image: - "https://upload.wikimedia.org/wikipedia/en/c/c1/The_Matrix_Poster.jpg", - } - ]); - + const [movies, setMovies] = useState([]); const [selectedMovie, setSelectedMovie] = useState(null); + useEffect(() => { + fetch("https://cf-2-movie-api.onrender.com/movies") + .then((response) => response.json()) + .then(({ data }) => { + // Please review the response format of the API here + // https://cf-2-movie-api.onrender.com/docs/#/Movie/get_movies + const moviesFromApi = data.map(movie => { + return { + id: movie._id, + Title: movie.Title, + Description: movie.Description, + ImagePath: movie.ImagePath, + Featured: movie.Featured, + ReleaseYear: movie.ReleaseYear, + MPA: movie.MPA, + IMDb: movie.IMDb, + Genre: movie.Genre, + Director: movie.Director, + Actors: movie.Actors, + } + }); + + setMovies(moviesFromApi); + }); + }, []); + if (selectedMovie) { - return setSelectedMovie(null)} /> + // Bonus Task 2: Similar Movies + const similarMovies = movies.filter(movie => { + const isSimilarMovie = movie.Genre.Name === selectedMovie.Genre.Name; + const isNotTheSelectedMovie = movie.id !== selectedMovie.id; + return isNotTheSelectedMovie && isSimilarMovie; + }); + + return ( + <> + setSelectedMovie(null)} /> +
+

Similar Movies

+ {similarMovies.map(movie => ( + { + setSelectedMovie(newSelectedMovie); + }} + /> + ))} + + ); } if (movies.length === 0) { diff --git a/src/components/movie-card/movie-card.jsx b/src/components/movie-card/movie-card.jsx index fa5cc66..fd5107d 100644 --- a/src/components/movie-card/movie-card.jsx +++ b/src/components/movie-card/movie-card.jsx @@ -1,3 +1,5 @@ +import PropTypes from "prop-types"; + export const MovieCard = ({ movie, onMovieClick }) => { return (
{ onMovieClick(movie); }} > - {movie.title} + {movie.Title}
); }; + +MovieCard.propTypes = { + movie: PropTypes.shape({ + Title: PropTypes.string + }).isRequired, + onMovieClick: PropTypes.func.isRequired +}; diff --git a/src/components/movie-view/movie-view.jsx b/src/components/movie-view/movie-view.jsx index 3c91b5d..46789a6 100644 --- a/src/components/movie-view/movie-view.jsx +++ b/src/components/movie-view/movie-view.jsx @@ -1,26 +1,71 @@ +import PropTypes from "prop-types"; + export const MovieView = ({ movie, onBackClick }) => { return (
- +
Title: - {movie.title} + {movie.Title}
Description: - {movie.description} + {movie.Description}
Genre: - {movie.genre.name} + {movie.Genre.Name}
Director: - {movie.director.name} + {movie.Director.Name} +
+
+ Release Year: + {movie.ReleaseYear} +
+
+ MPA: + {movie.MPA}  + (Motion Picture Association rating) +
+
+ Rating: + {movie.IMDb}  + (IMDb rating)
); }; + +MovieView.propTypes = { + movie: PropTypes.shape({ + id: PropTypes.string.isRequired, + Title: PropTypes.string.isRequired, + Description: PropTypes.string.isRequired, + ImagePath: PropTypes.string.isRequired, + ReleaseYear: PropTypes.number, + MPA: PropTypes.string, + IMDb: PropTypes.number, + Genre: PropTypes.shape({ + Name: PropTypes.string.isRequired, + Description: PropTypes.string.isRequired + }).isRequired, + Director: PropTypes.shape({ + Name: PropTypes.string.isRequired, + Bio: PropTypes.string.isRequired, + Birth: PropTypes.string, + Death: PropTypes.string, + }), + Actors: PropTypes.arrayOf(PropTypes.shape({ + Name: PropTypes.string.isRequired, + Bio: PropTypes.string.isRequired, + Birthday: PropTypes.string, + ImagePath: PropTypes.string.isRequired + })) + }).isRequired, + onBackClick: PropTypes.func.isRequired +};