diff --git a/README.md b/README.md index 4c8fd7876..4c48fd690 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,11 @@ # Project Movies -Replace this readme with your own information about your project. - -Start by briefly describing the assignment in a sentence or two. Keep it short and to the point. +This weeks project was all about building multi-page applications using React Router. It was done through pair-programming by Matilda Frid and Johanna Leonsson. The task was to create a site where the user can scroll through the latest movie releases and select a movie to read more about. ## The problem -Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next? +We started out planning and creating the components we wanted to use. Then we made sure that we could fetch the correct data from the IMDB API and insert it into our components. Once we got all the basic functions to work, we continued with styling the different pages according to the styling proposal we had recieved before. ## View it live -Every project should be deployed somewhere. Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about. +https://johanna-matilda-project-movies.netlify.app/ \ No newline at end of file diff --git a/code/package-lock.json b/code/package-lock.json index bb51e893e..3fa72176e 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -16,7 +16,8 @@ "eslint-plugin-react": "^7.30.1", "eslint-plugin-react-hooks": "^4.6.0", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "react-router-dom": "^6.9.0" }, "devDependencies": { "react-scripts": "5.0.1" @@ -3124,6 +3125,14 @@ } } }, + "node_modules/@remix-run/router": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.4.0.tgz", + "integrity": "sha512-BJ9SxXux8zAg991UmT8slpwpsd31K1dHHbD3Ba4VzD+liLQ4WAMSxQp2d2ZPRPfN0jN2NPRowcSSoM7lCaF08Q==", + "engines": { + "node": ">=14" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -14384,6 +14393,36 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.9.0.tgz", + "integrity": "sha512-51lKevGNUHrt6kLuX3e/ihrXoXCa9ixY/nVWRLlob4r/l0f45x3SzBvYJe3ctleLUQQ5fVa4RGgJOTH7D9Umhw==", + "dependencies": { + "@remix-run/router": "1.4.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.9.0.tgz", + "integrity": "sha512-/seUAPY01VAuwkGyVBPCn1OXfVbaWGGu4QN9uj0kCPcTyNYgL1ldZpxZUpRU7BLheKQI4Twtl/OW2nHRF1u26Q==", + "dependencies": { + "@remix-run/router": "1.4.0", + "react-router": "6.9.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", @@ -19509,6 +19548,11 @@ "source-map": "^0.7.3" } }, + "@remix-run/router": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.4.0.tgz", + "integrity": "sha512-BJ9SxXux8zAg991UmT8slpwpsd31K1dHHbD3Ba4VzD+liLQ4WAMSxQp2d2ZPRPfN0jN2NPRowcSSoM7lCaF08Q==" + }, "@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -27684,6 +27728,23 @@ "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", "dev": true }, + "react-router": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.9.0.tgz", + "integrity": "sha512-51lKevGNUHrt6kLuX3e/ihrXoXCa9ixY/nVWRLlob4r/l0f45x3SzBvYJe3ctleLUQQ5fVa4RGgJOTH7D9Umhw==", + "requires": { + "@remix-run/router": "1.4.0" + } + }, + "react-router-dom": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.9.0.tgz", + "integrity": "sha512-/seUAPY01VAuwkGyVBPCn1OXfVbaWGGu4QN9uj0kCPcTyNYgL1ldZpxZUpRU7BLheKQI4Twtl/OW2nHRF1u26Q==", + "requires": { + "@remix-run/router": "1.4.0", + "react-router": "6.9.0" + } + }, "react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", diff --git a/code/package.json b/code/package.json index 7aad26ebc..9736b71ad 100644 --- a/code/package.json +++ b/code/package.json @@ -11,7 +11,8 @@ "eslint-plugin-react": "^7.30.1", "eslint-plugin-react-hooks": "^4.6.0", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "react-router-dom": "^6.9.0" }, "scripts": { "start": "react-scripts start", diff --git a/code/public/index.html b/code/public/index.html index e6730aa66..2d0f6213e 100644 --- a/code/public/index.html +++ b/code/public/index.html @@ -4,6 +4,12 @@ + + + + + + - Technigo React App + Movie Releases diff --git a/code/src/App.js b/code/src/App.js index f2007d229..994c04df2 100644 --- a/code/src/App.js +++ b/code/src/App.js @@ -1,9 +1,34 @@ import React from 'react'; +// eslint-disable-next-line no-unused-vars +import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'; +import MovieList from './components/MovieList'; +import MovieDetails from './components/MovieDetails'; + +// https://api.themoviedb.org/3/movie/popular?api_key=7e62f4c867db459871fea2a9a052cb08&language=en-US&page=1 export const App = () => { + // const [loading, setLoading] = useState(false); + // const [list, setList] = useState([]); + // const API_KEY = '7e62f4c867db459871fea2a9a052cb08'; + // console.log(list) + return ( -
- Find me in src/app.js! -
+ + + } /> + } /> + + ); } + +/* + return ( + + + } /> + } /> + + + ); + */ \ No newline at end of file diff --git a/code/src/components/Footer.css b/code/src/components/Footer.css new file mode 100644 index 000000000..1dbbb29bc --- /dev/null +++ b/code/src/components/Footer.css @@ -0,0 +1,43 @@ + + +.foot-container { + display: flex; + flex-direction: column; + align-items: center; + margin: 0 auto; + padding-top: 20px; + padding-bottom: 30px; + } + + .icon-link { + color: red; + font-size: 30px; + padding: 0 20px 0 20px; + } + + .icon-link :hover { + color: white; + } + + .byFoot { + font-family: "Courier New"; + font-size: 16px; + color: white; + margin: 10px auto 14px auto; + max-width: 80%; + text-align: center; + } + + + @media (min-width: 820px) { + + .icon-link { + font-size: 43px; + } + + .byFoot { + font-size: 22px; + } + } + + diff --git a/code/src/components/Footer.js b/code/src/components/Footer.js new file mode 100644 index 000000000..83d68ec1f --- /dev/null +++ b/code/src/components/Footer.js @@ -0,0 +1,29 @@ +import React from 'react'; + +const Footer = () => { + return ( +
+
+ + + + + + +
+

Created by Matilda Frid & Johanna Leonsson

+
+ ) +} + +export default Footer; \ No newline at end of file diff --git a/code/src/components/Loading.css b/code/src/components/Loading.css new file mode 100644 index 000000000..fe0849115 --- /dev/null +++ b/code/src/components/Loading.css @@ -0,0 +1,23 @@ + +.loading { + display: flex; + justify-content: center; + font-size: 150px; + padding-top: 300px; +} + +.loading span { + animation: bounce 0.5s ease-in-out infinite; + } + + @keyframes bounce { + 0% { + transform: translateY(0); + } + 50% { + transform: translateY(-40px); + } + 100% { + transform: translateY(0); + } + } diff --git a/code/src/components/Loading.js b/code/src/components/Loading.js new file mode 100644 index 000000000..75e6c0e96 --- /dev/null +++ b/code/src/components/Loading.js @@ -0,0 +1,11 @@ +import React from 'react'; + +const Loading = () => { + return ( +
+ 🎬 +
+ ) +} + +export default Loading; \ No newline at end of file diff --git a/code/src/components/MovieDetails.css b/code/src/components/MovieDetails.css new file mode 100644 index 000000000..1d4b1ac79 --- /dev/null +++ b/code/src/components/MovieDetails.css @@ -0,0 +1,87 @@ +.detailContainer { + margin: 0; + position: relative; +} + +h2 { + color: white; + font-size: 30px; + margin: 0; +} + +p { + color: white; +} + +.icon { + position: absolute; + font-size: 40px; + color: red; + padding: 20px 20px; + text-decoration: none; + display: flex; + gap: 12px; +} + +.icon span { + color: white; + font-size: 28px; +} + +.icon:hover i { + transition: margin-right 0.2s ease-in-out; + } + + .rating { + margin: 0; + font-size: 18px; + font-weight: bold; + } + +.detailSummary { + min-height: 100vh; + display: flex; + background-size: cover; + flex-direction: column; + justify-content: flex-end; + padding: 25px; + gap: 15px; +} + +.detailText { + display: flex; + flex-direction: column; + } + + .poster { + max-width: 200px; + max-height: 300px; + border: solid white 3px; + } + + + @media (min-width: 577px) { + .detailSummary { + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: flex-end; + padding: 50px; + } + .detailText { + max-width: 600px; + } +} + + @media (min-width: 770px) { + .detailSummary { + display: flex; + flex-direction: row; + align-items: flex-end; + padding: 50px; + } + .detailText { + max-width: 600px; + } + } + \ No newline at end of file diff --git a/code/src/components/MovieDetails.js b/code/src/components/MovieDetails.js new file mode 100644 index 000000000..a291702b5 --- /dev/null +++ b/code/src/components/MovieDetails.js @@ -0,0 +1,53 @@ +import React, { useEffect, useState } from 'react'; +import { useParams, useNavigate } from 'react-router-dom'; + +const MovieDetails = () => { + const [movie, setMovie] = useState({}); + const { id } = useParams(); + const navigate = useNavigate(); + const posterPath = `https://image.tmdb.org/t/p/w342/${movie.poster_path}` + const backdropPath = `https://image.tmdb.org/t/p/w1280/${movie.backdrop_path}` + // const API_KEY = '7e62f4c867db459871fea2a9a052cb08'; + // `https://api.themoviedb.org/3/movie/${movieInfo}?api_key=${API_KEY}&language=en-US` + // https://api.themoviedb.org/3/movie/76600?api_key=7e62f4c867db459871fea2a9a052cb08&language=en-US + + const onBackButtonClick = () => { + navigate(-1); + } + + useEffect(() => { + fetch(`https://api.themoviedb.org/3/movie/${id}?api_key=6420add5c0a9b0e0b9462a92916c3187&language=en-US`) + .then((res) => res.json()) + .then((json) => { + setMovie(json) + }) + .catch((error) => { + console.log(error); + }); + }, [id]) + + return ( +
+ + + Back to movies + + {movie && ( +
+ bla +
+

{movie.title}

+

⭐️ {Math.round(movie.vote_average * 10) / 10}

+

{movie.overview}

+
+
+ )} +
+ ); +} + +export default MovieDetails; diff --git a/code/src/components/MovieList.css b/code/src/components/MovieList.css new file mode 100644 index 000000000..d1885e88e --- /dev/null +++ b/code/src/components/MovieList.css @@ -0,0 +1,73 @@ +.listContainer { + display: flex; + flex-wrap: wrap; +} + +.list-element { + position: relative; +} + +.list-element img { + width: 100%; +} + + +@media (min-width: 370px) { + .list-element { + width: 50%; + } + } + + +@media (min-width: 570px) { + .list-element { + width: 33.33%; + } + } + + @media (min-width: 820px) { + .list-element { + width: 25%; + } + } + @media (min-width: 1024px) { + h1 { + font-size: 42px; + } + + p { + font-size: 16px; + } + } + + +.details { + display: none; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + color: white; + text-decoration: none; + background-color: #0000006b; + padding: 20px; +} + +h1 { + font-size: 22px; + margin-top: auto; + margin-bottom: 0; +} + +p { + font-size: 14px; +} + +.list-element:hover .details { + display: flex; + flex-direction: column; + flex-wrap: wrap; + justify-content: flex-end; +} + diff --git a/code/src/components/MovieList.js b/code/src/components/MovieList.js new file mode 100644 index 000000000..5ac5c8aea --- /dev/null +++ b/code/src/components/MovieList.js @@ -0,0 +1,54 @@ +import React, { useState, useEffect } from 'react'; +import { Link } from 'react-router-dom'; +import Loading from './Loading.js'; +import Footer from './Footer.js'; + +const MovieList = () => { + const [loading, setLoading] = useState(false); + const [list, setList] = useState([]); + const API_KEY = '7e62f4c867db459871fea2a9a052cb08'; + console.log(list) + + useEffect(() => { + setLoading(true); + setTimeout(() => { + fetch(`https://api.themoviedb.org/3/movie/popular?api_key=${API_KEY}&language=en-US&page=1`) + .then((res) => res.json()) + .then((data) => { + setList(data.results) + }) + .catch((e) => { + console.error(console.error(e)) + }) + .finally(() => { + setLoading(false); + }) + }, 1200) + }, []); + + return ( + <> +
+ {!loading && list.map((movie) => { + const posterPath = `https://image.tmdb.org/t/p/w342/${movie.poster_path}` + return ( + + {movie.id} +
+

{movie.title}

+

Released {movie.release_date}

+
+ + ) + })} +
+ {!loading &&