├── .eslintcache
├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
└── src
├── App.css
├── App.js
├── Banner.css
├── Banner.js
├── Nav.css
├── Nav.js
├── Row.css
├── Row.js
├── axios.js
├── index.css
├── index.js
├── reportWebVitals.js
└── requests.js
/.eslintcache:
--------------------------------------------------------------------------------
1 | [{"C:\\Users\\shaon\\OneDrive\\Desktop\\react\\netflix_clone\\src\\index.js":"1","C:\\Users\\shaon\\OneDrive\\Desktop\\react\\netflix_clone\\src\\App.js":"2","C:\\Users\\shaon\\OneDrive\\Desktop\\react\\netflix_clone\\src\\reportWebVitals.js":"3","C:\\Users\\shaon\\OneDrive\\Desktop\\react\\netflix_clone\\src\\Row.js":"4","C:\\Users\\shaon\\OneDrive\\Desktop\\react\\netflix_clone\\src\\requests.js":"5","C:\\Users\\shaon\\OneDrive\\Desktop\\react\\netflix_clone\\src\\axios.js":"6","C:\\Users\\shaon\\OneDrive\\Desktop\\react\\netflix_clone\\src\\Banner.js":"7","C:\\Users\\shaon\\OneDrive\\Desktop\\react\\netflix_clone\\src\\Nav.js":"8"},{"size":500,"mtime":499162500000,"results":"9","hashOfConfig":"10"},{"size":920,"mtime":1610881132744,"results":"11","hashOfConfig":"10"},{"size":362,"mtime":499162500000,"results":"12","hashOfConfig":"10"},{"size":2049,"mtime":1610911449178,"results":"13","hashOfConfig":"10"},{"size":780,"mtime":1610871658591,"results":"14","hashOfConfig":"10"},{"size":170,"mtime":1610801385143,"results":"15","hashOfConfig":"10"},{"size":1556,"mtime":1610910824625,"results":"16","hashOfConfig":"10"},{"size":1082,"mtime":1610883878178,"results":"17","hashOfConfig":"10"},{"filePath":"18","messages":"19","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"20"},"1x8l7ke",{"filePath":"21","messages":"22","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"20"},{"filePath":"23","messages":"24","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"20"},{"filePath":"25","messages":"26","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"27","messages":"28","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"20"},{"filePath":"29","messages":"30","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"20"},{"filePath":"31","messages":"32","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"33","messages":"34","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"20"},"C:\\Users\\shaon\\OneDrive\\Desktop\\react\\netflix_clone\\src\\index.js",[],["35","36"],"C:\\Users\\shaon\\OneDrive\\Desktop\\react\\netflix_clone\\src\\App.js",[],"C:\\Users\\shaon\\OneDrive\\Desktop\\react\\netflix_clone\\src\\reportWebVitals.js",[],"C:\\Users\\shaon\\OneDrive\\Desktop\\react\\netflix_clone\\src\\Row.js",[],"C:\\Users\\shaon\\OneDrive\\Desktop\\react\\netflix_clone\\src\\requests.js",[],"C:\\Users\\shaon\\OneDrive\\Desktop\\react\\netflix_clone\\src\\axios.js",[],"C:\\Users\\shaon\\OneDrive\\Desktop\\react\\netflix_clone\\src\\Banner.js",[],"C:\\Users\\shaon\\OneDrive\\Desktop\\react\\netflix_clone\\src\\Nav.js",[],{"ruleId":"37","replacedBy":"38"},{"ruleId":"39","replacedBy":"40"},"no-native-reassign",["41"],"no-negated-in-lhs",["42"],"no-global-assign","no-unsafe-negation"]
--------------------------------------------------------------------------------
/.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 | ### `npm i react-youtube`
2 | ### `npm i movie-trailer`
3 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "netflix_clone",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.11.9",
7 | "@testing-library/react": "^11.2.3",
8 | "@testing-library/user-event": "^12.6.0",
9 | "axios": "^0.21.1",
10 | "movie-trailer": "^2.0.7",
11 | "prop-types": "^15.7.2",
12 | "react": "^17.0.1",
13 | "react-axios": "^2.0.4",
14 | "react-dom": "^17.0.1",
15 | "react-scripts": "4.0.1",
16 | "react-youtube": "^7.13.0",
17 | "web-vitals": "^0.2.4"
18 | },
19 | "scripts": {
20 | "start": "react-scripts start",
21 | "build": "react-scripts build",
22 | "test": "react-scripts test",
23 | "eject": "react-scripts eject"
24 | },
25 | "eslintConfig": {
26 | "extends": [
27 | "react-app",
28 | "react-app/jest"
29 | ]
30 | },
31 | "browserslist": {
32 | "production": [
33 | ">0.2%",
34 | "not dead",
35 | "not op_mini all"
36 | ],
37 | "development": [
38 | "last 1 chrome version",
39 | "last 1 firefox version",
40 | "last 1 safari version"
41 | ]
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rkshaon/react_netflix_clone/f00c6df8b6b3a3d248e2ef75870870b8344a2984/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | Netflix Clone
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rkshaon/react_netflix_clone/f00c6df8b6b3a3d248e2ef75870870b8344a2984/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rkshaon/react_netflix_clone/f00c6df8b6b3a3d248e2ef75870870b8344a2984/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 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | }
4 | .app {
5 | background-color: #111;
6 | }
7 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './App.css';
3 | import Row from './Row';
4 | import Banner from './Banner';
5 | import Nav from './Nav';
6 | import requests from './requests';
7 |
8 | function App() {
9 | return (
10 |
11 |
12 |
13 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | );
27 | }
28 |
29 | export default App;
30 |
--------------------------------------------------------------------------------
/src/Banner.css:
--------------------------------------------------------------------------------
1 | .banner {
2 | color: white;
3 | object-fit: contain;
4 | height: 448px;
5 | }
6 | .banner__contents {
7 | margin-left: 30px;
8 | padding-top: 144px;
9 | height: 190px;
10 | }
11 | .banner__title {
12 | font-size: 3rem;
13 | font-weight: 800;
14 | padding-bottom: 0.3rem;
15 | }
16 | .banner_description {
17 | width: 45rem;
18 | line-height: 1.3;
19 | padding-top: 1rem;
20 | font-size: 0.8rem;
21 | max-width: 360px;
22 | height: 80px;
23 | }
24 | .banner__button {
25 | cursor: pointer;
26 | color: #fff;
27 | outline: none;
28 | border: none;
29 | font-weight: 700;
30 | border-radius: 0.2vw;
31 | padding-left: 2rem;
32 | padding-right: 2rem;
33 | margin-right: 1rem;
34 | padding-top: 0.5rem;
35 | background-color: rgba(51, 51, 51, 0.5);
36 | padding-bottom: 0.5rem;
37 | }
38 | .banner__button:hover {
39 | color: #000;
40 | background-color: #e6e6e6;
41 | transition: all 0.2s;
42 | }
43 | .banner__fadeBottom {
44 | height: 7.4rem;
45 | background-image: linear-gradient(
46 | 180deg,
47 | transparent,
48 | rgba(37, 37, 37, 0.61),
49 | #111
50 | );
51 | }
52 |
--------------------------------------------------------------------------------
/src/Banner.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import axios from './axios';
3 | import requests from './requests';
4 | import "./Banner.css";
5 |
6 | function Banner() {
7 | const [movie, setMovie] = useState([]);
8 |
9 | useEffect(() => {
10 | async function fetchData() {
11 | const request = await axios.get(requests.fetchNetflixOriginals);
12 | setMovie(request.data.results[Math.floor(Math.random() * request.data.results.length - 1)]);
13 | // console.log(request.data.results[Math.floor(Math.random() * request.data.results.length - 1)]);
14 | return request;
15 | }
16 | fetchData();
17 | }, []);
18 |
19 | function truncate(str, n) {
20 | return str?.length > n ? str.substr(0, n-1) + "..." : str;
21 | }
22 |
23 | return(
24 |
49 | )
50 | }
51 |
52 | export default Banner;
53 |
--------------------------------------------------------------------------------
/src/Nav.css:
--------------------------------------------------------------------------------
1 | .nav {
2 | position: fixed;
3 | top: 0;
4 | display: flex;
5 | z-index: 1;
6 | width: 100%;
7 | height: 30px;
8 | padding: 20px;
9 | justify-content: space-between;
10 | /* animation */
11 | transition-timing-function: ease-in;
12 | transition: all 0.5s;
13 | }
14 | .nav__black {
15 | background-color: #111;
16 | }
17 | .nav__logo {
18 | position: fixed;
19 | left: 20px;
20 | width: 80px;
21 | object-fit: contain;
22 | }
23 | .nav__avatar {
24 | position: fixed;
25 | right: 20px;
26 | width: 30px;
27 | object-fit: contain;
28 | }
29 |
--------------------------------------------------------------------------------
/src/Nav.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import './Nav.css';
3 |
4 | function Nav() {
5 | const [show, handleShow] = useState(false);
6 |
7 | useEffect(() => {
8 | window.addEventListener("scroll", () => {
9 | if (window.scrollY > 100) {
10 | handleShow(true);
11 | } else {
12 | handleShow(false);
13 | }
14 | });
15 | return () => {
16 | window.removeEventListener("srcoll");
17 | }
18 | }, []);
19 |
20 | return(
21 |
22 |

27 |

33 |
34 | )
35 | }
36 |
37 | export default Nav;
38 |
--------------------------------------------------------------------------------
/src/Row.css:
--------------------------------------------------------------------------------
1 | .row {
2 | color: #fff;
3 | margin-left: 20px;
4 | }
5 | .row__posters {
6 | display: flex;
7 | overflow-y: hidden;
8 | overflow-x: scroll;
9 | padding: 20px;
10 | }
11 | .row__posters::-webkit-scrollbar {
12 | display: none;
13 | }
14 | .row__poster {
15 | object-fit: contain;
16 | width: 100%;
17 | max-height: 100px;
18 | transition: transform 450ms;
19 | margin-right: 10px;
20 | }
21 | .row__poster:hover {
22 | transform: scale(1.08);
23 | }
24 | .row__posterLarge {
25 | max-height: 250px;
26 | }
27 | .row__posterLarge:hover {
28 | transform: scale(1.09);
29 | }
30 |
--------------------------------------------------------------------------------
/src/Row.js:
--------------------------------------------------------------------------------
1 | // component
2 | import React, { useState, useEffect } from 'react';
3 | import instance from './axios';
4 | import "./Row.css";
5 | import YouTube from 'react-youtube';
6 | import movieTrailer from 'movie-trailer';
7 |
8 | const base_url = "https://image.tmdb.org/t/p/original/";
9 |
10 | function Row({ title, fetchURL, isLargeRow }) {
11 | const [movies, setMovies] = useState([]);
12 | const [trailerUrl, setTrailerUrl] = useState("");
13 |
14 | useEffect(() => {
15 | async function fetchData() {
16 | const request = await instance.get(fetchURL); // the url https://api.themoviedb.org/3 + fetchURL
17 | setMovies(request.data.results);
18 | return request;
19 | }
20 | fetchData();
21 | }, [fetchURL]);
22 |
23 | const opts = {
24 | height: "390",
25 | width: "100%",
26 | playerVars: {
27 | autoplay: 1,
28 | },
29 | };
30 |
31 | const handleClick = (movie) => {
32 | if (trailerUrl) {
33 | setTrailerUrl('');
34 | console.log('trailer closed');
35 | } else {
36 | console.log('trailer about to open');
37 | movieTrailer(movie?.name || "")
38 | .then(url => {
39 | console.log('enter trailer');
40 | const urlParams = new URLSearchParams(new URL(url).search);
41 | setTrailerUrl(urlParams.get('v'));
42 | // console.log(urlParams.get('v'));
43 | })
44 | .catch(error => console.log(error));
45 | console.log('hopefully trailer set');
46 | // function from movie-trailer library, it search movie trailer from youtube
47 | }
48 | }
49 | console.log(trailerUrl);
50 |
51 | return(
52 |
53 |
{title}
54 |
55 | {movies.map((movie) => {
56 | return
![]()
handleClick(movie)}
60 | src={`${base_url}${isLargeRow ? movie.poster_path : movie.backdrop_path}`}
61 | alt={movie.name}
62 | />
63 | })}
64 |
65 | {trailerUrl &&
}
66 |
67 | )
68 | }
69 |
70 | export default Row;
71 |
--------------------------------------------------------------------------------
/src/axios.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | // base url of make requests
4 | const instance = axios.create({
5 | baseURL: "https://api.themoviedb.org/3",
6 | });
7 |
8 | export default instance;
9 |
--------------------------------------------------------------------------------
/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 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/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 reportWebVitals from './reportWebVitals';
6 |
7 | ReactDOM.render(
8 |
9 |
10 | ,
11 | document.getElementById('root')
12 | );
13 |
14 | // If you want to start measuring performance in your app, pass a function
15 | // to log results (for example: reportWebVitals(console.log))
16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
17 | reportWebVitals();
18 |
--------------------------------------------------------------------------------
/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/src/requests.js:
--------------------------------------------------------------------------------
1 | // functional module
2 |
3 | // tmdb api key
4 | const API_KEY = "f956f57d239cc98269c50138d916d729";
5 |
6 | // object of request links
7 | const requests = {
8 | fetchTrending: `/trending/all/week?api_key=${API_KEY}&language=en-US`,
9 | fetchNetflixOriginals: `/discover/tv?api_key=${API_KEY}&with_networks=213`,
10 | fetchTopRated: `/movie/top_rated?api_key=${API_KEY}&language=en-US`,
11 | fetchActionMovies: `/discover/movie?api_key=${API_KEY}&with_genres=28`,
12 | fetchComedyMovies: `/discover/movie?api_key=${API_KEY}&with_genres=35`,
13 | fetchHorrorMovies: `/discover/movie?api_key=${API_KEY}&with_genres=27`,
14 | fetchRomanceMovies: `/discover/movie?api_key=${API_KEY}&with_genres=10749`,
15 | fetchDocumentaries: `/discover/movie?api_key=${API_KEY}&with_genres=99`,
16 | }
17 |
18 | export default requests;
19 |
--------------------------------------------------------------------------------