├── .gitignore ├── README.md ├── README.old.md ├── package.json ├── public ├── favicon.ico ├── index.html ├── logo.png ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt ├── src ├── App.js ├── App.scss ├── App.test.js ├── Assets │ ├── Footer1.png │ ├── Footer2.png │ ├── default.png │ ├── guyPearce.png │ ├── morganFreeman.png │ └── tmdb.svg ├── Components │ ├── Firebase │ │ └── firebase.utils.js │ ├── Footer │ │ ├── Footer.jsx │ │ └── Footer.scss │ ├── Hero │ │ ├── Hero.jsx │ │ └── Hero.scss │ ├── Home │ │ ├── Home.jsx │ │ └── Home.scss │ ├── LoadMore │ │ └── LoadMore.jsx │ ├── MidMenu │ │ ├── MidMenu.jsx │ │ └── MidMenu.scss │ ├── Modal │ │ ├── Modal.jsx │ │ └── Modal.scss │ ├── MovieDetails │ │ ├── MovieDetails.jsx │ │ └── MovieDetails.scss │ ├── MoviesComing │ │ └── MoviesComing.jsx │ ├── MoviesNow │ │ └── MoviesNow.jsx │ ├── MoviesPopular │ │ └── MoviesPopular.jsx │ ├── MoviesTop │ │ └── MoviesTop.jsx │ ├── Nav │ │ ├── Nav.scss │ │ └── NavTop.jsx │ ├── Search │ │ ├── Search.jsx │ │ └── Search.scss │ ├── SignIn │ │ ├── SignIn.jsx │ │ ├── SignIn.scss │ │ ├── SignInComponent │ │ │ ├── SignInComponent.jsx │ │ │ └── SignInComponent.scss │ │ └── SignUpComponent │ │ │ ├── SignUpComponent.jsx │ │ │ └── SignUpComponent.scss │ ├── User │ │ ├── User.jsx │ │ └── User.scss │ └── defaultMovieComponent │ │ └── DefaultMovieComponent.jsx ├── Context.jsx ├── ScrollToTop.jsx ├── config.js ├── favicon.png ├── index.js ├── index.scss ├── logo.png ├── logo.svg ├── logo_transparent.png ├── serviceWorker.js └── setupTests.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Scriptbase :movie_camera: 2 | 3 | # A Movie Database made with React and TMDB API 4 | 5 | ## Using Router, Firebase, Context API and styled with Bootstrap 6 | 7 | ## Hero 8 | 9 | ![Hero image](https://i.paste.pics/73728e1cb5b0225d128cd06bff2ba3a3.png) 10 | 11 | ## Popular Movies/Movie Menus 12 | 13 | ![home image](https://i.paste.pics/5c56c6278a25c29a69244af9968b7088.png) 14 | 15 | ## Movie Details 16 | 17 | ![movie details](https://i.paste.pics/b67a4b67410680bb02c1e33d3792fd89.png) 18 | 19 | ![movie details](https://i.paste.pics/bbff6a01e0cdb7ef1701d880e084f8b8.png) 20 | 21 | ## User Page 22 | 23 | ![user page](https://i.paste.pics/cc037312996748192b5251dcced5cfd5.png) 24 | 25 | ## Sign In 26 | 27 | ![sign in](https://i.paste.pics/b9282c289b6dfa6c98761c7ffa33f376.png) 28 | 29 | ## Search Modal 30 | 31 | ![search modal ](https://i.paste.pics/8eea85c723747a7abf6cc7b4bcde0531.png) 32 | 33 | -------------------------------------------------------------------------------- /README.old.md: -------------------------------------------------------------------------------- 1 | # react-scriptbase 2 | A movie database made with React and TMDB API 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-scriptbase", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^4.2.4", 7 | "@testing-library/react": "^9.3.2", 8 | "@testing-library/user-event": "^7.1.2", 9 | "axios": "^0.21.1", 10 | "bootstrap": "^4.4.1", 11 | "firebase": "^7.7.0", 12 | "node-sass": "^4.13.1", 13 | "react": "^16.12.0", 14 | "react-bootstrap": "^1.0.0-beta.16", 15 | "react-dom": "^16.12.0", 16 | "react-id-swiper": "^2.4.0", 17 | "react-lazyload": "^2.6.5", 18 | "react-persist": "^1.0.2", 19 | "react-router-dom": "^5.1.2", 20 | "react-scripts": "3.3.0", 21 | "swiper": "^5.3.0" 22 | }, 23 | "scripts": { 24 | "start": "react-scripts start", 25 | "build": "react-scripts build", 26 | "test": "react-scripts test", 27 | "eject": "react-scripts eject" 28 | }, 29 | "eslintConfig": { 30 | "extends": "react-app" 31 | }, 32 | "browserslist": { 33 | "production": [ 34 | ">0.2%", 35 | "not dead", 36 | "not op_mini all" 37 | ], 38 | "development": [ 39 | "last 1 chrome version", 40 | "last 1 firefox version", 41 | "last 1 safari version" 42 | ] 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urlDev/react-scriptbase/0233faa4a912f44d8e12dccb7fe55093e785425e/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 30 | Scriptbase - Movie DataBase 31 | 32 | 33 | 34 | 35 |
36 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urlDev/react-scriptbase/0233faa4a912f44d8e12dccb7fe55093e785425e/public/logo.png -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urlDev/react-scriptbase/0233faa4a912f44d8e12dccb7fe55093e785425e/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urlDev/react-scriptbase/0233faa4a912f44d8e12dccb7fe55093e785425e/public/logo512.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import NavTop from "./components/nav/NavTop"; 4 | import Home from "./components/home/Home"; 5 | import MovieDetails from "./components/movieDetails/MovieDetails"; 6 | import Footer from "./components/footer/Footer"; 7 | import Modal from "./components/modal/Modal"; 8 | import SignIn from "./components/signIn/SignIn"; 9 | import User from "./components/user/User"; 10 | 11 | import MovieContextProvider from "./Context"; 12 | 13 | import { Switch, Route } from "react-router-dom"; 14 | 15 | import "./App.scss"; 16 | 17 | const App = () => { 18 | return ( 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
32 | ); 33 | }; 34 | 35 | export default App; 36 | -------------------------------------------------------------------------------- /src/App.scss: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | position: relative; 4 | min-height: 100vh; 5 | transition: all 0.5 linear; 6 | // height: 250vh; 7 | } 8 | 9 | 10 | /* font-family: 'PT Sans', sans-serif; 11 | font-family: 'Lato', sans-serif; 12 | font-family: 'Metrophobic', sans-serif; */ -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import App from './App'; 4 | 5 | test('renders learn react link', () => { 6 | const { getByText } = render(); 7 | const linkElement = getByText(/learn react/i); 8 | expect(linkElement).toBeInTheDocument(); 9 | }); 10 | -------------------------------------------------------------------------------- /src/Assets/Footer1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urlDev/react-scriptbase/0233faa4a912f44d8e12dccb7fe55093e785425e/src/Assets/Footer1.png -------------------------------------------------------------------------------- /src/Assets/Footer2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urlDev/react-scriptbase/0233faa4a912f44d8e12dccb7fe55093e785425e/src/Assets/Footer2.png -------------------------------------------------------------------------------- /src/Assets/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urlDev/react-scriptbase/0233faa4a912f44d8e12dccb7fe55093e785425e/src/Assets/default.png -------------------------------------------------------------------------------- /src/Assets/guyPearce.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urlDev/react-scriptbase/0233faa4a912f44d8e12dccb7fe55093e785425e/src/Assets/guyPearce.png -------------------------------------------------------------------------------- /src/Assets/morganFreeman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urlDev/react-scriptbase/0233faa4a912f44d8e12dccb7fe55093e785425e/src/Assets/morganFreeman.png -------------------------------------------------------------------------------- /src/Assets/tmdb.svg: -------------------------------------------------------------------------------- 1 | PrimaryLogo_Green -------------------------------------------------------------------------------- /src/Components/Firebase/firebase.utils.js: -------------------------------------------------------------------------------- 1 | import firebase from "firebase/app"; 2 | import 'firebase/firestore'; 3 | import 'firebase/auth'; 4 | 5 | const config = { 6 | apiKey: "AIzaSyDIAO8bU1tlWLx9IPOeWVzGaIyPyRdKHts", 7 | authDomain: "urldev-scriptbase.firebaseapp.com", 8 | databaseURL: "https://urldev-scriptbase.firebaseio.com", 9 | projectId: "urldev-scriptbase", 10 | storageBucket: "urldev-scriptbase.appspot.com", 11 | messagingSenderId: "976679482375", 12 | appId: "1:976679482375:web:1dc8c1b43bbbed38b366a2" 13 | }; 14 | 15 | firebase.initializeApp(config); 16 | 17 | //userAuth is coming from data that firebase stores. 18 | //additionalData is for other data we would need 19 | export const createUserProfileDocument = async(userAuth, additionalData) => { 20 | //if theres no userAuth, exit from statement 21 | if (!userAuth) return; 22 | 23 | const userRef = firestore.doc(`users/${userAuth.uid}`); 24 | 25 | //snapshot will check if user exists 26 | const snapShot = await userRef.get(); 27 | 28 | //this will create a new user in the database 29 | if (!snapShot.exists) { 30 | const { displayName, email } = userAuth; 31 | const createdAt = new Date(); 32 | try { 33 | await userRef.set({ 34 | displayName, 35 | email, 36 | createdAt, 37 | ...additionalData 38 | }); 39 | } catch (error) { 40 | console.log('error creating user', error.message); 41 | } 42 | } 43 | 44 | return userRef; 45 | }; 46 | 47 | 48 | export const auth = firebase.auth(); 49 | export const firestore = firebase.firestore(); 50 | 51 | const provider = new firebase.auth.GoogleAuthProvider(); 52 | provider.setCustomParameters({ prompt: 'select_account' }); 53 | export const signInWithGoogle = () => auth.signInWithPopup(provider); 54 | 55 | export default firebase; -------------------------------------------------------------------------------- /src/Components/Footer/Footer.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import { Container, Row, Col } from "react-bootstrap"; 3 | import { Link } from "react-router-dom"; 4 | import { MovieContext } from "../../Context"; 5 | 6 | import "./Footer.scss"; 7 | 8 | const Footer = () => { 9 | const { clearVisible, getPopular, refreshPage, pageRefreshed } = useContext( 10 | MovieContext 11 | ); 12 | 13 | return ( 14 |
15 | 16 | 17 | 18 | 19 | { 24 | clearVisible(); 25 | getPopular(); 26 | refreshPage(); 27 | }} 28 | /> 29 | 30 | 31 | 32 | 41 | {pageRefreshed ? ( 42 |

43 | 44 | "Hope is a good thing, maybe the best of the good things and 45 | no good thing ever dies" 46 | 47 |

48 | ) : ( 49 |

50 | "We all need memories to remind ourselves who we are" 51 |

52 | )} 53 | 54 | 55 | 56 | 62 | 63 | 64 |
65 |
66 |
67 | ); 68 | }; 69 | 70 | export default React.memo(Footer); 71 | -------------------------------------------------------------------------------- /src/Components/Footer/Footer.scss: -------------------------------------------------------------------------------- 1 | @import "../../index.scss"; 2 | .Footer { 3 | position: absolute; 4 | bottom: 0; 5 | width: 100%; 6 | background: $blue; 7 | // height: 22em; 8 | // background: url("../../Assets/Footer2.png"); 9 | // background-repeat: no-repeat; 10 | // background-size: cover; 11 | .container { 12 | .row { 13 | .col { 14 | .footerBrand { 15 | width: 13em; 16 | margin-left: -4em; 17 | } 18 | h1 { 19 | color: $white; 20 | font-family: $secondary-font; 21 | } 22 | } 23 | .col { 24 | .morganFreeman { 25 | width: 29em; 26 | margin-top: 2em; 27 | float: right; 28 | } 29 | .guyPearce { 30 | width: 25em; 31 | margin-top: 2em; 32 | float: right; 33 | } 34 | .footerText { 35 | font-family: $secondary-font; 36 | color: $white; 37 | font-size: 2em; 38 | margin-top: 3em; 39 | // margin-bottom: 2em; 40 | // margin-left: 4.5em; 41 | animation: fadeIn 2s linear; 42 | } 43 | } 44 | } 45 | } 46 | } 47 | 48 | @media (min-width: 300px) and (max-width:750px) { 49 | .Footer { 50 | .container { 51 | padding: 5em; 52 | .row { 53 | .col { 54 | .footerBrand { 55 | width: 10em; 56 | } 57 | } 58 | .col { 59 | .morganFreeman { 60 | width: 15em; 61 | margin-top: 2em; 62 | float: right; 63 | } 64 | .guyPearce { 65 | width: 18em; 66 | margin-top: 2em; 67 | float: right; 68 | } 69 | .footerText { 70 | font-family: $secondary-font; 71 | color: $white; 72 | font-size: 2em; 73 | margin-top: 3em; 74 | // margin-bottom: 2em; 75 | // margin-left: 4.5em; 76 | animation: fadeIn 2s linear; 77 | } 78 | } 79 | } 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /src/Components/Hero/Hero.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | 3 | import { MovieContext} from "../../Context"; 4 | import Swiper from "react-id-swiper"; 5 | import { Link } from "react-router-dom"; 6 | import LazyLoad from "react-lazyload"; 7 | 8 | import "./Hero.scss"; 9 | import "swiper/swiper.scss"; 10 | 11 | const params = { 12 | spaceBetween: 30, 13 | centeredSlides: true, 14 | rebuildOnUpdate: true, 15 | autoplay: { 16 | delay: 2500, 17 | disableOnInteraction: false 18 | }, 19 | pagination: { 20 | el: ".swiper-pagination", 21 | clickable: true 22 | } 23 | }; 24 | 25 | const Hero = () => { 26 | const { trending, handleClick, refreshPage } = useContext(MovieContext); 27 | return ( 28 |
29 | 30 | {trending.map(movie => { 31 | return ( 32 | { 36 | handleClick(movie.id); 37 | refreshPage(); 38 | }} 39 | > 40 | 41 | {movie.title} 46 | 47 | 48 |

{movie.title}

49 | 50 | ); 51 | })} 52 |
53 |
54 | ); 55 | }; 56 | 57 | export default React.memo(Hero); 58 | -------------------------------------------------------------------------------- /src/Components/Hero/Hero.scss: -------------------------------------------------------------------------------- 1 | @import "../../index.scss"; 2 | .Hero { 3 | position: relative; 4 | .swiper-container { 5 | z-index: 0; 6 | .swiper-wrapper { 7 | .swiper-slide { 8 | cursor: pointer; 9 | // position: absolute; 10 | img { 11 | height: 80vh; 12 | width: 100%; 13 | } 14 | .carousel-caption { 15 | z-index: 3; 16 | text-align: left; 17 | margin-bottom: 1.5em; 18 | // margin-left: -9%; 19 | position: absolute; 20 | // top: 85%; 21 | left: 16.4%; 22 | // transform: translate(-45%, -20%); 23 | // width: 20em; 24 | // height: 4em; 25 | // background: $blue; 26 | font-family: $primary-font; 27 | // font-size: 5em; 28 | text-shadow: 3px 3px $blue; 29 | font-weight: bold; 30 | letter-spacing: 0.1em; 31 | text-transform: uppercase; 32 | color: $white; 33 | } 34 | } 35 | } 36 | } 37 | } 38 | 39 | @media (min-width: 300px) and (max-width:750px) { 40 | .Hero { 41 | .swiper-container { 42 | .swiper-wrapper { 43 | .swiper-slide { 44 | img { 45 | height: 30vh; 46 | width: 100%; 47 | } 48 | .carousel-caption { 49 | position: absolute; 50 | left: 8%; 51 | font-size: 2em; 52 | } 53 | } 54 | } 55 | } 56 | } 57 | } 58 | 59 | @media (min-width: 750px) and (max-width:1100px) { 60 | .Hero { 61 | position: relative; 62 | .swiper-container { 63 | .swiper-wrapper { 64 | .swiper-slide { 65 | img { 66 | height: 50vh; 67 | width: 100%; 68 | } 69 | .carousel-caption { 70 | position: absolute; 71 | left: 6%; 72 | font-size: 3em; 73 | } 74 | } 75 | } 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /src/Components/Home/Home.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import Hero from "../hero/Hero"; 4 | import MidMenu from "../midMenu/MidMenu"; 5 | import MoviesPopular from "../moviesPopular/MoviesPopular"; 6 | import MoviesNow from "../moviesNow/MoviesNow"; 7 | import MoviesComing from "../moviesComing/MoviesComing"; 8 | import MoviesTop from "../moviesTop/MoviesTop"; 9 | 10 | import "./Home.scss"; 11 | 12 | const Home = () => { 13 | return ( 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | ); 23 | }; 24 | 25 | export default Home; 26 | -------------------------------------------------------------------------------- /src/Components/Home/Home.scss: -------------------------------------------------------------------------------- 1 | .Home { 2 | padding-bottom: 30em; 3 | } -------------------------------------------------------------------------------- /src/Components/LoadMore/LoadMore.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import { MovieContext } from "../../Context"; 3 | 4 | const LoadMore = () => { 5 | const { visible, coming, loadMore } = useContext(MovieContext); 6 | return ( 7 |
8 | {/* if value visible is smaller than popular.length then add button */} 9 | {visible < coming.length && ( 10 | 13 | )} 14 |
15 | ); 16 | }; 17 | 18 | export default LoadMore; 19 | -------------------------------------------------------------------------------- /src/Components/MidMenu/MidMenu.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import { Nav, Container } from "react-bootstrap"; 3 | import { Link } from "react-router-dom"; 4 | import "./MidMenu.scss"; 5 | import { MovieContext } from "../../Context"; 6 | 7 | const MidMenu = () => { 8 | const { 9 | popular, 10 | getPopular, 11 | clearVisible, 12 | now, 13 | getNow, 14 | coming, 15 | getComing, 16 | top, 17 | getTop 18 | } = useContext(MovieContext); 19 | 20 | return ( 21 | 22 | 88 | 89 | ); 90 | }; 91 | 92 | export default MidMenu; 93 | -------------------------------------------------------------------------------- /src/Components/MidMenu/MidMenu.scss: -------------------------------------------------------------------------------- 1 | @import "../../index.scss"; 2 | .MidMenu { 3 | height: 5em; 4 | background: $white; 5 | color: $blue; 6 | margin-top: -5em; 7 | z-index: 1000; 8 | position: absolute; 9 | left: 50%; 10 | transform: translate(-50%); 11 | .nav { 12 | &-item { 13 | a { 14 | // padding: 0 2em; 15 | color: $blue; 16 | text-decoration: none; 17 | font-size: 2em; 18 | font-family: $primary-font; 19 | margin-top: 0.7em; 20 | transition: all 0.5s ease-in-out; 21 | &:hover { 22 | color: $yellow; 23 | font-weight: bold; 24 | text-shadow: 1px 1px $blue; 25 | } 26 | } 27 | } 28 | } 29 | .clicked { 30 | color: $yellow !important; 31 | font-weight: bold; 32 | text-shadow: 1px 1px $blue; 33 | } 34 | } 35 | 36 | @media (min-width: 300px) and (max-width:750px) { 37 | .MidMenu { 38 | padding: 0; 39 | // margin: 0; 40 | .nav { 41 | &-item { 42 | a { 43 | font-size: 1.2em; 44 | padding: 0; 45 | margin: 1em 0 !important; 46 | width: 7em; 47 | } 48 | } 49 | } 50 | } 51 | } 52 | 53 | @media (min-width: 751px) and (max-width:999.98px) { 54 | .MidMenu { 55 | padding: 0; 56 | .nav { 57 | &-item { 58 | a { 59 | font-size: 2em; 60 | padding: 0; 61 | // width: 7em; 62 | } 63 | } 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /src/Components/Modal/Modal.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import { MovieContext } from "../../Context"; 3 | import { Container, Row, Col } from "react-bootstrap"; 4 | 5 | import { Link } from "react-router-dom"; 6 | import "./Modal.scss"; 7 | 8 | const Modal = () => { 9 | const { 10 | modalOpen, 11 | closeModal, 12 | moviesResult, 13 | handleClick, 14 | clearSearch 15 | } = useContext(MovieContext); 16 | 17 | //if modal open is false, dont return anything 18 | if (!modalOpen) { 19 | return null; 20 | } else { 21 | //if there is a modal, then return this 22 | return ( 23 |
24 | 25 | {/* */} 26 | {moviesResult.map(movie => { 27 | const { id, poster_path, title, vote_average } = movie; 28 | return ( 29 | { 34 | handleClick(id); 35 | clearSearch(); 36 | }} 37 | > 38 | 39 | 40 | 45 | 46 | 47 |

{title}

{" "} 48 |
49 | {/*

{release_date 50 | ? `${release_date 51 | .split("-") 52 | .reverse() 53 | .join("-")}` 54 | : "Release Date Unknown"}

*/} 55 | 56 | 57 |

{vote_average}

{" "} 58 | 59 |
60 | 61 | ); 62 | })} 63 | {/*
*/} 64 |
65 |
66 | ); 67 | } 68 | }; 69 | 70 | export default Modal; 71 | -------------------------------------------------------------------------------- /src/Components/Modal/Modal.scss: -------------------------------------------------------------------------------- 1 | @import "../../index.scss"; 2 | .Modal { 3 | position: absolute; 4 | top: 0em; 5 | left: 0; 6 | right: 0; 7 | bottom: 0; 8 | // background: rgba(0, 0, 0, 0.3); 9 | z-index: 3000; 10 | margin-left: -2em; 11 | .container { 12 | max-height: 50vh; 13 | margin-top: 8em; 14 | padding: 0; 15 | background: $white; 16 | overflow-y: scroll; 17 | overflow-x: hidden; 18 | .swiper-container { 19 | max-height: 50vh; 20 | } 21 | .row { 22 | padding-top: 1em; 23 | padding-bottom: 1em; 24 | &:hover, 25 | &:hover .modalTitle { 26 | background: $blue; 27 | color: $white !important; 28 | } 29 | padding-bottom: 1em; 30 | .col { 31 | img { 32 | width: 8em; 33 | border: 1px solid $yellow; 34 | } 35 | .modalTitle { 36 | color: $blue; 37 | position: absolute; 38 | // top: 50%; 39 | // left: 10%; 40 | // transform: translate(-50%, -50%); 41 | margin-top: 1.5em; 42 | text-decoration: none; 43 | font-size: 2.5em; 44 | font-weight: bold; 45 | font-family: $primary-font; 46 | &:hover { 47 | text-decoration: none; 48 | } 49 | } 50 | .average { 51 | font-family: $primary-font; 52 | margin-top: 2em; 53 | font-size: 1.5em; 54 | color: $white; 55 | background: $yellow; 56 | width: 3em; 57 | height: 3em; 58 | border-radius: 50%; 59 | line-height: 3em; 60 | text-shadow: 2px 2px $blue; 61 | font-weight: bold; 62 | &:hover { 63 | text-decoration: none !important; 64 | } 65 | } 66 | // .release { 67 | // color: $blue; 68 | // text-decoration: none; 69 | // font-size: 1.5em; 70 | // font-weight: bold; 71 | // font-family: $primary-font; 72 | // } 73 | } 74 | } 75 | } 76 | } 77 | 78 | @media (min-width: 300px) and (max-width:779px) { 79 | .Modal { 80 | width: 80%; 81 | position: absolute; 82 | top: 11em; 83 | left: 10%; 84 | right: 0; 85 | bottom: 0; 86 | // background: rgba(0, 0, 0, 0.3); 87 | z-index: 3000; 88 | margin-left: -2em; 89 | .container { 90 | max-height: 50vh; 91 | margin-top: 8em; 92 | padding: 0; 93 | background: $white; 94 | overflow-y: scroll; 95 | overflow-x: hidden; 96 | .swiper-container { 97 | max-height: 50vh; 98 | } 99 | .row { 100 | .col { 101 | padding-right: 0; 102 | img { 103 | width: 7em; 104 | border: 1px solid $yellow; 105 | } 106 | .modalTitle { 107 | color: $blue; 108 | position: absolute; 109 | text-decoration: none; 110 | font-size: 2em; 111 | font-weight: bold; 112 | font-family: $primary-font; 113 | &:hover { 114 | text-decoration: none; 115 | } 116 | } 117 | } 118 | } 119 | } 120 | } 121 | } 122 | 123 | @media (min-width: 780px) and (max-width:991.99px) { 124 | .Modal { 125 | width: 80%; 126 | position: absolute; 127 | top: 5em; 128 | left: 10%; 129 | right: 0; 130 | bottom: 0; 131 | // background: rgba(0, 0, 0, 0.3); 132 | z-index: 3000; 133 | margin-left: -2em; 134 | .container { 135 | max-height: 50vh; 136 | margin-top: 8em; 137 | padding: 0; 138 | background: $white; 139 | overflow-y: scroll; 140 | overflow-x: hidden; 141 | .swiper-container { 142 | max-height: 50vh; 143 | } 144 | .row { 145 | .col { 146 | padding-right: 0; 147 | img { 148 | width: 7em; 149 | border: 1px solid $yellow; 150 | } 151 | .modalTitle { 152 | color: $blue; 153 | position: absolute; 154 | text-decoration: none; 155 | font-size: 2em; 156 | font-weight: bold; 157 | font-family: $primary-font; 158 | &:hover { 159 | text-decoration: none; 160 | } 161 | } 162 | } 163 | } 164 | } 165 | } 166 | } 167 | 168 | ::-webkit-scrollbar { 169 | width: 1.5em; 170 | } 171 | 172 | ::-webkit-scrollbar-thumb { 173 | background: $red; 174 | border-radius: 0.5em; 175 | } -------------------------------------------------------------------------------- /src/Components/MovieDetails/MovieDetails.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import { Container, Col, Row, Card } from "react-bootstrap"; 3 | import { MovieContext } from "../../Context"; 4 | import Swiper from "react-id-swiper"; 5 | import { Link } from "react-router-dom"; 6 | import LazyLoad from "react-lazyload"; 7 | 8 | import "swiper/swiper.scss"; 9 | import "./MovieDetails.scss"; 10 | 11 | const params = { 12 | slidesPerView: 3, 13 | spaceBetween: 30, 14 | // centeredSlides: true, 15 | pagination: { 16 | el: ".swiper-pagination", 17 | clickable: true 18 | } 19 | }; 20 | 21 | const MovieDetails = () => { 22 | const { 23 | details, 24 | currentUser, 25 | favorite, 26 | addFavorite, 27 | genres, 28 | companies, 29 | countries, 30 | cast, 31 | similar, 32 | handleClick, 33 | refreshPage, 34 | videos 35 | } = useContext(MovieContext); 36 | 37 | const { 38 | poster_path, 39 | overview, 40 | title, 41 | vote_average, 42 | vote_count, 43 | release_date, 44 | revenue, 45 | runtime, 46 | backdrop_path, 47 | budget, 48 | tagline 49 | } = details; 50 | 51 | return ( 52 |
53 | 58 | 59 | 60 | 61 | 62 |
63 | 68 |
69 |
70 |
addFavorite(poster_path)} 73 | > 74 | {currentUser ? ( 75 | favorite.includes(poster_path) ? ( 76 | 81 | ) : ( 82 | 83 | ) 84 | ) : ( 85 | 86 | {" "} 87 | {" "} 88 | 89 | )} 90 |
91 |
92 | 93 | 94 | 95 | 96 | {/* ({release_date}) */} 97 |

{title}

98 |
99 | 100 |

{overview}

101 | 102 |

Average Note:

103 | 104 | 105 |

Vote Count:

106 | 107 |
108 | 109 | 110 |

{vote_average}

111 | 112 | 113 |

{vote_count}

114 | 115 |
116 | 117 |
118 |
119 | 120 | 121 |

122 | Genre: 123 | {genres.map(genre => genre.name).join(", ")} 124 |

125 |

126 | {/* using array and string methods like this, inside a ternary operator and string interpolator */} 127 | Release Date: 128 | {release_date 129 | ? `${release_date 130 | .split("-") 131 | .reverse() 132 | .join("-")}` 133 | : "Release Date Unknown"} 134 |

135 |

136 | Budget: 137 | {budget > 0 ? `${budget.toLocaleString()}$` : "Budget Unknown"} 138 |

139 |

140 | Revenue: 141 | {revenue > 0 ? `${revenue.toLocaleString()}$` : "Not Estimated"} 142 |

143 | 144 | 145 |

146 | Production Companies: 147 | {/* couldnt use array methods here so i made them as states and then used array methods */} 148 | {companies.map(company => company.name).join(", ")} 149 |

150 |

151 | Production Countries: 152 | {countries.map(country => country.name).join(", ")} 153 |

154 |

155 | Tagline: 156 | {tagline ? `${tagline}` : `No Tagline Found`} 157 |

158 |

159 | Runtime: {runtime} 160 | minutes{" "} 161 |

162 | 163 |
164 | 165 |

Cast

166 | 167 | {cast.slice(0, 12).map(i => { 168 | return ( 169 | 170 | {i.profile_path ? ( 171 | 172 | 176 | 177 | ) : ( 178 | 179 | 183 | 184 | )} 185 | 186 | 187 | {i.name} 188 | as {i.character} 189 | 190 | 191 | ); 192 | })} 193 |
194 |
195 | 196 | 197 | 198 |

Similar Movies

199 |
200 |
201 |
202 | 203 | {similar.slice(0, 10).map(movie => { 204 | return ( 205 | { 211 | handleClick(movie.id); 212 | refreshPage(); 213 | }} 214 | > 215 | 216 | 220 | 221 | 222 | ); 223 | })} 224 | 225 |
226 |
227 | {videos.slice(0, 1).map(video => { 228 | return ( 229 | 230 | 231 |

Trailer

232 |
233 | 242 |