├── .firebase └── hosting.YnVpbGQ.cache ├── .firebaserc ├── .gitignore ├── README.md ├── debug.log ├── firebase.json ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt ├── screenshots ├── 1.PNG ├── 2.PNG ├── 3.PNG ├── 4.PNG └── 5.PNG ├── src ├── API │ └── index.js ├── App.css ├── App.js ├── App.test.js ├── assets │ ├── amazonIcon.png │ └── amazonIcon2.png ├── axios.js ├── components │ ├── AllContent │ │ ├── index.js │ │ └── styles.scss │ ├── Episode │ │ ├── index.js │ │ └── styles.scss │ ├── Header │ │ ├── index.js │ │ └── styles.scss │ ├── Home │ │ ├── index.js │ │ └── styles.scss │ ├── HoverScreen │ │ ├── index.js │ │ └── styles.scss │ ├── MediaScreen │ │ ├── index.js │ │ └── styles.scss │ ├── Movie │ │ ├── index.js │ │ └── styles.scss │ ├── Slideshow │ │ ├── index.js │ │ └── styles.scss │ └── TV │ │ ├── index.js │ │ └── styles.scss ├── homeRequests.js ├── index.css ├── index.js ├── logo.svg ├── requests.js ├── serviceWorker.js ├── setupTests.js └── tvRequests.js └── yarn.lock /.firebase/hosting.YnVpbGQ.cache: -------------------------------------------------------------------------------- 1 | favicon.ico,1592292975688,d96ddbc4933b04e12c738ab39f469573143949ca2c39eda0a49d16f83d40c319 2 | logo192.png,1592292975688,3ee59515172ee198f3be375979df15ac5345183e656720a381b8872b2a39dc8b 3 | logo512.png,1592292975688,ee7e2f3fdb8209c4b6fd7bef6ba50d1b9dba30a25bb5c3126df057e1cb6f5331 4 | manifest.json,1592292975688,aff3449bdc238776f5d6d967f19ec491b36aed5fb7f23ccff6500736fd58494a 5 | robots.txt,1592292975688,bfe106a3fb878dc83461c86818bf74fc1bdc7f28538ba613cd3e775516ce8b49 6 | asset-manifest.json,1606393864276,eb9cf6548f9af132c62978a284cbe702a349a4564a8978b1037ec19c5761e4a4 7 | precache-manifest.02afa5a67b00d8c9452f8dc9c02a7d0d.js,1606393864276,331f39c2d28b5d4548f35c3135e748cde752f4e18b4f2487479105f6e9537b41 8 | index.html,1606393864276,d5c4a5d16f1c841e2e231bc241c771541c981664fe68b397d92fec133483dc39 9 | service-worker.js,1606393864276,15e20de7e532f6ea31df3b10eec6b0e1f26b86b61e0f840be3554a56702cb66b 10 | static/css/main.794d03c8.chunk.css,1606393864276,aca71f8baf6f01fa6f1f8bda3cc5ebcc870f67c07cf78e4e4cebbc2c912260fe 11 | static/js/2.9206692c.chunk.js.LICENSE.txt,1606393864283,9222236c29af6e341c37a506e8fd6756969d4d711183fb4832efc33e0e16537c 12 | static/css/main.794d03c8.chunk.css.map,1606393864278,b686dd86b832ef2e4fe4c01fa7cc0c1f1e0f9436d3a7017dd6b0f39f83eb7b11 13 | static/js/main.2a0d8dcf.chunk.js,1606393864279,5b3ca6e8b7c626cbf7f312df7cf4c8af0b6f609f373dd7e2d46f0bb40c3e9fa3 14 | static/js/runtime-main.a123e81e.js,1606393864279,e18d7e8668aa67b52c28f132dcbb695d641007ac529903d6ed11fa1ef727659c 15 | static/js/runtime-main.a123e81e.js.map,1606393864307,d9747a0c8a0853ace29d16375cb2f134ff3ab51c2207a23fb140e92cceb39fc5 16 | static/js/main.2a0d8dcf.chunk.js.map,1606393864283,9d1671433c777ad15bb796c2fc7b8d704cfc273ac583e3941fad2841002cf37e 17 | static/js/2.9206692c.chunk.js,1606393864283,a81a93cf713b29e31c2dab01c89f99ae2ec09fef5f6809dde9480671767611ec 18 | static/js/2.9206692c.chunk.js.map,1606393864307,9a883cbe52f16a401031b3632f407b6201317205fb171896b97e5812134fbc30 19 | -------------------------------------------------------------------------------- /.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "prime-clone-e1de6" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.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 | ## Amazon Prime Clone 2 | This project is a Amazon Prime Clone. You can run the below commands to see the project on your local system. 3 | Hosted on Firebase at https://prime-clone-2fcfe.web.app/ 4 | This is the version 1 of the project. (Desktop View Only). 5 | For getting Data I have used TMDB API. 6 | 7 | ## If you like it please give it a star 😊 8 | 9 | ## Note For Developers 10 | For running the App locally you will have to generate your own API_Key and substitute in all requests files and App.js files. 11 | You can check out other ReactJs projects as well in other repositories deployed on firebase. 12 | 13 | Icons from Material UI library have been used. Link is https://material-ui.com/components/material-icons/ 14 | 15 | #### Technologies Used: 16 | 1. ReactJS 17 | 2. NodeJS 18 | 3. MaterialUI for icons 19 | 20 | ## Don't use it for any commercial purposes. 21 | 22 | Screenshots of the App: 23 | 24 | ![alt text](https://github.com/peeyush14goyal/AmazonPrime-ReactJS-Clone/blob/master/screenshots/1.PNG) 25 | 26 | 27 | ![alt text](https://github.com/peeyush14goyal/AmazonPrime-ReactJS-Clone/blob/master/screenshots/2.PNG) 28 | 29 | 30 | ![alt text](https://github.com/peeyush14goyal/AmazonPrime-ReactJS-Clone/blob/master/screenshots/3.PNG) 31 | 32 | 33 | ![alt text](https://github.com/peeyush14goyal/AmazonPrime-ReactJS-Clone/blob/master/screenshots/4.PNG) 34 | 35 | 36 | ![alt text](https://github.com/peeyush14goyal/AmazonPrime-ReactJS-Clone/blob/master/screenshots/5.PNG) 37 | 38 | #### Contact Details: Email id => peeyushgoyal154@gmail.com 39 | 40 | ## Featured 41 | https://freesoff.com/t/160-open-source-clones-of-popular-sites/88788 42 | 43 | ## Available Scripts 44 | 45 | In the project directory, you can run: 46 | 47 | ### `npm install` 48 | 49 | This command installs all the required dependencies for running the App. 50 | 51 | ### `npm start` 52 | 53 | Runs the app in the development mode.
54 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 55 | 56 | The page will reload if you make edits.
57 | You will also see any lint errors in the console. 58 | 59 | -------------------------------------------------------------------------------- /debug.log: -------------------------------------------------------------------------------- 1 | [1014/164122.072:ERROR:directory_reader_win.cc(43)] FindFirstFile: The system cannot find the path specified. (0x3) 2 | -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "build", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "prime-clone", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@material-ui/core": "^4.11.0", 7 | "@material-ui/icons": "^4.9.1", 8 | "@testing-library/jest-dom": "^4.2.4", 9 | "@testing-library/react": "^9.3.2", 10 | "@testing-library/user-event": "^7.1.2", 11 | "axios": "^0.20.0", 12 | "firebase": "^9.0.1", 13 | "react": "^16.13.1", 14 | "react-dom": "^16.13.1", 15 | "react-pure-lifecycle": "^3.0.0", 16 | "react-redux": "^7.2.2", 17 | "react-router-dom": "^5.2.0", 18 | "react-scripts": "3.4.3", 19 | "react-youtube": "^7.13.0", 20 | "redux": "^4.0.5", 21 | "redux-thunk": "^2.3.0", 22 | "sass": "^1.54.4" 23 | }, 24 | "scripts": { 25 | "start": "react-scripts start", 26 | "build": "react-scripts build", 27 | "test": "react-scripts test", 28 | "eject": "react-scripts eject" 29 | }, 30 | "eslintConfig": { 31 | "extends": "react-app" 32 | }, 33 | "browserslist": { 34 | "production": [ 35 | ">0.2%", 36 | "not dead", 37 | "not op_mini all" 38 | ], 39 | "development": [ 40 | "last 1 chrome version", 41 | "last 1 firefox version", 42 | "last 1 safari version" 43 | ] 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peeyush14goyal/AmazonPrime-ReactJS-Clone/c609202a897af2e062d00b4f8c77ab619b5b7417/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peeyush14goyal/AmazonPrime-ReactJS-Clone/c609202a897af2e062d00b4f8c77ab619b5b7417/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peeyush14goyal/AmazonPrime-ReactJS-Clone/c609202a897af2e062d00b4f8c77ab619b5b7417/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 | Disallow: 4 | -------------------------------------------------------------------------------- /screenshots/1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peeyush14goyal/AmazonPrime-ReactJS-Clone/c609202a897af2e062d00b4f8c77ab619b5b7417/screenshots/1.PNG -------------------------------------------------------------------------------- /screenshots/2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peeyush14goyal/AmazonPrime-ReactJS-Clone/c609202a897af2e062d00b4f8c77ab619b5b7417/screenshots/2.PNG -------------------------------------------------------------------------------- /screenshots/3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peeyush14goyal/AmazonPrime-ReactJS-Clone/c609202a897af2e062d00b4f8c77ab619b5b7417/screenshots/3.PNG -------------------------------------------------------------------------------- /screenshots/4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peeyush14goyal/AmazonPrime-ReactJS-Clone/c609202a897af2e062d00b4f8c77ab619b5b7417/screenshots/4.PNG -------------------------------------------------------------------------------- /screenshots/5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peeyush14goyal/AmazonPrime-ReactJS-Clone/c609202a897af2e062d00b4f8c77ab619b5b7417/screenshots/5.PNG -------------------------------------------------------------------------------- /src/API/index.js: -------------------------------------------------------------------------------- 1 | export const API_KEY = "989a8027930013244e3c2af17088dcac"; 2 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | font-family: "Arial"; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | .gap { 40 | height: 400px; 41 | } 42 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "./App.css"; 3 | import Header from "./components/Header"; 4 | import Home from "./components/Home/index"; 5 | import { BrowserRouter as Router, Route, Switch } from "react-router-dom"; 6 | import AllContent from "./components/AllContent"; 7 | import Movie from "./components/Movie/index"; 8 | import requests from "./requests"; 9 | import tvrequests from "./tvRequests"; 10 | import homeRequests from "./homeRequests"; 11 | import TV from "./components/TV/index"; 12 | 13 | function App() { 14 | const api_key = "989a8027930013244e3c2af17088dcac"; 15 | return ( 16 | 17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | 26 | ( 30 | 35 | )} 36 | /> 37 | ( 41 | 46 | )} 47 | /> 48 | ( 52 | 57 | )} 58 | /> 59 | } 63 | /> 64 | } 68 | /> 69 | } /> 70 | 71 |
72 |
73 |
74 | ); 75 | } 76 | 77 | export default App; 78 | -------------------------------------------------------------------------------- /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/amazonIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peeyush14goyal/AmazonPrime-ReactJS-Clone/c609202a897af2e062d00b4f8c77ab619b5b7417/src/assets/amazonIcon.png -------------------------------------------------------------------------------- /src/assets/amazonIcon2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peeyush14goyal/AmazonPrime-ReactJS-Clone/c609202a897af2e062d00b4f8c77ab619b5b7417/src/assets/amazonIcon2.png -------------------------------------------------------------------------------- /src/axios.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | const instance = axios.create({ 4 | baseURL: "https://api.themoviedb.org/3" 5 | }) 6 | 7 | export default instance; -------------------------------------------------------------------------------- /src/components/AllContent/index.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import "./styles.scss"; 3 | import axiosR from "../../axios"; 4 | import axios from "axios"; 5 | 6 | const AllContent = ({ API_KEY }) => { 7 | const urlParams = new URLSearchParams(window.location.search); 8 | const genre_id = urlParams.get("genre"); 9 | const heading = urlParams.get("title"); 10 | 11 | const [allcontent, setContent] = useState([]); 12 | const base_url = "https://image.tmdb.org/t/p/original/"; 13 | 14 | useEffect(() => { 15 | const request1 = axiosR.get( 16 | `/discover/movie/?api_key=${API_KEY}&with_genres=${genre_id}` 17 | ); 18 | const request2 = axiosR.get( 19 | `/discover/movie/?api_key=${API_KEY}&with_genres=${genre_id}&page=2` 20 | ); 21 | const request3 = axiosR.get( 22 | `/discover/movie/?api_key=${API_KEY}&with_genres=${genre_id}&page=3` 23 | ); 24 | const request4 = axiosR.get( 25 | `/discover/movie/?api_key=${API_KEY}&with_genres=${genre_id}&page=4` 26 | ); 27 | async function getData() { 28 | axios.all([request1, request2, request3, request4]).then( 29 | axios.spread((...responses) => { 30 | const response1 = responses[0].data.results; 31 | const response2 = responses[1].data.results; 32 | const response3 = responses[2].data.results; 33 | 34 | setContent(response1.concat(response2, response3)); 35 | }) 36 | ); 37 | } 38 | getData(); 39 | }, [genre_id, API_KEY]); 40 | 41 | return ( 42 |
43 |
44 |
{heading}
45 |
46 |
47 | {allcontent.map((item) => { 48 | return ( 49 |
50 | {item.name} 55 |
56 | ); 57 | })} 58 |
59 |
60 | ); 61 | }; 62 | 63 | export default AllContent; 64 | -------------------------------------------------------------------------------- /src/components/AllContent/styles.scss: -------------------------------------------------------------------------------- 1 | .contentTitle { 2 | font-size: 18px; 3 | color: gray; 4 | margin-left: 15px; 5 | } 6 | .contentGridDisplay { 7 | display: grid; 8 | grid-template-columns: repeat(5, 2fr); 9 | margin: 0 auto; 10 | margin-left: 10px; 11 | grid-gap: 8px; 12 | overflow-x: hidden; 13 | } 14 | .gridImg { 15 | height: 130px; 16 | object-fit: contain; 17 | } 18 | -------------------------------------------------------------------------------- /src/components/Episode/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "./styles.scss"; 3 | import PlayCircleFilledWhiteIcon from "@material-ui/icons/PlayCircleFilledWhite"; 4 | 5 | const Episode = ({ index, episode }) => { 6 | const base_img_url = "https://image.tmdb.org/t/p/original/"; 7 | return ( 8 |
9 |
10 | {episode.name} 15 |
16 |
17 |
18 |
19 | 24 |
25 |
26 | {index}. {episode.name} 27 |
28 |
29 |
30 |
{episode.air_date}
31 |
32 |
{episode.overview}
33 |
34 |
35 |
36 |
37 |
38 | ); 39 | }; 40 | 41 | export default Episode; 42 | -------------------------------------------------------------------------------- /src/components/Episode/styles.scss: -------------------------------------------------------------------------------- 1 | .EpisodeDiv { 2 | display: grid; 3 | grid-template-columns: 2fr 9fr 1fr; 4 | min-height: 200px; 5 | background-color: #0f171e; 6 | color: gray; 7 | } 8 | .episodeImg { 9 | max-height: 201px; 10 | max-width: 268px; 11 | } 12 | .episodeTitle { 13 | display: flex; 14 | font-size: 20px; 15 | color: white; 16 | } 17 | .paddingInfoDiv { 18 | padding-left: 25px; 19 | } 20 | .playButtonEpisode { 21 | margin-top: 0px; 22 | transform: scale(1.5); 23 | } 24 | .episodeTitleText { 25 | margin-top: 5px; 26 | margin-left: 15px; 27 | } 28 | -------------------------------------------------------------------------------- /src/components/Header/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "./styles.scss"; 3 | import PrimeIcon from "../../assets/amazonIcon.png"; 4 | import SearchOutlinedIcon from "@material-ui/icons/SearchOutlined"; 5 | import AccountCircleOutlinedIcon from "@material-ui/icons/AccountCircleOutlined"; 6 | import { Link } from "react-router-dom"; 7 | 8 | const Header = () => { 9 | return ( 10 |
11 |
12 | 13 |
14 |
15 |
16 |
17 | 18 |
Home
19 |
20 |
21 |
22 | 23 |
TV Shows
24 | 25 |
26 |
27 | 28 |
Movies
29 |
30 |
31 | {/*
32 | 33 |
Kids
34 |
35 |
*/} 36 |
37 |
38 | 39 |
40 |
41 |
42 |
43 | 44 |
45 |
46 | 47 |
48 |
49 |
50 |
51 | 52 |
53 |
54 |
55 | ); 56 | }; 57 | 58 | export default Header; 59 | -------------------------------------------------------------------------------- /src/components/Header/styles.scss: -------------------------------------------------------------------------------- 1 | .header { 2 | height: 72px; 3 | width: 100%; 4 | top: 0; 5 | position: fixed; 6 | background-color: #0f171e; 7 | font-size: 17px; 8 | line-height: 24px; 9 | padding: 16px 35px; 10 | display: flex; 11 | z-index: 6; 12 | } 13 | .primeIcon { 14 | height: 50px; 15 | position: relative; 16 | top: 2px; 17 | background-position: left 0; 18 | object-fit: contain; 19 | color: #0f171e; 20 | filter: invert(1); 21 | } 22 | .iconDiv { 23 | left: 0; 24 | } 25 | .navBarDiv { 26 | display: flex; 27 | color: rgba(242, 244, 246, 0.9); 28 | padding-top: 10px; 29 | font-size: 17px; 30 | min-width: 250px; 31 | align-content: space-between; 32 | } 33 | .navLinks { 34 | color: rgba(242, 244, 246, 0.9); 35 | margin: 8px; 36 | } 37 | 38 | .inputOuterDiv { 39 | border: 1px solid gray; 40 | width: 220px; 41 | height: 40px; 42 | margin-top: 10px; 43 | cursor: pointer; 44 | } 45 | .inputOuterDiv:hover { 46 | border: 1px solid whitesmoke; 47 | } 48 | .inputBox { 49 | border: none; 50 | outline: none; 51 | background-color: #0f171e; 52 | color: white; 53 | margin-left: 5px; 54 | line-height: 20px; 55 | font-size: 15px; 56 | padding: 0px; 57 | } 58 | .inputBox::placeholder { 59 | color: darkgray; 60 | } 61 | .inputDiv { 62 | padding: 9px; 63 | display: flex; 64 | margin-right: 5px; 65 | } 66 | .searchIcon { 67 | filter: invert(0.8); 68 | } 69 | .searchIcon:hover { 70 | filter: invert(1); 71 | } 72 | .headerAlignEnd { 73 | position: absolute; 74 | right: 100px; 75 | display: flex; 76 | } 77 | .account { 78 | filter: invert(0.7); 79 | width: 30px; 80 | object-fit: contain; 81 | margin-left: 20px; 82 | margin-top: 13px; 83 | } 84 | .account:hover { 85 | filter: invert(1); 86 | cursor: pointer; 87 | } 88 | a { 89 | text-decoration: none; 90 | color: rgba(242, 244, 246, 0.9); 91 | } 92 | a:hover { 93 | .textLink { 94 | color: white; 95 | } 96 | .navLinks { 97 | border-bottom: 2px solid white; 98 | cursor: pointer; 99 | } 100 | } 101 | a:active { 102 | .textLink { 103 | color: white; 104 | } 105 | .navLinks { 106 | border-bottom: 2px solid white; 107 | cursor: pointer; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/components/Home/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import MediaScreen from "../MediaScreen"; 3 | import Slideshow from "../Slideshow"; 4 | import "./styles.scss"; 5 | 6 | const Home = ({ api_key, requests, slideShowUrl }) => { 7 | return ( 8 |
9 |
10 | 11 |
12 |
13 | {requests.map((mediaShow) => { 14 | return ( 15 | 23 | ); 24 | })} 25 |
26 |
27 | ); 28 | }; 29 | export default Home; 30 | -------------------------------------------------------------------------------- /src/components/Home/styles.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peeyush14goyal/AmazonPrime-ReactJS-Clone/c609202a897af2e062d00b4f8c77ab619b5b7417/src/components/Home/styles.scss -------------------------------------------------------------------------------- /src/components/HoverScreen/index.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import "./styles.scss"; 3 | import PlayCircleFilledWhiteOutlinedIcon from "@material-ui/icons/PlayCircleFilledWhiteOutlined"; 4 | import AddOutlinedIcon from "@material-ui/icons/AddOutlined"; 5 | import ChatBubbleIcon from "@material-ui/icons/ChatBubble"; 6 | import axios from "../../axios"; 7 | import { Link } from "react-router-dom"; 8 | 9 | const HoverScreen = ({ item, api_key, media_type }) => { 10 | let hours = 0, 11 | minutes = 0; 12 | const [media, setMedia] = useState({}); 13 | 14 | useEffect(() => { 15 | async function getData() { 16 | const response = await axios.get( 17 | `/${media_type}/${item.id}?api_key=${api_key}` 18 | ); 19 | setMedia(response.data); 20 | return response; 21 | } 22 | getData(); 23 | }, [item, api_key, media_type]); 24 | 25 | const base_url = "https://image.tmdb.org/t/p/original/"; 26 | if (media.runtime && media.runtime > 0) { 27 | hours = Math.floor(media.runtime / 60); 28 | minutes = media.runtime % 60; 29 | } 30 | return ( 31 |
32 | 36 | {item.name} 41 |
42 |
43 |
44 |
45 | 46 |
47 |
Play
48 |
49 |
50 | 51 |
52 |
53 |
54 | {item.title ? item.title : item.original_name} 55 |
56 |
57 | {item.overview.length > 90 58 | ? item.overview.substr(0, 89) + "..." 59 | : item.overview} 60 |
61 |
62 |
63 | {hours > 0 ? `${hours}h ` : ""} 64 | {minutes > 0 ? `${minutes}min` : ""} 65 |
66 |
67 | {item.release_date ? item.release_date.substr(0, 4) : ""} 68 |
69 |
70 | 71 |
72 |
{item.adult ? "18+" : "ALL"}
73 |
74 |
75 | 76 |
77 | ); 78 | }; 79 | 80 | export default HoverScreen; 81 | -------------------------------------------------------------------------------- /src/components/HoverScreen/styles.scss: -------------------------------------------------------------------------------- 1 | .mediaHoverImg { 2 | height: 160px; 3 | width: 300px; 4 | margin-top: 10px; 5 | border-radius: 0%; 6 | z-index: 2; 7 | } 8 | .hoverScreen { 9 | position: relative; 10 | color: white; 11 | width: 300px; 12 | transform: scale(1.1); 13 | transition-property: transform; 14 | transition-delay: 2000ms; 15 | transition-duration: 3s; 16 | top: -30px; 17 | opacity: 1; 18 | z-index: 2; 19 | margin-bottom: 20px; 20 | text-decoration: none; 21 | } 22 | .hoverData { 23 | position: relative; 24 | background: linear-gradient(rgba(27, 37, 48, 0), #1b2530 48px); 25 | padding: 30px 30px; 26 | padding-bottom: 5px; 27 | margin-top: -45px; 28 | z-index: 2; 29 | text-decoration: none; 30 | } 31 | .playButton { 32 | color: white; 33 | transform: scale(1.3); 34 | } 35 | .playButton:hover { 36 | background-color: blue; 37 | border-radius: 50%; 38 | outline: none; 39 | } 40 | .playtext { 41 | text-decoration: none; 42 | margin-top: 5px; 43 | font-size: 14px; 44 | font-weight: bold; 45 | } 46 | .playDiv { 47 | display: flex; 48 | justify-content: space-between; 49 | height: 30px; 50 | width: 65px; 51 | } 52 | .playIcon { 53 | width: 40px; 54 | } 55 | .addIcon { 56 | color: white; 57 | } 58 | .hoverHeading { 59 | text-decoration: none; 60 | display: flex; 61 | justify-content: space-between; 62 | } 63 | .title { 64 | margin-top: 10px; 65 | font-weight: 700; 66 | font-size: 14px; 67 | text-decoration: none; 68 | } 69 | .overview { 70 | margin-top: 5px; 71 | font-size: 11px; 72 | text-decoration: none; 73 | } 74 | .releaseYear { 75 | font-size: 11px; 76 | color: gray; 77 | margin-bottom: 15px; 78 | } 79 | .runTime { 80 | color: darkgray; 81 | font-size: 11px; 82 | } 83 | .footerScreen { 84 | margin-top: 10px; 85 | display: flex; 86 | justify-content: space-between; 87 | width: 200px; 88 | } 89 | .messageIcon { 90 | color: darkgray; 91 | max-height: 18px; 92 | } 93 | .rated { 94 | border: 1px solid darkgray; 95 | color: darkgray; 96 | font-size: 9px; 97 | padding: 3px; 98 | height: 10px; 99 | } 100 | -------------------------------------------------------------------------------- /src/components/MediaScreen/index.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import "./styles.scss"; 3 | import axios from "../../axios"; 4 | import ChevronRightIcon from "@material-ui/icons/ChevronRight"; 5 | import ChevronLeftIcon from "@material-ui/icons/ChevronLeft"; 6 | import HoverScreen from "../HoverScreen"; 7 | import { Link } from "react-router-dom"; 8 | 9 | const MediaScreen = ({ 10 | heading, 11 | fetchURL, 12 | API_KEY, 13 | genre = -1, 14 | moveCount, 15 | media_type, 16 | }) => { 17 | const [data, setData] = useState([]); 18 | const base_url = "https://image.tmdb.org/t/p/original/"; 19 | var count = 0; 20 | 21 | useEffect(() => { 22 | async function fetchData() { 23 | const response = await axios.get(fetchURL); 24 | setData(response.data.results); 25 | return response; 26 | } 27 | fetchData(); 28 | }, [fetchURL]); 29 | 30 | const scrollToLeft = () => { 31 | document.getElementById("bannerDiv" + moveCount.toString()).scrollBy({ 32 | left: -800, 33 | }); 34 | }; 35 | const scrollToRight = () => { 36 | document.getElementById("bannerDiv" + moveCount.toString()).scrollBy({ 37 | left: 800, 38 | }); 39 | }; 40 | 41 | const setPosition = (item) => { 42 | var x = document.getElementById(`1${item.id}`); 43 | var divItem = document.getElementById(`2${item.id}`); 44 | const ele = document.getElementById("bannerDiv" + moveCount.toString()); 45 | if (divItem) { 46 | divItem.style.position = "absolute"; 47 | divItem.style.top = x.offsetTop + "px"; 48 | divItem.style.left = x.offsetLeft - ele.scrollLeft + "px"; 49 | } 50 | }; 51 | 52 | const shuffleData = (arr) => { 53 | for (var i = arr.length - 1; i > 0; i--) { 54 | var j = Math.floor(Math.random() * (i + 1)); 55 | var temp = arr[i]; 56 | arr[i] = arr[j]; 57 | arr[j] = temp; 58 | } 59 | }; 60 | if (data.length > 0) { 61 | shuffleData(data); 62 | } 63 | return ( 64 |
65 |
66 |
{heading}
67 | {genre > 0 ? ( 68 | 69 |
see more
70 | 71 | ) : ( 72 |
73 | )} 74 |
75 | 76 |
77 | 78 |
79 |
80 |   81 | {data.map((item) => { 82 | return ( 83 |
84 | {item.backdrop_path ? ( 85 |
{ 89 | setPosition(item); 90 | }} 91 | > 92 | {item.name} 97 | 98 |
99 | 104 |
105 |
106 | ) : ( 107 |
108 | )} 109 |
110 | ); 111 | })} 112 |
113 |
114 | 115 |
116 |
117 | ); 118 | }; 119 | 120 | export default MediaScreen; 121 | -------------------------------------------------------------------------------- /src/components/MediaScreen/styles.scss: -------------------------------------------------------------------------------- 1 | .headingBanner { 2 | color: white; 3 | font-size: 19px; 4 | margin-left: 20px; 5 | display: flex; 6 | justify-content: space-between; 7 | } 8 | .banner { 9 | display: flex; 10 | left: 10px; 11 | overflow-y: hidden; 12 | overflow-x: scroll; 13 | scroll-behavior: smooth; 14 | justify-content: space-between; 15 | z-index: -1; 16 | } 17 | .banner::-webkit-scrollbar { 18 | display: none; 19 | } 20 | .leftIconDiv { 21 | left: 0px; 22 | max-height: 166px; 23 | z-index: 1; 24 | width: 30px; 25 | color: gray; 26 | position: absolute; 27 | margin-top: 10px; 28 | -webkit-transition: opacity 0.25s ease, background-color 0.25s ease; 29 | transition: opacity 0.25s ease, background-color 0.25s ease; 30 | background-color: rgba(15, 23, 30, 0.5); 31 | } 32 | .leftIcon { 33 | min-height: 160px; 34 | } 35 | .leftIconDiv:hover { 36 | .leftIcon { 37 | color: white; 38 | transform: scale(1.5); 39 | } 40 | } 41 | .rightIconDiv { 42 | margin-top: -180px; 43 | right: 0px; 44 | min-height: 166px; 45 | z-index: 1; 46 | width: 40px; 47 | color: gray; 48 | position: absolute; 49 | -webkit-transition: opacity 0.25s ease, background-color 0.25s ease; 50 | transition: opacity 0.25s ease, background-color 0.25s ease; 51 | background-color: rgba(15, 23, 30, 0.5); 52 | //background-color: black; 53 | cursor: pointer; 54 | } 55 | .rightIcon { 56 | min-height: 160px; 57 | margin-left: 0px; 58 | padding-top: -200px; 59 | } 60 | .rightIconDiv:hover { 61 | .rightIcon { 62 | color: white; 63 | transform: scale(1.5); 64 | } 65 | } 66 | 67 | .mediaScreen { 68 | margin-top: 5px; 69 | z-index: 0; 70 | } 71 | 72 | .mediaDiv { 73 | position: static; 74 | width: 100%; 75 | cursor: pointer; 76 | z-index: 0; 77 | padding: 10px 0px; 78 | padding-top: 5px; 79 | .displayhoverScreen { 80 | display: none; 81 | position: absolute; 82 | z-index: 5; 83 | padding: 1px; 84 | min-height: 400px; 85 | transform: scale(1); 86 | } 87 | &:hover > .displayhoverScreen { 88 | // 89 | display: block; 90 | position: absolute; 91 | 92 | // padding: 1px; 93 | //z-index: 3; 94 | } 95 | } 96 | .mediaImg { 97 | height: 160px; 98 | object-fit: cover; 99 | margin: 5px; 100 | border-radius: 4px; 101 | z-index: 0; 102 | visibility: visible; 103 | } 104 | 105 | .mediaDiv:hover { 106 | padding: 0px; 107 | .mediaImg { 108 | height: 0px; 109 | width: 284px; 110 | visibility: hidden; 111 | // margin-top: -10px; 112 | } 113 | } 114 | 115 | .moreButton { 116 | color: lightblue; 117 | font-size: 14px; 118 | margin-right: 15px; 119 | cursor: pointer; 120 | text-decoration: none; 121 | } 122 | .moreButton:hover { 123 | color: white; 124 | } 125 | -------------------------------------------------------------------------------- /src/components/Movie/index.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import "./styles.scss"; 3 | import axios from "../../axios"; 4 | import ChatBubbleIcon from "@material-ui/icons/ChatBubble"; 5 | import PlayCircleFilledWhiteIcon from "@material-ui/icons/PlayCircleFilledWhite"; 6 | import ChangeHistoryIcon from "@material-ui/icons/ChangeHistory"; 7 | import GetAppIcon from "@material-ui/icons/GetApp"; 8 | import Button from "@material-ui/core/Button"; 9 | import MediaScreen from "../MediaScreen"; 10 | import CancelIcon from "@material-ui/icons/Cancel"; 11 | import IconButton from "@material-ui/core/IconButton"; 12 | import YouTube from "react-youtube"; 13 | 14 | const Movie = ({ api_key }) => { 15 | const [credits, setCredits] = useState(); 16 | const [movieDetails, setDetails] = useState(); 17 | const [videos, setVideo] = useState(); 18 | const [detailShow, setShow] = useState(1); 19 | const [YoutubePlay, setYoutubePlay] = useState(false); 20 | const [trailer_id, setTrailer_id] = useState(); 21 | const base_url = "https://api.themoviedb.org/3/movie/"; 22 | let detailsLoaded = false; 23 | let creditsLoaded = false; 24 | let hours, minutes; 25 | let director = []; 26 | let crew = []; 27 | let writing = []; 28 | let production = []; 29 | const opts = { 30 | width: "100%", 31 | minHeight: "200%", 32 | paddingTop: "56.25%", // Percentage ratio for 16:9 33 | position: "absolute", 34 | playerVars: { 35 | autoplay: 1, 36 | listType: "user_uploads", 37 | }, 38 | }; 39 | 40 | const urlParams = new URLSearchParams(window.location.search); 41 | const movie_id = urlParams.get("id"); 42 | 43 | const image_base_url = "https://image.tmdb.org/t/p/original/"; 44 | 45 | useEffect(() => { 46 | async function fetchDetails() { 47 | const response = await axios.get( 48 | `${base_url}${movie_id}?api_key=${api_key}` 49 | ); 50 | 51 | setDetails(response.data); 52 | return response; 53 | } 54 | async function fetchCredits() { 55 | const response = await axios.get( 56 | `${base_url}${movie_id}/credits?api_key=${api_key}` 57 | ); 58 | 59 | setCredits(response.data); 60 | } 61 | async function getVideo() { 62 | const response = await axios.get( 63 | `${base_url}${movie_id}/videos?api_key=${api_key}` 64 | ); 65 | 66 | setVideo(response.data.results); 67 | } 68 | fetchCredits(); 69 | fetchDetails(); 70 | getVideo(); 71 | }, [base_url, movie_id, api_key]); 72 | 73 | const playVideo = () => { 74 | if (videos) { 75 | setYoutubePlay(true); 76 | 77 | setTrailer_id(videos[0].key); 78 | } else { 79 | setYoutubePlay(false); 80 | } 81 | return trailer_id; 82 | }; 83 | 84 | if (movieDetails) { 85 | detailsLoaded = true; 86 | } 87 | if (credits) { 88 | creditsLoaded = true; 89 | credits.crew.map((person) => { 90 | if (person.known_for_department === "Directing") { 91 | director.push(person.name); 92 | } else if (person.known_for_department === "Production") { 93 | production.push(person.name); 94 | } else if (person.known_for_department === "Writing") { 95 | writing.push(person.name); 96 | } else if (person.known_for_department === "Crew") { 97 | crew.push(person.name); 98 | } 99 | return person.name; 100 | }); 101 | } 102 | 103 | if (detailsLoaded && movieDetails.runtime && movieDetails.runtime > 0) { 104 | hours = Math.floor(movieDetails.runtime / 60); 105 | minutes = movieDetails.runtime % 60; 106 | } 107 | 108 | return ( 109 |
110 | {detailsLoaded ? ( 111 |
112 |
113 |
114 | {movieDetails.title 115 | ? movieDetails.title 116 | : movieDetails.original_name} 117 |
118 |
{movieDetails.overview}
119 |
120 |
121 | IMDb {movieDetails.vote_average} 122 |
123 |
124 | {hours > 0 ? `${hours}h ` : ""} 125 | {minutes > 0 ? `${minutes}min` : ""} 126 |
127 |
128 | {movieDetails.release_date 129 | ? movieDetails.release_date.substr(0, 4) 130 | : ""} 131 |
132 | 133 |
134 | {movieDetails.adult ? "18+" : "ALL"} 135 |
136 |
137 | 138 |
139 |
140 |
141 |
142 | 155 |
156 |
157 | 167 |
168 |
169 | 176 |
177 |
178 | 186 |
187 |
188 | {creditsLoaded ? ( 189 |
190 |
Director
191 |
{director}
192 |
Starring
193 |
194 | {credits.cast.map((person) => { 195 | let str = ""; 196 | if (credits.cast.indexOf(person) < 11) { 197 | str = `${person.name}, `; 198 | } 199 | return str; 200 | })} 201 |
202 |
Genres
203 |
204 | {movieDetails.genres.map((genre) => { 205 | let str = `${genre.name}, `; 206 | return str; 207 | })} 208 |
209 |
210 | ) : ( 211 |
212 | )} 213 |
214 |
215 | {movieDetails.id} 220 |
221 |
222 |
223 |
224 | ) : ( 225 |
226 | )} 227 | 228 | {YoutubePlay ? ( 229 |
230 |
231 | { 235 | setYoutubePlay(false); 236 | }} 237 | color="primary" 238 | className="closeIconButton" 239 | > 240 | 241 | 242 |
243 | 244 | { 248 | alert("Youtube Not working"); 249 | }} 250 | /> 251 |
252 | ) : ( 253 |
254 | )} 255 |
256 |
257 |
258 |
{ 260 | setShow(1); 261 | }} 262 | className={detailShow === 1 ? "activeRelated" : ""} 263 | > 264 | Related 265 |
266 |
{ 268 | setShow(0); 269 | }} 270 | className={detailShow === 0 ? "activeDetails" : ""} 271 | > 272 | Details 273 |
274 |
275 | {detailsLoaded && detailShow === 1 ? ( 276 | 282 | ) : ( 283 |
284 |
285 | {production.length > 0 ? ( 286 |
Production
287 | ) : ( 288 |
289 | )} 290 | {production.length > 0 ? ( 291 |
292 | {production.map((person) => { 293 | let str = `${person}, `; 294 | return str; 295 | })} 296 |
297 | ) : ( 298 |
299 | )} 300 | {writing.length > 0 ? ( 301 |
Writing
302 | ) : ( 303 |
304 | )} 305 | {writing.length > 0 ? ( 306 |
307 | {writing.map((person) => { 308 | let str = `${person}, `; 309 | return str; 310 | })} 311 |
312 | ) : ( 313 |
314 | )} 315 | {crew.length > 0 ? ( 316 |
Crew
317 | ) : ( 318 |
319 | )} 320 | {crew.length > 0 ? ( 321 |
322 | {crew.map((person) => { 323 | let str = `${person}, `; 324 | return str; 325 | })} 326 |
327 | ) : ( 328 |
329 | )} 330 |
331 |
332 | )} 333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 | ); 342 | }; 343 | export default Movie; 344 | -------------------------------------------------------------------------------- /src/components/Movie/styles.scss: -------------------------------------------------------------------------------- 1 | .movie_image { 2 | width: 950px; 3 | position: absolute; 4 | right: 0px; 5 | object-fit: contain; 6 | z-index: -1; 7 | top: 100px; 8 | } 9 | .imageDiv { 10 | position: absolute; 11 | z-index: 0; 12 | right: 0; 13 | top: 0; 14 | height: 510px; 15 | overflow: hidden; 16 | width: 950px; 17 | padding: 0px; 18 | } 19 | .divImage1 { 20 | position: absolute; 21 | top: 0; 22 | width: 950px; 23 | height: 600px; 24 | right: 0; 25 | background: linear-gradient(90deg, #0f171e 10%, rgba(15, 23, 30, 0)); 26 | } 27 | .divImage2 { 28 | position: absolute; 29 | top: 0; 30 | width: 950px; 31 | height: 600px; 32 | right: 0; 33 | background: linear-gradient(0deg, #0f171e 0, rgba(15, 23, 30, 0) 50%); 34 | } 35 | .movieInfo { 36 | position: absolute; 37 | left: 0; 38 | color: white; 39 | margin-left: 30px; 40 | z-index: 2; 41 | } 42 | .title2 { 43 | font-size: 40px; 44 | margin-top: 10px; 45 | font-weight: normal; 46 | } 47 | .overview2 { 48 | // position: absolute; 49 | // margin-top: 40px; 50 | //z-index: 2; 51 | margin-top: 20px; 52 | width: 600px; 53 | font-size: 16px; 54 | line-height: 1.5; 55 | } 56 | 57 | .moviereleaseYear { 58 | font-size: 15px; 59 | color: gray; 60 | margin-bottom: 15px; 61 | } 62 | .movierunTime { 63 | color: darkgray; 64 | font-size: 15px; 65 | } 66 | .moviefooterScreen { 67 | margin-top: 15px; 68 | display: flex; 69 | justify-content: space-between; 70 | width: 300px; 71 | } 72 | .moviemessageIcon { 73 | color: darkgray; 74 | max-height: 18px; 75 | } 76 | .movierated { 77 | border: 1px solid darkgray; 78 | color: darkgray; 79 | font-size: 12px; 80 | padding: 3px; 81 | height: 10px; 82 | } 83 | .movierating { 84 | color: darkgray; 85 | font-size: 15px; 86 | } 87 | .people { 88 | //position: absolute; 89 | min-width: 500px; 90 | max-width: 70%; 91 | display: grid; 92 | grid-template-columns: 1.3fr 10.7fr; 93 | text-align: left; 94 | margin-top: 40px; 95 | //z-index: 2; 96 | grid-row-gap: 7px; 97 | line-height: 1.5; 98 | } 99 | .peopleHeading { 100 | color: gray; 101 | font-weight: bold; 102 | } 103 | .peopleVal { 104 | color: rgb(6, 167, 196); 105 | } 106 | .buttonGroup { 107 | display: flex; 108 | justify-content: space-evenly; 109 | // z-index: 2; 110 | //position: absolute; 111 | margin-top: 30px; 112 | width: 750px; 113 | padding: 0 auto; 114 | } 115 | 116 | .trailerIcon { 117 | transform: rotate(90deg); 118 | } 119 | .moviePlayText { 120 | color: white; 121 | margin-left: 8px; 122 | //font-size: 20px; 123 | //margin-left: 10px; 124 | } 125 | .moviePlayIcon { 126 | transform: scale(2); 127 | background-color: white; 128 | border-radius: 50%; 129 | //margin-bottom: 30px; 130 | } 131 | .movieButton { 132 | height: 50px; 133 | } 134 | .playmovieButton { 135 | transform: scale(1.5); 136 | } 137 | .relatedMovies { 138 | position: absolute; 139 | top: 650px; 140 | width: 100%; 141 | } 142 | .tabHeading { 143 | display: flex; 144 | justify-content: space-between; 145 | min-width: 250px; 146 | text-align: center; 147 | margin-left: 40%; 148 | top: 800px; 149 | color: gray; 150 | font-size: 25px; 151 | cursor: pointer; 152 | } 153 | 154 | .activeRelated { 155 | border-bottom: 2px solid white; 156 | color: white; 157 | } 158 | .activeDetails { 159 | border-bottom: 2px solid white; 160 | color: white; 161 | } 162 | .detailsCrew { 163 | margin-left: 30px; 164 | } 165 | .playTrailerVideo { 166 | position: absolute; 167 | top: 0; 168 | left: 0; 169 | z-index: 10; 170 | min-height: 100%; 171 | min-width: 100%; 172 | background-color: rgba(220, 220, 220, 0.5); 173 | transition: background-color 1s ease-in; 174 | padding-top: 100px; 175 | } 176 | .closeButtonDiv { 177 | margin-left: 90%; 178 | } 179 | .closeIconButton { 180 | transform: scale(2); 181 | } 182 | -------------------------------------------------------------------------------- /src/components/Slideshow/index.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import axios from "../../axios"; 3 | import "./styles.scss"; 4 | 5 | const Slideshow = ({ fetch_url, api_key }) => { 6 | const [sshow, setSshow] = useState([]); 7 | const base_url = "https://image.tmdb.org/t/p/original/"; 8 | var startSS = 0; 9 | var temp_int; 10 | const automaticSlideshow = () => { 11 | const x = document.getElementsByClassName("ssDiv"); 12 | 13 | var i; 14 | if (x.length === 0) { 15 | clearInterval(temp_int); 16 | } 17 | for (i = 0; i < sshow.length && x.length > 0; i++) { 18 | if (i === startSS) { 19 | x[i].style.display = "block"; 20 | x[i].style.width = "100%"; 21 | } else { 22 | x[i].style.display = "none"; 23 | x[i].style.width = "0%"; 24 | } 25 | } 26 | startSS++; 27 | if (sshow.length > 0 && startSS === sshow.length) { 28 | startSS = 0; 29 | } 30 | }; 31 | 32 | temp_int = setInterval(automaticSlideshow, 5000); 33 | 34 | useEffect(() => { 35 | async function fetchData() { 36 | const response = await axios.get(fetch_url + `?api_key=${api_key}`); 37 | 38 | setSshow(response.data.results); 39 | return response; 40 | } 41 | fetchData(); 42 | }, [fetch_url, api_key]); 43 | 44 | return ( 45 |
46 | {sshow.map((item) => { 47 | return ( 48 |
49 |
50 | {item.name} 55 | 56 |
57 |
58 | {item.original_title 59 | ? item.original_title 60 | : item.original_name} 61 |
62 |
{item.overview}
63 | {/*
64 | Media Type:{" "} 65 | {item.media_type === "tv" 66 | ? item.media_type.toUpperCase() 67 | : item.media_type.charAt(0).toUpperCase() + 68 | item.media_type.slice(1)} 69 |
*/} 70 |
71 |
72 |
73 | ); 74 | })} 75 |
76 | ); 77 | }; 78 | 79 | export default Slideshow; 80 | -------------------------------------------------------------------------------- /src/components/Slideshow/styles.scss: -------------------------------------------------------------------------------- 1 | .SSdescription { 2 | position: absolute; 3 | color: white; 4 | margin-top: 200px; 5 | font-size: 35px; 6 | width: 500px; 7 | font-weight: bolder; 8 | line-height: 1.5; 9 | //background-color: rgba(223, 217, 217, 0.5); 10 | } 11 | .ssDiv { 12 | display: none; 13 | position: relative; 14 | min-height: 900px; 15 | max-height: 1000px; 16 | } 17 | 18 | .ssOverview { 19 | margin-top: 10px; 20 | opacity: 1; 21 | font-size: 20px; 22 | color: darkgray; 23 | font-weight: normal; 24 | margin-left: 40px; 25 | } 26 | .ssTitle { 27 | opacity: 1; 28 | margin-left: 40px; 29 | } 30 | .ssVote { 31 | margin-top: 15px; 32 | margin-left: 40px; 33 | font-size: 23px; 34 | color: whitesmoke; 35 | } 36 | 37 | .slideshowImg { 38 | position: absolute; 39 | display: block; 40 | width: 100%; 41 | object-fit: cover; 42 | max-height: 900px; 43 | opacity: 0.5; 44 | // margin-bottom: 50px; 45 | } 46 | -------------------------------------------------------------------------------- /src/components/TV/index.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import "./styles.scss"; 3 | import axios from "../../axios"; 4 | import ChatBubbleIcon from "@material-ui/icons/ChatBubble"; 5 | import PlayCircleFilledWhiteIcon from "@material-ui/icons/PlayCircleFilledWhite"; 6 | import ChangeHistoryIcon from "@material-ui/icons/ChangeHistory"; 7 | import GetAppIcon from "@material-ui/icons/GetApp"; 8 | import Button from "@material-ui/core/Button"; 9 | import MediaScreen from "../MediaScreen"; 10 | import CancelIcon from "@material-ui/icons/Cancel"; 11 | import IconButton from "@material-ui/core/IconButton"; 12 | import YouTube from "react-youtube"; 13 | import Episode from "../Episode/index"; 14 | 15 | const TV = ({ api_key }) => { 16 | const [credits, setCredits] = useState(); 17 | const [movieDetails, setDetails] = useState(); 18 | const [videos, setVideo] = useState(); 19 | const [detailShow, setShow] = useState(1); 20 | const [YoutubePlay, setYoutubePlay] = useState(false); 21 | const [trailer_id, setTrailer_id] = useState(); 22 | const [episodes, setEpisodes] = useState(); 23 | const [seasonCount, setseasonCount] = useState(); 24 | const base_url = "https://api.themoviedb.org/3/tv/"; 25 | let detailsLoaded = false; 26 | let creditsLoaded = false; 27 | let hours, minutes; 28 | let director = []; 29 | let crew = []; 30 | let writing = []; 31 | let production = []; 32 | const opts = { 33 | width: "100%", 34 | minHeight: "200%", 35 | paddingTop: "56.25%", // Percentage ratio for 16:9 36 | position: "absolute", 37 | playerVars: { 38 | autoplay: 1, 39 | listType: "user_uploads", 40 | }, 41 | }; 42 | 43 | const urlParams = new URLSearchParams(window.location.search); 44 | const movie_id = urlParams.get("id"); 45 | 46 | const image_base_url = "https://image.tmdb.org/t/p/original/"; 47 | 48 | useEffect(() => { 49 | async function fetchDetails() { 50 | const response = await axios.get( 51 | `${base_url}${movie_id}?api_key=${api_key}` 52 | ); 53 | 54 | const temp = response.data.number_of_seasons; 55 | var tempArr = []; 56 | for (let i = 1; i <= temp; i++) { 57 | tempArr.push(i); 58 | } 59 | 60 | setseasonCount(tempArr); 61 | setDetails(response.data); 62 | return response; 63 | } 64 | async function fetchCredits() { 65 | const response = await axios.get( 66 | `${base_url}${movie_id}/credits?api_key=${api_key}` 67 | ); 68 | 69 | setCredits(response.data); 70 | } 71 | async function getVideo() { 72 | const response = await axios.get( 73 | `${base_url}${movie_id}/videos?api_key=${api_key}` 74 | ); 75 | 76 | setVideo(response.data.results); 77 | } 78 | async function getDefaultEpisodes() { 79 | const response = await axios.get( 80 | `${base_url}${movie_id}/season/1?api_key=${api_key}` 81 | ); 82 | 83 | setEpisodes(response.data.episodes); 84 | } 85 | fetchCredits(); 86 | fetchDetails(); 87 | getVideo(); 88 | getDefaultEpisodes(); 89 | }, [base_url, movie_id, api_key]); 90 | 91 | const playVideo = () => { 92 | if (videos) { 93 | setYoutubePlay(true); 94 | 95 | setTrailer_id(videos[0].key); 96 | } else { 97 | setYoutubePlay(false); 98 | } 99 | return trailer_id; 100 | }; 101 | 102 | async function getEpisodes() { 103 | const temp = document.getElementById("selectIdTag").value; 104 | const val = temp.substr(7, 8); 105 | const response = await axios.get( 106 | `${base_url}${movie_id}/season/${val}?api_key=${api_key}` 107 | ); 108 | 109 | setEpisodes(response.data.episodes); 110 | } 111 | 112 | if (movieDetails) { 113 | detailsLoaded = true; 114 | } 115 | if (credits) { 116 | creditsLoaded = true; 117 | credits.crew.map((person) => { 118 | if (person.known_for_department === "Directing") { 119 | director.push(person.name); 120 | } else if (person.known_for_department === "Production") { 121 | production.push(person.name); 122 | } else if (person.known_for_department === "Writing") { 123 | writing.push(person.name); 124 | } else if (person.known_for_department === "Crew") { 125 | crew.push(person.name); 126 | } 127 | return person.name; 128 | }); 129 | } 130 | 131 | if (detailsLoaded && movieDetails.runtime && movieDetails.runtime > 0) { 132 | hours = Math.floor(movieDetails.runtime / 60); 133 | minutes = movieDetails.runtime % 60; 134 | } 135 | 136 | return ( 137 |
138 | {detailsLoaded ? ( 139 |
140 |
141 |
142 | {movieDetails.title 143 | ? movieDetails.title 144 | : movieDetails.original_name} 145 |
146 |
147 | {/* {movieDetails.overview.length > 90 148 | ? movieDetails.overview.substr(0, 89) + "..." 149 | : movieDetails.overview} */} 150 | {movieDetails.overview} 151 |
152 |
153 |
154 | {seasonCount.length > 0 ? ( 155 | 168 | ) : ( 169 |
170 | )} 171 |
172 |
173 | IMDb {movieDetails.vote_average} 174 |
175 |
176 | {hours > 0 ? `${hours}h ` : ""} 177 | {minutes > 0 ? `${minutes}min` : ""} 178 |
179 |
180 | {movieDetails.first_air_date 181 | ? movieDetails.first_air_date.substr(0, 4) 182 | : ""} 183 |
184 |
185 | {movieDetails.adult ? "18+" : "ALL"} 186 |
187 |
188 | 189 |
190 |
191 |
192 |
193 | 206 |
207 |
208 | 218 |
219 |
220 | 227 |
228 |
229 | 237 |
238 |
239 | {creditsLoaded ? ( 240 |
241 |
Director
242 |
{director}
243 |
Starring
244 |
245 | {credits.cast.map((person) => { 246 | let str = ""; 247 | if (credits.cast.indexOf(person) < 11) { 248 | str = `${person.name}, `; 249 | } 250 | return str; 251 | })} 252 |
253 |
Genres
254 |
255 | {movieDetails.genres.map((genre) => { 256 | let str = `${genre.name}, `; 257 | return str; 258 | })} 259 |
260 |
261 | ) : ( 262 |
263 | )} 264 |
265 |
266 | {movieDetails.id} 271 |
272 |
273 |
274 |
275 | ) : ( 276 |
277 | )} 278 | 279 | {YoutubePlay ? ( 280 |
281 |
282 | { 286 | setYoutubePlay(false); 287 | }} 288 | color="primary" 289 | className="closeIconButton" 290 | > 291 | 292 | 293 |
294 | 295 | { 299 | alert("Youtube Not working"); 300 | }} 301 | /> 302 |
303 | ) : ( 304 |
305 | )} 306 |
307 |
308 |
{ 310 | setShow(2); 311 | }} 312 | className={detailShow === 2 ? "activeRelated" : ""} 313 | > 314 | Episodes 315 |
316 |
{ 318 | setShow(1); 319 | }} 320 | className={detailShow === 1 ? "activeRelated" : ""} 321 | > 322 | Related 323 |
324 |
{ 326 | setShow(0); 327 | }} 328 | className={detailShow === 0 ? "activeDetails" : ""} 329 | > 330 | Details 331 |
332 |
333 |
334 |
335 |
336 | {detailsLoaded && detailShow === 1 && ( 337 | 343 | )}{" "} 344 | {detailsLoaded && detailShow === 0 && ( 345 |
346 |
347 | {production.length > 0 ? ( 348 |
Production
349 | ) : ( 350 |
351 | )} 352 | {production.length > 0 ? ( 353 |
354 | {production.map((person) => { 355 | let str = `${person}, `; 356 | return str; 357 | })} 358 |
359 | ) : ( 360 |
361 | )} 362 | {writing.length > 0 ? ( 363 |
Writing
364 | ) : ( 365 |
366 | )} 367 | {writing.length > 0 ? ( 368 |
369 | {writing.map((person) => { 370 | let str = `${person}, `; 371 | return str; 372 | })} 373 |
374 | ) : ( 375 |
376 | )} 377 | {crew.length > 0 ? ( 378 |
Crew
379 | ) : ( 380 |
381 | )} 382 | {crew.length > 0 ? ( 383 |
384 | {crew.map((person) => { 385 | let str = `${person}, `; 386 | return str; 387 | })} 388 |
389 | ) : ( 390 |
391 | )} 392 |
393 |
394 | )} 395 | {episodes && 396 | episodes.length > 0 && 397 | detailShow === 2 && 398 | episodes.map((episode) => { 399 | return ( 400 | 401 | ); 402 | })} 403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 | ); 412 | }; 413 | export default TV; 414 | -------------------------------------------------------------------------------- /src/components/TV/styles.scss: -------------------------------------------------------------------------------- 1 | .movie_image { 2 | width: 950px; 3 | position: absolute; 4 | right: 0px; 5 | object-fit: contain; 6 | z-index: -1; 7 | top: 100px; 8 | } 9 | .imageDiv { 10 | position: absolute; 11 | z-index: 0; 12 | right: 0; 13 | top: 0; 14 | height: 510px; 15 | overflow: hidden; 16 | width: 950px; 17 | padding: 0px; 18 | } 19 | .divImage1 { 20 | position: absolute; 21 | top: 0; 22 | width: 950px; 23 | height: 600px; 24 | right: 0; 25 | background: linear-gradient(90deg, #0f171e 10%, rgba(15, 23, 30, 0)); 26 | } 27 | .divImage2 { 28 | position: absolute; 29 | top: 0; 30 | width: 950px; 31 | height: 600px; 32 | right: 0; 33 | background: linear-gradient(0deg, #0f171e 0, rgba(15, 23, 30, 0) 50%); 34 | } 35 | .movieInfo { 36 | position: absolute; 37 | left: 0; 38 | color: white; 39 | margin-left: 30px; 40 | z-index: 2; 41 | } 42 | .title2 { 43 | font-size: 40px; 44 | margin-top: 10px; 45 | font-weight: normal; 46 | } 47 | .overview2 { 48 | // position: absolute; 49 | // margin-top: 40px; 50 | //z-index: 2; 51 | margin-top: 20px; 52 | width: 600px; 53 | font-size: 16px; 54 | line-height: 1.5; 55 | } 56 | 57 | .moviereleaseYear { 58 | font-size: 15px; 59 | color: gray; 60 | margin-bottom: 15px; 61 | } 62 | .movierunTime { 63 | color: darkgray; 64 | font-size: 15px; 65 | } 66 | .moviefooterScreen { 67 | margin-top: 15px; 68 | display: flex; 69 | justify-content: space-between; 70 | vertical-align: middle; 71 | width: 400px; 72 | } 73 | .moviemessageIcon { 74 | color: darkgray; 75 | max-height: 18px; 76 | } 77 | .movierated { 78 | border: 1px solid darkgray; 79 | color: darkgray; 80 | font-size: 12px; 81 | padding: 3px; 82 | height: 10px; 83 | } 84 | .movierating { 85 | color: darkgray; 86 | font-size: 15px; 87 | } 88 | .people { 89 | //position: absolute; 90 | min-width: 500px; 91 | max-width: 70%; 92 | display: grid; 93 | grid-template-columns: 1.3fr 10.7fr; 94 | text-align: left; 95 | margin-top: 40px; 96 | //z-index: 2; 97 | grid-row-gap: 7px; 98 | line-height: 1.5; 99 | } 100 | .peopleHeading { 101 | color: gray; 102 | font-weight: bold; 103 | } 104 | .peopleVal { 105 | color: rgb(6, 167, 196); 106 | } 107 | .buttonGroup { 108 | display: flex; 109 | justify-content: space-evenly; 110 | // z-index: 2; 111 | //position: absolute; 112 | margin-top: 30px; 113 | width: 750px; 114 | padding: 0 auto; 115 | } 116 | 117 | .trailerIcon { 118 | transform: rotate(90deg); 119 | } 120 | .moviePlayText { 121 | color: white; 122 | margin-left: 8px; 123 | //font-size: 20px; 124 | //margin-left: 10px; 125 | } 126 | .moviePlayIcon { 127 | transform: scale(2); 128 | background-color: white; 129 | border-radius: 50%; 130 | //margin-bottom: 30px; 131 | } 132 | .movieButton { 133 | height: 50px; 134 | } 135 | .playmovieButton { 136 | transform: scale(1.5); 137 | } 138 | .relatedMovies { 139 | position: absolute; 140 | top: 650px; 141 | width: 100%; 142 | } 143 | .tabHeading { 144 | display: flex; 145 | justify-content: space-between; 146 | width: 300px; 147 | text-align: center; 148 | margin-left: 40%; 149 | top: 800px; 150 | color: gray; 151 | font-size: 25px; 152 | cursor: pointer; 153 | } 154 | 155 | .activeRelated { 156 | border-bottom: 2px solid white; 157 | color: white; 158 | } 159 | .activeDetails { 160 | border-bottom: 2px solid white; 161 | color: white; 162 | } 163 | .detailsCrew { 164 | margin-left: 30px; 165 | } 166 | .playTrailerVideo { 167 | position: absolute; 168 | top: 0; 169 | left: 0; 170 | z-index: 10; 171 | min-height: 100%; 172 | min-width: 100%; 173 | background-color: rgba(220, 220, 220, 0.5); 174 | transition: background-color 1s ease-in; 175 | padding-top: 100px; 176 | } 177 | .closeButtonDiv { 178 | margin-left: 90%; 179 | } 180 | .closeIconButton { 181 | transform: scale(2); 182 | } 183 | .selectTag { 184 | width: 140px; 185 | height: 40px; 186 | text-align: center; 187 | color: white; 188 | background-color: #425265; 189 | outline: none; 190 | border: none; 191 | font-size: 18px; 192 | padding-left: 20px; 193 | cursor: pointer; 194 | overflow: scroll; 195 | } 196 | .selectTag:hover { 197 | background-color: #0f171e; 198 | opacity: 0.7; 199 | :fullscreen { 200 | opacity: 0.2; 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /src/homeRequests.js: -------------------------------------------------------------------------------- 1 | const API_KEY = "989a8027930013244e3c2af17088dcac"; 2 | 3 | const homeRequests = [ 4 | { 5 | title: "Comedy", 6 | url: `/discover/movie?api_key=${API_KEY}&with_genres=35`, 7 | media: "movie", 8 | }, 9 | { 10 | title: "Action", 11 | url: `/discover/movie?api_key=${API_KEY}&with_genres=28`, 12 | media: "movie", 13 | }, 14 | { 15 | title: "Horror", 16 | url: `/discover/movie?api_key=${API_KEY}&with_genres=27`, 17 | media: "movie", 18 | }, 19 | { 20 | title: "Adventure TV Shows", 21 | url: `/discover/tv?api_key=${API_KEY}&with_genres=12`, 22 | media: "tv", 23 | }, 24 | { 25 | title: "Popular in your Region TV Shows", 26 | url: `/discover/tv?api_key=${API_KEY}®ion=IN`, 27 | media: "tv", 28 | }, 29 | ]; 30 | 31 | export default homeRequests; 32 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | background-color: #0f171e; 9 | } 10 | 11 | code { 12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 13 | monospace; 14 | } 15 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import * as serviceWorker from './serviceWorker'; 6 | import { initializeApp } from "firebase/app"; 7 | import { getAnalytics } from "firebase/analytics"; 8 | // TODO: Add SDKs for Firebase products that you want to use 9 | // https://firebase.google.com/docs/web/setup#available-libraries 10 | 11 | // Your web app's Firebase configuration 12 | // For Firebase JS SDK v7.20.0 and later, measurementId is optional 13 | const firebaseConfig = { 14 | apiKey: "AIzaSyDO0WWJhETy25tIVwRrhFtt52msxFKMis8", 15 | authDomain: "prime-clone-e1de6.firebaseapp.com", 16 | databaseURL: "https://prime-clone-e1de6.firebaseio.com", 17 | projectId: "prime-clone-e1de6", 18 | storageBucket: "prime-clone-e1de6.appspot.com", 19 | messagingSenderId: "536067131178", 20 | appId: "1:536067131178:web:f9642c8a945f59209c4053", 21 | measurementId: "G-ELR0K1QTZ4" 22 | }; 23 | 24 | // Initialize Firebase 25 | const app = initializeApp(firebaseConfig); 26 | const analytics = getAnalytics(app); 27 | 28 | ReactDOM.render( 29 | 30 | 31 | , 32 | document.getElementById('root') 33 | ); 34 | 35 | // If you want your app to work offline and load faster, you can change 36 | // unregister() to register() below. Note this comes with some pitfalls. 37 | // Learn more about service workers: https://bit.ly/CRA-PWA 38 | serviceWorker.unregister(); 39 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/requests.js: -------------------------------------------------------------------------------- 1 | const API_KEY = "989a8027930013244e3c2af17088dcac"; 2 | 3 | const requests = [ 4 | { 5 | title: "Discover", 6 | url: `/discover/movie?api_key=${API_KEY}`, 7 | media: "movie", 8 | }, 9 | { 10 | title: "Comedy", 11 | url: `/discover/movie?api_key=${API_KEY}&with_genres=35`, 12 | media: "movie", 13 | }, 14 | { 15 | title: "Action", 16 | url: `/discover/movie?api_key=${API_KEY}&with_genres=28`, 17 | media: "movie", 18 | }, 19 | { 20 | title: "Adventure", 21 | url: `/discover/movie?api_key=${API_KEY}&with_genres=12`, 22 | media: "movie", 23 | }, 24 | { 25 | title: "Science Fiction", 26 | url: `/discover/movie?api_key=${API_KEY}&with_genres=878`, 27 | media: "movie", 28 | }, 29 | { 30 | title: "Horror", 31 | url: `/discover/movie?api_key=${API_KEY}&with_genres=27`, 32 | media: "movie", 33 | }, 34 | { 35 | title: "Drama", 36 | url: `/discover/movie?api_key=${API_KEY}&with_genres=18`, 37 | media: "movie", 38 | }, 39 | { 40 | title: "Popular in your Region", 41 | url: `/discover/movie?api_key=${API_KEY}®ion=IN`, 42 | media: "movie", 43 | }, 44 | { 45 | title: "Will Smith's Hits", 46 | url: `/discover/movie?api_key=${API_KEY}&with_people=2888`, 47 | media: "movie", 48 | }, 49 | { 50 | title: "Thriller", 51 | url: `/discover/movie?api_key=${API_KEY}&with_genres=53`, 52 | media: "movie", 53 | }, 54 | { 55 | title: "Crime", 56 | url: `/discover/movie?api_key=${API_KEY}&with_genres=80`, 57 | media: "movie", 58 | }, 59 | { 60 | title: "Short Films", 61 | url: `/discover/movie?api_key=${API_KEY}&with_runtime.lte=70`, 62 | media: "movie", 63 | }, 64 | ]; 65 | 66 | export default requests; 67 | -------------------------------------------------------------------------------- /src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.0/8 are considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl, { 104 | headers: { 'Service-Worker': 'script' }, 105 | }) 106 | .then(response => { 107 | // Ensure service worker exists, and that we really are getting a JS file. 108 | const contentType = response.headers.get('content-type'); 109 | if ( 110 | response.status === 404 || 111 | (contentType != null && contentType.indexOf('javascript') === -1) 112 | ) { 113 | // No service worker found. Probably a different app. Reload the page. 114 | navigator.serviceWorker.ready.then(registration => { 115 | registration.unregister().then(() => { 116 | window.location.reload(); 117 | }); 118 | }); 119 | } else { 120 | // Service worker found. Proceed as normal. 121 | registerValidSW(swUrl, config); 122 | } 123 | }) 124 | .catch(() => { 125 | console.log( 126 | 'No internet connection found. App is running in offline mode.' 127 | ); 128 | }); 129 | } 130 | 131 | export function unregister() { 132 | if ('serviceWorker' in navigator) { 133 | navigator.serviceWorker.ready 134 | .then(registration => { 135 | registration.unregister(); 136 | }) 137 | .catch(error => { 138 | console.error(error.message); 139 | }); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom/extend-expect'; 6 | -------------------------------------------------------------------------------- /src/tvRequests.js: -------------------------------------------------------------------------------- 1 | const API_KEY = "989a8027930013244e3c2af17088dcac"; 2 | 3 | const tvrequests = [ 4 | { 5 | title: "Discover TV Shows", 6 | url: `/discover/tv?api_key=${API_KEY}`, 7 | media: "tv", 8 | }, 9 | { 10 | title: "Comedy TV Shows", 11 | url: `/discover/tv?api_key=${API_KEY}&with_genres=35`, 12 | media: "tv", 13 | }, 14 | { 15 | title: "Adventure TV Shows", 16 | url: `/discover/tv?api_key=${API_KEY}&with_genres=12`, 17 | media: "tv", 18 | }, 19 | { 20 | title: "Popular in your Region TV Shows", 21 | url: `/discover/tv?api_key=${API_KEY}®ion=IN`, 22 | media: "tv", 23 | }, 24 | ]; 25 | export default tvrequests; 26 | --------------------------------------------------------------------------------