├── .gitignore ├── README.md ├── favicon.ico ├── package.json ├── public ├── _redirects ├── favicon.ico ├── favicon.png ├── index.html ├── manifest.json └── robots.txt ├── src ├── apis │ ├── 2embed.js │ └── tmdb.js ├── assets │ └── images │ │ ├── .webp │ │ ├── avatar.webp │ │ ├── hero-banners │ │ ├── la-casa.webp │ │ ├── spider-man.webp │ │ ├── squid-game-banner.webp │ │ └── stranger-things.webp │ │ ├── hero-slider │ │ ├── la-casa-bg.webp │ │ ├── spider-man.webp │ │ ├── squid-game-bg.webp │ │ └── stranger-things-bg.webp │ │ ├── icon.png │ │ ├── logo.svg │ │ └── work-bg.jpg ├── components │ ├── App.jsx │ ├── CastSlider.jsx │ ├── EpisodeItem.jsx │ ├── GridTest.jsx │ ├── HeroSlider.jsx │ ├── HomePage.jsx │ ├── HomeTrendings.jsx │ ├── LoadWrapper.jsx │ ├── MainMenu.jsx │ ├── MobileNavMenu.jsx │ ├── Mouse.jsx │ ├── MovieDetails.jsx │ ├── MovieOnSliderView.jsx │ ├── MoviePageHero.jsx │ ├── MovieSerieView.jsx │ ├── MoviesPage.jsx │ ├── Navbar.jsx │ ├── NowPlayingSlider.jsx │ ├── PageHeroSlide.jsx │ ├── PageHeroSlider.jsx │ ├── Pagination.jsx │ ├── PeoplePage.jsx │ ├── PersonPage.jsx │ ├── PopularSlider.jsx │ ├── ResultsContainer.jsx │ ├── ReviewItem.jsx │ ├── SearchPage.jsx │ ├── SeasonItem.jsx │ ├── SeasonPageHero.jsx │ ├── SerieDetails.jsx │ ├── SeriePageHero.jsx │ ├── SerieSeasonPage.jsx │ ├── SideBarFilter.jsx │ ├── TopRatedSlider.jsx │ ├── TvShowsPage.jsx │ ├── VideoPlayerArea.jsx │ ├── WatchMovie.jsx │ ├── WatchSerie.jsx │ ├── WorkScore.jsx │ ├── WorksClassificationBtns.jsx │ ├── WorksFilter.jsx │ ├── WorksSlider.jsx │ └── _404.jsx ├── helpers │ └── scrollToTop.js ├── index.js ├── redux │ ├── actions │ │ ├── changeIsLoggedIn.js │ │ ├── clear.js │ │ ├── filterByGenre.js │ │ ├── filterByLanguage.js │ │ ├── filterByMediaType.js │ │ ├── getMovieById.js │ │ ├── getNowPlayingMovies.js │ │ ├── getNowPlayingTv.js │ │ ├── getOnTheAirTv.js │ │ ├── getPeople.js │ │ ├── getPersonById.js │ │ ├── getPopularMovies.js │ │ ├── getPopularPeople.js │ │ ├── getPopularTv.js │ │ ├── getSerieById.js │ │ ├── getSerieEpisodes.js │ │ ├── getTmdbTrendings.js │ │ ├── getTopMovies.js │ │ ├── getTopTv.js │ │ ├── getUpcomingMovies.js │ │ ├── index.js │ │ ├── initFilteredList.js │ │ ├── searchTMDB.js │ │ ├── sortDateAscending.js │ │ ├── sortDateDescending.js │ │ ├── sortRateAscending.js │ │ ├── sortRateDescending.js │ │ ├── sortTitleA_Z.js │ │ └── sortTitleZ_A.js │ └── reducers │ │ ├── Episodes.js │ │ ├── Filter.js │ │ ├── Movie.js │ │ ├── Movies.js │ │ ├── Now_Playing.js │ │ ├── People.js │ │ ├── Person.js │ │ ├── Populars.js │ │ ├── Search.js │ │ ├── Serie.js │ │ ├── Series.js │ │ ├── TMDB_Trendings.js │ │ ├── Top_Rated.js │ │ ├── index.js │ │ └── userLogin.js └── styles │ ├── episode-item.sass │ ├── grid_test.sass │ ├── hero-slider.sass │ ├── home_trendings.sass │ ├── load-wrapper.sass │ ├── main-menu.sass │ ├── mob-nav-menu.sass │ ├── mouse.sass │ ├── movie_details_page.sass │ ├── movie_serie_view.sass │ ├── movie_slider_view.sass │ ├── movies-page.sass │ ├── navbar.sass │ ├── normalize.sass │ ├── pagination.sass │ ├── person-page.sass │ ├── review-item.sass │ ├── score.sass │ ├── search-area.sass │ ├── slider-bg-white.sass │ ├── variables.sass │ ├── works-filter.sass │ ├── works_classification_btns.sass │ └── works_slider.sass └── 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 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `npm start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser. 13 | 14 | The page will reload when you make changes.\ 15 | You may also see any lint errors in the console. 16 | 17 | ### `npm test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `npm run build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `npm run eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can't go back!** 35 | 36 | If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. 39 | 40 | You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | 48 | ### Code Splitting 49 | 50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 51 | 52 | ### Analyzing the Bundle Size 53 | 54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 55 | 56 | ### Making a Progressive Web App 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 59 | 60 | ### Advanced Configuration 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 63 | 64 | ### Deployment 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 67 | 68 | ### `npm run build` fails to minify 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 71 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enjoycod1ng/netflix-clone/163fb690e933a8f32ff2d8ef08ea97e83084a26b/favicon.ico -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "netflix", 3 | "version": "0.1.0", 4 | "private": true, 5 | "homepage": "https://lotus-netflix-clone.vercel.app", 6 | "dependencies": { 7 | "@testing-library/jest-dom": "^5.16.1", 8 | "@testing-library/react": "^12.1.2", 9 | "@testing-library/user-event": "^13.5.0", 10 | "axios": "^0.24.0", 11 | "bootstrap": "^5.1.3", 12 | "lodash": "^4.17.21", 13 | "react": "^17.0.2", 14 | "react-dom": "^17.0.2", 15 | "react-placeholder": "^4.1.0", 16 | "react-redux": "^7.2.6", 17 | "react-router-dom": "^6.2.1", 18 | "react-scripts": "5.0.0", 19 | "redux": "^4.1.2", 20 | "redux-thunk": "^2.4.1", 21 | "sass": "^1.45.1", 22 | "swiper": "^7.4.1", 23 | "web-vitals": "^2.1.2" 24 | }, 25 | "scripts": { 26 | "start": "react-scripts start", 27 | "build": "react-scripts build", 28 | "test": "react-scripts test", 29 | "eject": "react-scripts eject", 30 | "predeploy": "npm run build", 31 | "deploy": "gh-pages -d build" 32 | }, 33 | "eslintConfig": { 34 | "extends": [ 35 | "react-app", 36 | "react-app/jest" 37 | ] 38 | }, 39 | "browserslist": { 40 | "production": [ 41 | ">0.2%", 42 | "not dead", 43 | "not op_mini all" 44 | ], 45 | "development": [ 46 | "last 1 chrome version", 47 | "last 1 firefox version", 48 | "last 1 safari version" 49 | ] 50 | }, 51 | "devDependencies": { 52 | "gh-pages": "^3.2.3" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /public/_redirects: -------------------------------------------------------------------------------- 1 | /* /index.html 200 2 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enjoycod1ng/netflix-clone/163fb690e933a8f32ff2d8ef08ea97e83084a26b/public/favicon.ico -------------------------------------------------------------------------------- /public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enjoycod1ng/netflix-clone/163fb690e933a8f32ff2d8ef08ea97e83084a26b/public/favicon.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 23 | 24 | 28 | 29 | 35 | NETFLIX | Watch Movies And TV Shows Online 36 | 37 | 38 | 39 |
40 |
41 |
42 | 43 | 44 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "NETFLIX", 3 | "name": "netflix clone react js application", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "favicon.png", 12 | "type": "image/png", 13 | "sizes": "64x64" 14 | } 15 | ], 16 | "start_url": ".", 17 | "display": "standalone", 18 | "theme_color": "#FF2530", 19 | "background_color": "#151515" 20 | } 21 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/apis/2embed.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | export default axios.create({ 4 | baseURL: "https://www.2embed.ru/embed/tmdb", 5 | }); 6 | -------------------------------------------------------------------------------- /src/apis/tmdb.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | const api_key = "d470a238b9aab25e3b6df09a4413e353"; 4 | 5 | export default axios.create({ 6 | baseURL: "https://api.themoviedb.org/3", 7 | params: { 8 | api_key, 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /src/assets/images/.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enjoycod1ng/netflix-clone/163fb690e933a8f32ff2d8ef08ea97e83084a26b/src/assets/images/.webp -------------------------------------------------------------------------------- /src/assets/images/avatar.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enjoycod1ng/netflix-clone/163fb690e933a8f32ff2d8ef08ea97e83084a26b/src/assets/images/avatar.webp -------------------------------------------------------------------------------- /src/assets/images/hero-banners/la-casa.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enjoycod1ng/netflix-clone/163fb690e933a8f32ff2d8ef08ea97e83084a26b/src/assets/images/hero-banners/la-casa.webp -------------------------------------------------------------------------------- /src/assets/images/hero-banners/spider-man.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enjoycod1ng/netflix-clone/163fb690e933a8f32ff2d8ef08ea97e83084a26b/src/assets/images/hero-banners/spider-man.webp -------------------------------------------------------------------------------- /src/assets/images/hero-banners/squid-game-banner.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enjoycod1ng/netflix-clone/163fb690e933a8f32ff2d8ef08ea97e83084a26b/src/assets/images/hero-banners/squid-game-banner.webp -------------------------------------------------------------------------------- /src/assets/images/hero-banners/stranger-things.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enjoycod1ng/netflix-clone/163fb690e933a8f32ff2d8ef08ea97e83084a26b/src/assets/images/hero-banners/stranger-things.webp -------------------------------------------------------------------------------- /src/assets/images/hero-slider/la-casa-bg.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enjoycod1ng/netflix-clone/163fb690e933a8f32ff2d8ef08ea97e83084a26b/src/assets/images/hero-slider/la-casa-bg.webp -------------------------------------------------------------------------------- /src/assets/images/hero-slider/spider-man.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enjoycod1ng/netflix-clone/163fb690e933a8f32ff2d8ef08ea97e83084a26b/src/assets/images/hero-slider/spider-man.webp -------------------------------------------------------------------------------- /src/assets/images/hero-slider/squid-game-bg.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enjoycod1ng/netflix-clone/163fb690e933a8f32ff2d8ef08ea97e83084a26b/src/assets/images/hero-slider/squid-game-bg.webp -------------------------------------------------------------------------------- /src/assets/images/hero-slider/stranger-things-bg.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enjoycod1ng/netflix-clone/163fb690e933a8f32ff2d8ef08ea97e83084a26b/src/assets/images/hero-slider/stranger-things-bg.webp -------------------------------------------------------------------------------- /src/assets/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enjoycod1ng/netflix-clone/163fb690e933a8f32ff2d8ef08ea97e83084a26b/src/assets/images/icon.png -------------------------------------------------------------------------------- /src/assets/images/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/work-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enjoycod1ng/netflix-clone/163fb690e933a8f32ff2d8ef08ea97e83084a26b/src/assets/images/work-bg.jpg -------------------------------------------------------------------------------- /src/components/App.jsx: -------------------------------------------------------------------------------- 1 | /// MODULES 2 | import React from "react"; 3 | import { BrowserRouter, Routes, Route } from "react-router-dom"; 4 | 5 | /// COMPONENTS 6 | import Navbar from "./Navbar"; 7 | import GridTest from "./GridTest"; 8 | import MainMenu from "./MainMenu"; 9 | import HomePage from "./HomePage"; 10 | import MoviesPage from "./MoviesPage"; 11 | import TvShowsPage from "./TvShowsPage"; 12 | import MovieDetails from "./MovieDetails"; 13 | import SerieDetails from "./SerieDetails"; 14 | import SerieSeasonPage from "./SerieSeasonPage"; 15 | import WatchMovie from "./WatchMovie"; 16 | import WatchSerie from "./WatchSerie"; 17 | import PeoplePage from "./PeoplePage"; 18 | import PersonPage from "./PersonPage"; 19 | import SearchPage from "./SearchPage"; 20 | import _404 from "./_404"; 21 | 22 | export default (function App() { 23 | return ( 24 | 25 | {/* */} 26 | 27 | 28 | } /> 29 | } /> 30 | 31 | } /> 32 | } /> 33 | } /> 34 | } /> 35 | 36 | } /> 37 | } /> 38 | } /> 39 | } /> 40 | 41 | } /> 42 | } /> 43 | 44 | } /> 45 | } /> 46 | 47 | } 51 | /> 52 | 53 | } /> 54 | } 57 | /> 58 | 59 | } /> 60 | }> 61 | 62 | 63 | 64 | ); 65 | }); 66 | -------------------------------------------------------------------------------- /src/components/CastSlider.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | // import Swiper core and required modules 4 | import { Navigation, Pagination, Autoplay, Scrollbar } from "swiper"; 5 | import { Swiper, SwiperSlide } from "swiper/react"; 6 | import MovieSerieView from "./MovieSerieView"; 7 | 8 | // Import Swiper styles 9 | import "swiper/css"; 10 | import "swiper/css/navigation"; 11 | import "swiper/css/pagination"; 12 | import "swiper/css/scrollbar"; 13 | 14 | export default function CastSlider({ cast, title }) { 15 | const renderList = () => { 16 | return cast?.map((person) => { 17 | return ( 18 | 19 | 20 | 21 | ); 22 | }); 23 | }; 24 | return ( 25 | <> 26 |
Top billed cast
27 | {cast.length ? ( 28 | 51 | {renderList()} 52 | 53 | ) : ( 54 | 55 | We don't have any information for {title} cast. 56 | 57 | )} 58 | 59 | ); 60 | } 61 | -------------------------------------------------------------------------------- /src/components/EpisodeItem.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link } from "react-router-dom"; 3 | 4 | import "../styles/episode-item.sass"; 5 | 6 | export default function EpisodeItem({ episode, id, season }) { 7 | return ( 8 |
9 |
10 |
11 | 15 | 16 | 17 | episode-img 25 |
26 |
27 | 31 | {episode.episode_number} {episode.name} 32 | 33 |

{episode.air_date}

34 | {episode.overview} 35 |
36 |
37 |
38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /src/components/GridTest.jsx: -------------------------------------------------------------------------------- 1 | import React, { useRef, useState } from "react"; 2 | import "../styles/grid_test.sass"; 3 | export default function GridTest() { 4 | const [gridShow, setGridShow] = useState(false); 5 | return ( 6 | <> 7 |
8 | { 12 | setGridShow(!gridShow); 13 | }} 14 | /> 15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
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 | 59 | ); 60 | } 61 | -------------------------------------------------------------------------------- /src/components/HeroSlider.jsx: -------------------------------------------------------------------------------- 1 | /// MODULES 2 | import { Link } from "react-router-dom"; 3 | import { Swiper, SwiperSlide } from "swiper/react"; 4 | import { Navigation, Pagination, Autoplay } from "swiper"; 5 | 6 | /// STYLES 7 | import "swiper/css"; 8 | import "swiper/css/navigation"; 9 | import "swiper/css/pagination"; 10 | import "../styles/hero-slider.sass"; 11 | 12 | /// IMAGES 13 | import netflix_icon from "../assets/images/icon.png"; 14 | import la_casa_bg from "../assets/images/hero-slider/la-casa-bg.webp"; 15 | import la_casa_banner from "../assets/images/hero-banners/la-casa.webp"; 16 | import spider_man_bg from "../assets/images/hero-slider/spider-man.webp"; 17 | import squid_game_bg from "../assets/images/hero-slider/squid-game-bg.webp"; 18 | import spider_man_banner from "../assets/images/hero-banners/spider-man.webp"; 19 | import squid_game_banner from "../assets/images/hero-banners/squid-game-banner.webp"; 20 | 21 | export default function HeroSlider() { 22 | return ( 23 | 36 | 37 |
38 | slider-bg 39 |
40 |
41 |
42 |
43 |
44 | netflix 50 | SERIES 51 |
52 |
53 | la_casa_banner 59 |
60 |
61 | 2017 62 | 16 63 | 3 seasons 64 | Crime 65 | Drama 66 | 1h 10m 67 |
68 |

69 | To carry out the biggest heist in history, a mysterious man 70 | called The Professor recruits a band of eight robbers who have 71 | a single characteristic: none of them has anything to lose. 72 | Five months of seclusion - memorizing every step, every 73 | detail, every probability - culminate in eleven days locked up 74 | in the National Coinage and Stamp Factory of Spain, surrounded 75 | by police forces and with dozens of hostages in their power, 76 | to find out whether their suicide wager will lead to 77 | everything or nothing. 78 |

79 |
80 | 84 | 85 | play 86 | 87 | 88 | more information 89 | 90 |
91 |
92 |
93 |
94 |
95 |
96 | 97 |
98 | slider-bg 99 |
100 |
101 |
102 |
103 |
104 | netflix 110 | SERIES 111 |
112 |
113 | squid_game_banner 119 |
120 |
121 | 2021 122 | +18 123 | Action 124 | Adventure 125 | 1 season 126 | 54m 127 |
128 |

129 | Hundreds of cash-strapped players accept a strange invitation 130 | to compete in children's games—with high stakes. But, a 131 | tempting prize awaits the victor. 132 |

133 |
134 | 138 | 139 | play 140 | 141 | 142 | more information 143 | 144 |
145 |
146 |
147 |
148 |
149 |
150 | 151 |
152 | slider-bg 153 |
154 |
155 |
156 |
157 |
158 | netflix 164 | MOVIES 165 |
166 |
167 | spider_man_banner 173 |
174 |
175 | 2021 176 | PG-13 177 | Action 178 | Fiction 179 | 2h 28m 180 |
181 |

182 | Peter Parker is unmasked and no longer able to separate his 183 | normal life from the high-stakes of being a super-hero. When 184 | he asks for help from Doctor Strange the stakes become even 185 | more dangerous, forcing him to discover what it truly means to 186 | be Spider-Man. 187 |

188 |
189 | 190 | 191 | play 192 | 193 | 194 | more information 195 | 196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 | ); 204 | } 205 | -------------------------------------------------------------------------------- /src/components/HomePage.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | 3 | import HomeTrendings from "./HomeTrendings"; 4 | import HeroSlider from "./HeroSlider"; 5 | import PopularSlider from "./PopularSlider"; 6 | import NowPlayingSlider from "./NowPlayingSlider"; 7 | import TopRatedSlider from "./TopRatedSlider"; 8 | import scrollToTop from "../helpers/scrollToTop"; 9 | 10 | export default function HomePage() { 11 | useEffect(() => { 12 | document.title = `NETFLIX | Watch Movies And TV Shows Online`; 13 | scrollToTop(); 14 | return () => { 15 | scrollToTop(); 16 | }; 17 | }, []); 18 | 19 | return ( 20 | <> 21 | 22 | 23 | 24 | 25 | 26 | 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /src/components/HomeTrendings.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | 3 | import { Navigation, Scrollbar, Autoplay } from "swiper"; 4 | import { Swiper, SwiperSlide } from "swiper/react"; 5 | import MovieOnSliderView from "./MovieOnSliderView"; 6 | import getTmdbTrendings from "../redux/actions/getTmdbTrendings"; 7 | 8 | import "swiper/css"; 9 | import "swiper/css/navigation"; 10 | import "swiper/css/scrollbar"; 11 | import "swiper/css/pagination"; 12 | 13 | import "../styles/home_trendings.sass"; 14 | import { connect } from "react-redux"; 15 | 16 | const mapStateToProps = (state) => { 17 | return state; 18 | }; 19 | export default connect(mapStateToProps, { getTmdbTrendings })( 20 | function HomeTrendings({ getTmdbTrendings, trendings }) { 21 | useEffect(() => { 22 | getTmdbTrendings(); 23 | }, []); 24 | const renderTrendingsList = () => { 25 | return trendings.map((trend) => { 26 | return ( 27 | 28 | 29 | 30 | ); 31 | }); 32 | }; 33 | 34 | return ( 35 |
36 |
37 |
38 |
39 |

40 | 41 | trending now 42 |

43 | {trendings.length ? ( 44 | 67 | {renderTrendingsList()} 68 | 69 | ) : ( 70 | "LOADING ..." 71 | )} 72 |
73 |
74 |
75 |
76 | ); 77 | } 78 | ); 79 | -------------------------------------------------------------------------------- /src/components/LoadWrapper.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | 4 | import "../styles/load-wrapper.sass"; 5 | 6 | export default function LoadWrapper({ ready }) { 7 | return ReactDOM.createPortal( 8 |
9 |
10 | Loading... 11 |
12 |
, 13 | document.getElementById("wrapper") 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /src/components/MainMenu.jsx: -------------------------------------------------------------------------------- 1 | /// MODULES 2 | import React from "react"; 3 | import { Link } from "react-router-dom"; 4 | 5 | /// IMAGES 6 | import logo from "../assets/images/logo.svg"; 7 | 8 | /// STYLES 9 | import "../styles/main-menu.sass"; 10 | 11 | export default function MainMenu() { 12 | return ( 13 | <> 14 |
15 |
16 |
17 |
18 | 19 | netflix logo 25 | 26 |
27 |
28 | 29 | movies 30 | 31 |
    32 |
  • 33 | Popular Movies 34 |
  • 35 |
  • 36 | Now Playing Movies 37 |
  • 38 |
  • 39 | Top Rated Movies 40 |
  • 41 |
  • 42 | Upcoming Movies 43 |
  • 44 |
45 |
46 |
47 | 48 | series 49 | 50 |
    51 |
  • 52 | Popular Series 53 |
  • 54 |
  • 55 | Airing Today Series 56 |
  • 57 |
  • 58 | Top Rated Series 59 |
  • 60 |
  • 61 | On Tv Series 62 |
  • 63 |
64 |
65 |
66 | 93 |

94 | All rights reserved by 95 | 99 | Blue Lotus 100 | {" "} 101 | © 2022 102 |

103 |
104 |
105 |
106 |
107 | 108 | ); 109 | } 110 | -------------------------------------------------------------------------------- /src/components/MobileNavMenu.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link } from "react-router-dom"; 3 | import "../styles/mob-nav-menu.sass"; 4 | 5 | import logo from "../assets/images/logo.svg"; 6 | 7 | export default function MobileNavMenu() { 8 | return ( 9 |
10 |
11 |
12 |
13 | 14 | netflix logo 15 | 16 |
17 |
18 | 21 |
22 |
23 |
24 |
    25 |
  • 26 | Home 27 |
  • 28 |
  • 29 | Movies 30 |
  • 31 |
  • 32 | Series 33 |
  • 34 |
  • 35 | People 36 |
  • 37 |
  • 38 | Favourites 39 |
  • 40 |
41 |
42 | ); 43 | } 44 | -------------------------------------------------------------------------------- /src/components/Mouse.jsx: -------------------------------------------------------------------------------- 1 | import React, { useRef } from "react"; 2 | import ReactDOM from "react-dom"; 3 | 4 | import "../styles/mouse.sass"; 5 | 6 | export default function Mouse() { 7 | const mouse = useRef(null); 8 | 9 | const body = document.body; 10 | body.addEventListener("pointermove", (e) => { 11 | console.log(e.pageX); 12 | console.log(e.pageY); 13 | mouse.current.style.left = `${e.pageX - 15}px`; 14 | mouse.current.style.top = `${e.pageY - 15}px`; 15 | }); 16 | 17 | return ReactDOM.createPortal( 18 | , 19 | document.querySelector("body") 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /src/components/MovieDetails.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { connect } from "react-redux"; 3 | import { useParams } from "react-router-dom"; 4 | import { getMovieById } from "../redux/actions"; 5 | import "../styles/movie_details_page.sass"; 6 | import CastSlider from "./CastSlider"; 7 | import ReviewItem from "./ReviewItem"; 8 | import MoviePageHero from "./MoviePageHero"; 9 | import LoadWrapper from "./LoadWrapper"; 10 | import _ from "lodash"; 11 | import _404 from "./_404"; 12 | import scrollToTop from "../helpers/scrollToTop"; 13 | 14 | const mapStateToProps = (state) => { 15 | return state; 16 | }; 17 | 18 | export default connect(mapStateToProps, { getMovieById })( 19 | function MovieDetails({ movie, getMovieById }) { 20 | const { id } = useParams(); 21 | const [ready, setReady] = useState("loading"); 22 | 23 | useEffect(() => { 24 | document.title = `NETFLIX | Loading ...`; 25 | scrollToTop(); 26 | return () => { 27 | scrollToTop(); 28 | }; 29 | }, []); 30 | useEffect(() => { 31 | getMovieById(id); 32 | }, [id]); 33 | 34 | useEffect(() => { 35 | if (movie.success === false) { 36 | document.title = `NETFLIX | 404 NOT FOUND`; 37 | setReady("404"); 38 | } else if (!movie.success && movie.title) { 39 | document.title = `NETFLIX | ${movie.title}`; 40 | setReady("ready"); 41 | } else { 42 | setReady("loading"); 43 | } 44 | }, [movie]); 45 | 46 | useEffect(() => { 47 | if (ready === "loading") { 48 | document.title = `NETFLIX | Loading ...`; 49 | } 50 | }, [ready]); 51 | 52 | if (ready === "404") return <_404 />; 53 | if (ready === "loading") return ; 54 | if (ready === "ready") 55 | return ( 56 | <> 57 |
58 | 59 |
60 |
61 |
62 |
63 |
64 | {(() => { 65 | return ( 66 |
67 |
Movie Trailer
68 |
69 | 76 |
77 |
78 | ); 79 | })()} 80 | 81 | { 84 | return el.profile_path; 85 | })} 86 | /> 87 |
88 |
89 |
90 |
91 |
92 | 98 | 99 | 100 | {movie?.external_ids?.facebook_id ? ( 101 | 107 | 108 | 109 | ) : null} 110 | {movie?.external_ids?.twitter_id ? ( 111 | 117 | 118 | 119 | ) : null} 120 | {movie?.external_ids?.instagram_id ? ( 121 | 127 | 128 | 129 | ) : null} 130 |
131 |
132 |

Status

133 |

{movie.status || "N/A"}

134 |
135 |
136 |

Original Language

137 |

138 | {movie.original_language || "N/A"} 139 |

140 |
141 |
142 |

Budget

143 |

144 | {!movie.budget ? "N/A" : `$ ${movie.budget}`} 145 |

146 |
147 |
148 |

Revenue

149 |

150 | {!movie.revenue ? "N/A" : `$ ${movie.revenue}`} 151 |

152 |
153 | 154 | {(() => { 155 | if (movie?.keywords) { 156 |
157 |

Keywords

158 |
    159 | {movie.keywords?.keywords.map((el) => { 160 | return ( 161 |
  • 165 | {el.name} 166 |
  • 167 | ); 168 | })} 169 |
170 |
; 171 | } 172 | })()} 173 | 174 | {(() => { 175 | if (movie?.production_companies?.length) { 176 | return ( 177 |
178 |

Production

179 |
    180 | {movie?.production_companies 181 | ?.filter((el) => { 182 | return el.logo_path; 183 | }) 184 | .map((el) => { 185 | return ( 186 |
  • 187 | {el.name} 192 |
  • 193 | ); 194 | })} 195 |
196 |
197 | ); 198 | } 199 | })()} 200 | 201 | {(() => { 202 | return ( 203 |
204 |

{`Reviews (${ 205 | movie?.reviews?.results?.length || 0 206 | })`}

207 |
    208 | {movie?.reviews?.results.length ? ( 209 | movie.reviews.results.map((rev) => { 210 | return ( 211 | 218 | {rev.content} 219 | 220 | ); 221 | }) 222 | ) : ( 223 |
  • 224 | We don't have any reviews for {movie.title}. 225 |
  • 226 | )} 227 |
228 |
229 | ); 230 | })()} 231 |
232 |
233 |
234 |
235 |
236 |
237 | 238 | ); 239 | } 240 | ); 241 | -------------------------------------------------------------------------------- /src/components/MovieOnSliderView.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link } from "react-router-dom"; 3 | import netflix_icon from "../assets/images/icon.png"; 4 | import "../styles/movie_slider_view.sass"; 5 | 6 | export default function MovieOnSliderView({ trend }) { 7 | return ( 8 | 12 | trend_backdrop 17 |
18 | netflix 19 | 20 | {trend.media_type !== "movie" ? "series" : "movies"} 21 | 22 |
23 |
{trend.title || trend.name}
24 | {trend.original_language} 25 | 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /src/components/MoviePageHero.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import work_bg from "../assets/images/work-bg.jpg"; 4 | import WorkScore from "./WorkScore"; 5 | import { Link } from "react-router-dom"; 6 | 7 | export default function MoviePageHero({ movie, btns }) { 8 | return ( 9 |
10 |
11 |
12 | backdrop-img 21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | movie-poster 37 |
38 |
39 |
40 |
41 |

42 | {movie.title || "N/A"} 43 | 47 | {movie.release_date 48 | ? `(${movie.release_date?.split("-")[0]})` 49 | : null} 50 | 51 |

52 |
53 | {movie.release_date} 54 | 55 | {movie?.release_dates?.results?.find((el) => { 56 | return el?.release_dates?.find((el) => { 57 | return el?.certification !== ""; 58 | }); 59 | })?.release_dates[0]?.certification || "N/A"} 60 | 61 | {movie.genres?.map((el) => { 62 | return ( 63 | 64 | {el.name} 65 | 66 | ); 67 | })} 68 |
69 |
70 | 71 |
72 | {movie.tagline} 73 |
{movie.overview}
74 | {btns ? ( 75 |
76 | 80 | 81 | play 82 | 83 | {movie?.homepage ? ( 84 | 89 | Visit Website 90 | 91 | ) : null} 92 |
93 | ) : null} 94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 | ); 102 | } 103 | -------------------------------------------------------------------------------- /src/components/MovieSerieView.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link } from "react-router-dom"; 3 | import WorkScore from "./WorkScore"; 4 | import "../styles/movie_serie_view.sass"; 5 | 6 | export default function MovieSerieView({ work }) { 7 | return ( 8 |
13 | 20 | 21 |
{work.original_language || "N/A"}
22 |
23 |
24 | 31 | poster 42 | 43 | 44 | 50 | 63 | {work.profile_path ? ( 64 | 65 | ) : ( 66 | 67 | )} 68 | 69 |
70 |
71 | 78 |

{work.title || work.name}

79 | 80 |

81 | {work.release_date || 82 | work.first_air_date || 83 | work.character || 84 | work.known_for_department} 85 |

86 |
87 |
88 | ); 89 | } 90 | -------------------------------------------------------------------------------- /src/components/MoviesPage.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import ResultsContainer from "./ResultsContainer"; 3 | import SideBarFilter from "./SideBarFilter"; 4 | import { useLocation } from "react-router-dom"; 5 | import scrollToTop from "../helpers/scrollToTop"; 6 | import Pagination from "./Pagination"; 7 | import LoadWrapper from "./LoadWrapper"; 8 | import _ from "lodash"; 9 | import { 10 | getPopularMovies, 11 | getNowPlayingMovies, 12 | getTopMovies, 13 | getUpcomingMovies, 14 | } from "../redux/actions"; 15 | 16 | import "../styles/movies-page.sass"; 17 | import { connect } from "react-redux"; 18 | import PageHeroSlider from "./PageHeroSlider"; 19 | 20 | const mapStateToProps = (state) => { 21 | return state; 22 | }; 23 | export default connect(mapStateToProps, { 24 | getPopularMovies, 25 | getNowPlayingMovies, 26 | getTopMovies, 27 | getUpcomingMovies, 28 | })(function MoviesPage(props) { 29 | const location = useLocation(); 30 | const [ready, setReady] = useState("loading"); 31 | const [page, setpage] = useState(1); 32 | const [category, setCategory] = useState(""); 33 | 34 | useEffect(() => { 35 | setCategory(location.pathname.split("/")[2]); 36 | setpage(location.search.split("=")[1] ? +location.search.split("=")[1] : 1); 37 | scrollToTop(); 38 | return () => { 39 | scrollToTop(); 40 | }; 41 | }, [location]); 42 | useEffect(() => { 43 | setReady("loading"); 44 | switch (category) { 45 | case undefined: 46 | props.getPopularMovies(page); 47 | document.title = "NETFLIX | Popular Movies"; 48 | break; 49 | case "now_playing": 50 | props.getNowPlayingMovies(page); 51 | document.title = "NETFLIX | Now Playing Movies"; 52 | break; 53 | case "top_rated": 54 | props.getTopMovies(page); 55 | document.title = "NETFLIX | Top Rated Movies"; 56 | break; 57 | case "upcoming": 58 | props.getUpcomingMovies(page); 59 | document.title = "NETFLIX | Upcoming Movies"; 60 | break; 61 | } 62 | }, [category, page]); 63 | 64 | useEffect(() => { 65 | if (!_.isEmpty(props.movies)) { 66 | setReady("ready"); 67 | } 68 | }, [props.movies]); 69 | 70 | if (ready === "loading") { 71 | return ; 72 | } 73 | if (ready === "ready") 74 | return ( 75 | <> 76 |
77 | 78 |
79 |
80 |
81 |
82 | 86 | 91 | 92 | 93 |
94 |
95 |
96 | 97 | ); 98 | }); 99 | -------------------------------------------------------------------------------- /src/components/Navbar.jsx: -------------------------------------------------------------------------------- 1 | /// MODULES 2 | import { connect } from "react-redux"; 3 | import { changeIsLoggedIn } from "../redux/actions"; 4 | import { Link, useLocation } from "react-router-dom"; 5 | import React, { useState, useEffect, useRef } from "react"; 6 | 7 | /// IMAGES 8 | import logo from "../assets/images/logo.svg"; 9 | import avatar from "../assets/images/avatar.webp"; 10 | 11 | /// STYLES 12 | import "../styles/navbar.sass"; 13 | import "../styles/mob-nav-menu.sass"; 14 | 15 | const mapStateToProps = (state) => { 16 | return state; 17 | }; 18 | 19 | export default connect(mapStateToProps, { changeIsLoggedIn })( 20 | function MainNavbar({ changeIsLoggedIn, isUserLoggedIn }) { 21 | const location = useLocation(); 22 | 23 | const nav = useRef(); 24 | const menu = useRef(); 25 | const menu_nav = useRef(); 26 | const home = useRef(); 27 | const home_nav = useRef(); 28 | 29 | const [currentPage, setCurrentPage] = useState(null); 30 | const [navFixed, setNavFixed] = useState(false); 31 | const [scrollY, setscrollY] = useState(0); 32 | 33 | const setActiveClass = () => { 34 | [...nav.current.children].map((el) => { 35 | el.children[0].classList.remove("active"); 36 | if (currentPage === "") { 37 | home.current.classList.add("active"); 38 | } 39 | if (currentPage && el.children[0].innerHTML === currentPage) { 40 | el.children[0].classList.add("active"); 41 | } 42 | }); 43 | 44 | [...menu_nav.current.children].map((el) => { 45 | el.classList.remove("active"); 46 | if (currentPage === "") { 47 | home_nav.current.classList.add("active"); 48 | } 49 | if (currentPage && el.children[0].innerHTML === currentPage) { 50 | el.classList.add("active"); 51 | } 52 | }); 53 | }; 54 | 55 | const closeModal = () => { 56 | menu.current.classList.remove("show"); 57 | }; 58 | 59 | document.addEventListener("scroll", () => { 60 | setscrollY(window.scrollY); 61 | }); 62 | useEffect(() => { 63 | setCurrentPage(location.pathname.split("/")[1]); 64 | }, [location]); 65 | useEffect(() => { 66 | setActiveClass(); 67 | }, [currentPage]); 68 | useEffect(() => { 69 | if (scrollY > 120) { 70 | setNavFixed(true); 71 | } else if (scrollY <= 120) { 72 | setNavFixed(false); 73 | } 74 | }, [scrollY]); 75 | 76 | return ( 77 | <> 78 |
79 |
80 |
81 |
82 | 83 | netflix logo 89 | 90 |
91 |
92 | 100 |
101 |
102 |
103 |
    104 |
  • 105 | 106 | home 107 | 108 |
  • 109 |
  • 110 | 111 | movies 112 | 113 |
  • 114 |
  • 115 | 116 | series 117 | 118 |
  • 119 |
  • 120 | 121 | people 122 | 123 |
  • 124 |
  • 125 | 126 | favourites 127 | 128 |
  • 129 |
130 |
131 |
132 | 133 | 134 | 135 | 136 | 137 | 138 | {!isUserLoggedIn ? ( 139 | 145 | ) : ( 146 | <> 147 | 148 | {"avatar"} 149 | 150 | 151 | 152 | 153 | 156 | 157 | )} 158 |
159 | 249 | 250 | ); 251 | } 252 | ); 253 | -------------------------------------------------------------------------------- /src/components/NowPlayingSlider.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import { connect } from "react-redux"; 3 | import WorksSlider from "./WorksSlider"; 4 | import { getNowPlayingMovies } from "../redux/actions"; 5 | import { getNowPlayingTv } from "../redux/actions"; 6 | 7 | import "../styles/slider-bg-white.sass"; 8 | 9 | const mapStateToProps = (state) => { 10 | return state; 11 | }; 12 | 13 | export default connect(mapStateToProps, { 14 | getNowPlayingMovies, 15 | getNowPlayingTv, 16 | })(function PopularSlider(props) { 17 | useEffect(() => { 18 | props.getNowPlayingMovies(); 19 | }, []); 20 | return ( 21 |
22 | 30 |
31 | ); 32 | }); 33 | -------------------------------------------------------------------------------- /src/components/PageHeroSlide.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import MovieSerieView from "./MovieSerieView"; 3 | import { Link } from "react-router-dom"; 4 | 5 | import netflix_icon from "../assets/images/icon.png"; 6 | import bg from "../assets/images/work-bg.jpg"; 7 | 8 | export default function PageHeroSlide({ data }) { 9 | return ( 10 | <> 11 |
12 | slider-bg 21 |
22 |
23 |
24 |
25 |
26 | netflix 27 | {data.title ? "MOVIES" : "SERIES"} 28 |
29 |
30 |

{data.title || data.name}

31 |
32 |
33 | 34 | {data.release_date?.split("-")[0] || 35 | data.first_air_date?.split("-")[0]} 36 | 37 |
38 |

{data.overview}

39 |
40 | 46 | 47 | play 48 | 49 | 53 | more information 54 | 55 |
56 |
57 |
58 | 59 |
60 |
61 |
62 |
63 | 64 | ); 65 | } 66 | -------------------------------------------------------------------------------- /src/components/PageHeroSlider.jsx: -------------------------------------------------------------------------------- 1 | // import Swiper core and required modules 2 | import { Navigation, Pagination, Autoplay } from "swiper"; 3 | import { Swiper, SwiperSlide } from "swiper/react"; 4 | 5 | // Import Swiper styles 6 | import "swiper/css"; 7 | import "swiper/css/navigation"; 8 | import "swiper/css/pagination"; 9 | 10 | import "../styles/hero-slider.sass"; 11 | import PageHeroSlide from "./PageHeroSlide"; 12 | 13 | export default function PageHeroSlider(props) { 14 | const renderList = () => { 15 | return props.results.map((el) => { 16 | return ( 17 | 18 | 19 | 20 | ); 21 | }); 22 | }; 23 | return ( 24 | 38 | {renderList()} 39 | 40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /src/components/Pagination.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import { Link, useLocation } from "react-router-dom"; 3 | 4 | import "../styles/pagination.sass"; 5 | export default function Pagination({ page }) { 6 | const location = useLocation(); 7 | const [search, setSearch] = useState(""); 8 | const [hasSearch, setHasSearch] = useState(false); 9 | 10 | useEffect(() => { 11 | if (location.search) setHasSearch(true); 12 | }, [location]); 13 | 14 | useEffect(() => { 15 | if (hasSearch) { 16 | if (!location.search.split("&")[0].startsWith("?page=")) { 17 | setSearch(location.search.split("&")[0]); 18 | } 19 | } 20 | }, [hasSearch]); 21 | 22 | return ( 23 |
24 | {(() => { 25 | if (+page - 1 !== 0) { 26 | return ( 27 | 30 | 31 | page {+page - 1} 32 | 33 | ); 34 | } 35 | })()} 36 | {(() => { 37 | if (+page < 500) { 38 | return ( 39 | 42 | page {+page + 1} 43 | 44 | 45 | ); 46 | } 47 | })()} 48 |
49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /src/components/PeoplePage.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import MovieSerieView from "./MovieSerieView"; 3 | import LoadWrapper from "./LoadWrapper"; 4 | import _404 from "./_404"; 5 | import { getPeople } from "../redux/actions"; 6 | import { connect } from "react-redux"; 7 | import Pagination from "./Pagination"; 8 | import { useLocation } from "react-router-dom"; 9 | import _ from "lodash"; 10 | import work_bg from "../assets/images/work-bg.jpg"; 11 | 12 | const mapStateToProps = (state) => { 13 | return state; 14 | }; 15 | 16 | export default connect(mapStateToProps, { getPeople })(function PeoplePage({ 17 | people, 18 | getPeople, 19 | }) { 20 | const location = useLocation(); 21 | const [ready, setReady] = useState("loading"); 22 | const [page, setPage] = useState(null); 23 | 24 | useEffect(() => { 25 | setPage(+location.search.split("=")[1] || 1); 26 | }, [location]); 27 | 28 | useEffect(() => { 29 | getPeople(1); 30 | }, []); 31 | 32 | useEffect(() => { 33 | setReady("loading"); 34 | if (page) getPeople(page); 35 | }, [page]); 36 | 37 | useEffect(() => { 38 | if (people.length) { 39 | if (people[0] === "page must be less than or equal to 500") { 40 | setReady("404"); 41 | document.title = `NETFLIX | 404 NOT FOUND`; 42 | } else { 43 | setReady("ready"); 44 | document.title = `NETFLIX | Popular People`; 45 | } 46 | } 47 | }, [people]); 48 | 49 | if (ready === "loading") { 50 | document.title = `NETFLIX | Loading ...`; 51 | return ; 52 | } 53 | if (ready === "404") { 54 | document.title = `NETFLIX | 404 NOT FOUND`; 55 | return <_404 />; 56 | } 57 | if (ready === "ready") 58 | return ( 59 |
67 |
68 |
69 | {people.map((el) => { 70 | if (el.profile_path) 71 | return ( 72 |
76 |
77 | 78 |
79 |
80 | ); 81 | })} 82 |
83 |
84 | 85 |
86 |
87 |
88 | ); 89 | }); 90 | -------------------------------------------------------------------------------- /src/components/PersonPage.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import _404 from "./_404"; 3 | import LoadWrapper from "./LoadWrapper"; 4 | import { connect } from "react-redux"; 5 | import { getPersonById } from "../redux/actions"; 6 | import { useParams } from "react-router-dom"; 7 | import MovieSerieView from "./MovieSerieView"; 8 | import scrollToTop from "../helpers/scrollToTop"; 9 | 10 | import "../styles/person-page.sass"; 11 | 12 | const mapStateToProps = (state) => { 13 | return state; 14 | }; 15 | 16 | export default connect(mapStateToProps, { getPersonById })(function PersonPage({ 17 | getPersonById, 18 | person, 19 | }) { 20 | const { id } = useParams(); 21 | const [ready, setReady] = useState("loading"); 22 | 23 | useEffect(() => { 24 | getPersonById(id); 25 | scrollToTop(); 26 | return () => { 27 | scrollToTop(); 28 | }; 29 | }, [id]); 30 | 31 | useEffect(() => { 32 | if (person.status_code === 34) { 33 | setReady("404"); 34 | } 35 | if (person.name) { 36 | setReady("ready"); 37 | document.title = `NETFLIX | ${person.name}`; 38 | } 39 | }, [person]); 40 | 41 | if (ready === "loading") { 42 | document.title = `NETFLIX | Loading ...`; 43 | return ; 44 | } 45 | if (ready === "404") { 46 | document.title = `NETFLIX | 404 NOT FOUND`; 47 | return <_404 />; 48 | } 49 | if (ready === "ready") { 50 | return ( 51 |
52 |
53 |
54 |
55 |
56 |
57 | {person.name} 61 |
62 |
    63 |
  • 64 | 68 | 69 | 70 |
  • 71 | {person.external_ids.facebook_id ? ( 72 |
  • 73 | 77 | 78 | 79 |
  • 80 | ) : null} 81 | {person.external_ids.instagram_id ? ( 82 |
  • 83 | 87 | 88 | 89 |
  • 90 | ) : null} 91 | {person.external_ids.twitter_id ? ( 92 |
  • 93 | 97 | 98 | 99 |
  • 100 | ) : null} 101 |
102 | {person.also_known_as.length ? ( 103 |
104 | 105 | {person.also_known_as.map((el) => { 106 | return {`${el} , `}; 107 | })} 108 |
109 | ) : null} 110 |
111 |
112 |
113 |
114 |

{person.name}

115 |
116 | 117 |

118 | {person.biography || "N/A"} 119 |

120 |
121 |
122 |
123 | 124 |

{person.known_for_department || "N/A"}

125 |
126 |
127 | 128 |

{person.combined_credits.cast.length}

129 |
130 |
131 | 132 |

133 | {(() => { 134 | if (person.gender === 1) { 135 | return "Female"; 136 | } 137 | if (person.gender === 2) { 138 | return "Male"; 139 | } else { 140 | return "N/A"; 141 | } 142 | })()} 143 |

144 |
145 |
146 | 147 |

{person.birthday || "N/A"}

148 |
149 | {person.deathday ? ( 150 |
151 | 152 |

{person.deathday || "N/A"}

153 |
154 | ) : null} 155 |
156 | 157 |

{person.place_of_birth || "N/A"}

158 |
159 |
160 |
161 | 162 |
163 | {person.combined_credits.cast.map((el) => { 164 | if (el.poster_path) { 165 | return ; 166 | } 167 | })} 168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 | ); 176 | } 177 | }); 178 | -------------------------------------------------------------------------------- /src/components/PopularSlider.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import { connect } from "react-redux"; 3 | import WorksSlider from "./WorksSlider"; 4 | 5 | import { 6 | getPopularMovies, 7 | getPopularTv, 8 | getPopularPeople, 9 | } from "../redux/actions"; 10 | 11 | const mapStateToProps = (state) => { 12 | return state; 13 | }; 14 | 15 | export default connect(mapStateToProps, { 16 | getPopularMovies, 17 | getPopularTv, 18 | getPopularPeople, 19 | })(function PopularSlider(props) { 20 | useEffect(() => { 21 | props.getPopularMovies(); 22 | }, []); 23 | 24 | return ( 25 |
26 | 38 |
39 | ); 40 | }); 41 | -------------------------------------------------------------------------------- /src/components/ResultsContainer.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { connect } from "react-redux"; 3 | import "../styles/movies-page.sass"; 4 | import MovieSerieView from "./MovieSerieView"; 5 | import WorksClassificationBtns from "./WorksClassificationBtns"; 6 | 7 | const mapStateToProps = (state) => { 8 | return state; 9 | }; 10 | 11 | export default connect(mapStateToProps)(function ResultsContainer(props) { 12 | const renderList = () => { 13 | if (props.filteredList.length) { 14 | return props.filteredList.map((el) => { 15 | return ( 16 |
20 | 21 |
22 | ); 23 | }); 24 | } 25 | return <>Sorry ! There are no results that matched your query 🥺.; 26 | }; 27 | return ( 28 |
29 |
30 | {props.categories ? ( 31 |
32 | 36 |
37 | ) : null} 38 | 39 |
{renderList()}
40 |
{props.children}
41 |
42 |
43 | ); 44 | }); 45 | -------------------------------------------------------------------------------- /src/components/ReviewItem.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import avatarIMG from "../assets/images/avatar.webp"; 3 | 4 | import "../styles/review-item.sass"; 5 | 6 | export default function ReviewItem({ invert, review, avatarCol, body }) { 7 | const avatar = () => { 8 | let avatar_path = review?.author_details?.avatar_path; 9 | if (avatar_path && !avatar_path.startsWith("/h")) { 10 | return `https://www.themoviedb.org/t/p/w64_and_h64_face${avatar_path}`; 11 | } else if (avatar_path) { 12 | return avatar_path.slice(1); 13 | } 14 | // el 15 | }; 16 | return ( 17 | <> 18 |
19 |
20 |
21 |
22 | avatar 23 |
24 |
25 |
26 |
27 |

28 | A review by {review.author}{" "} 29 |

30 |

{review.created_at}

31 | 32 |

33 | 34 | {review.author_details.rating || "N/A"} 35 |

36 |

{review.content}

37 |
38 |
39 |
40 |
41 | 42 | ); 43 | } 44 | -------------------------------------------------------------------------------- /src/components/SearchPage.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import _404 from "./_404"; 3 | import { useLocation, Link, useSearchParams } from "react-router-dom"; 4 | import LoadWrapper from "./LoadWrapper"; 5 | import "../styles/search-area.sass"; 6 | import Pagination from "./Pagination"; 7 | import { searchTMDB } from "../redux/actions"; 8 | import { connect } from "react-redux"; 9 | import SideBarFilter from "./SideBarFilter"; 10 | import ResultsContainer from "./ResultsContainer"; 11 | import scrollToTop from "../helpers/scrollToTop"; 12 | 13 | const mapStateToProps = (state) => { 14 | return state; 15 | }; 16 | export default connect(mapStateToProps, { searchTMDB })(function SearchPage({ 17 | search_list, 18 | searchTMDB, 19 | }) { 20 | const location = useLocation(); 21 | const [params] = useSearchParams(); 22 | const [query, setQuery] = useState(""); 23 | const [term, setTerm] = useState(""); 24 | const [page, setPage] = useState(1); 25 | const [ready, setReady] = useState("loading"); 26 | 27 | useEffect(() => { 28 | document.title = `NETFLIX | Search`; 29 | }, []); 30 | 31 | useEffect(() => { 32 | setReady("loading"); 33 | scrollToTop(); 34 | setQuery(params.get("query")); 35 | setPage(+params.get("page") || 1); 36 | }, [location]); 37 | 38 | useEffect(() => { 39 | if (query) 40 | (async () => { 41 | await searchTMDB(query, page); 42 | document.title = `NETFLIX | Search ${query}`; 43 | setReady("ready"); 44 | })(); 45 | setInterval(() => { 46 | setReady("ready"); 47 | }, 1000); 48 | }, [page, query]); 49 | 50 | if (ready === "loading") return ; 51 | return ( 52 |
53 |
54 |
e.preventDefault()}> 55 | { 58 | setTerm(e.target.value); 59 | }} 60 | type="text" 61 | name="query" 62 | placeholder="Search for a movie, tv show or person" 63 | onFocus={(e) => { 64 | e.target.placeholder = ""; 65 | }} 66 | onBlur={(e) => { 67 | e.target.placeholder = "Search for a movie, tv show or person"; 68 | }} 69 | /> 70 | 71 | 72 | 73 |
74 |
75 |
76 |
77 |
78 | 79 | 80 | {search_list.length ? : null} 81 | 82 |
83 |
84 |
85 |
86 | ); 87 | }); 88 | -------------------------------------------------------------------------------- /src/components/SeasonItem.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link } from "react-router-dom"; 3 | 4 | export default function SeasonItem({ season, serieID }) { 5 | return ( 6 |
7 |
8 |
9 |
10 | 11 | season-poster 20 | 21 |
22 |
23 | 27 |
{season?.name}
28 | 29 |
{`${ 30 | season?.air_date?.split("-")[0] 31 | } | ${season?.episode_count} Epoisodes`}
32 |

{season?.overview}

33 |
34 |
35 |
36 |
37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /src/components/SeasonPageHero.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import work_bg from "../assets/images/work-bg.jpg"; 4 | import { Link } from "react-router-dom"; 5 | 6 | export default function SeasonPageHero({ serie, season }) { 7 | return ( 8 |
9 |
10 |
11 | backdrop-img 20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | movie-poster 36 |
37 |
38 |
39 |
40 |

41 | {serie?.name}{" "} 42 | 46 | {`(${season?.name})`} 47 | 48 |

49 |
50 | {season?.air_date} 51 | {`${ 52 | season?.episode_count 53 | } ${ 54 | season?.episode_count === 1 ? "episode" : "episodes" 55 | }`} 56 | {serie?.genres?.map((el) => { 57 | return ( 58 | 59 | {el.name} 60 | 61 | ); 62 | })} 63 |
64 |
65 |
66 | {season?.overview || serie?.overview} 67 |
68 |
69 | 73 | 74 | play 75 | 76 | {serie?.homepage ? ( 77 | 82 | Visit Website 83 | 84 | ) : null} 85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 | ); 94 | } 95 | -------------------------------------------------------------------------------- /src/components/SerieDetails.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { useParams } from "react-router-dom"; 3 | import { connect } from "react-redux"; 4 | import { getSerieById } from "../redux/actions"; 5 | import "../styles/movie_details_page.sass"; 6 | import CastSlider from "./CastSlider"; 7 | import SeasonItem from "./SeasonItem"; 8 | import ReviewItem from "./ReviewItem"; 9 | import SeriePageHero from "./SeriePageHero"; 10 | import LoadWrapper from "./LoadWrapper"; 11 | import _ from "lodash"; 12 | import _404 from "./_404"; 13 | import scrollToTop from "../helpers/scrollToTop"; 14 | 15 | const mapStateToProps = (state) => { 16 | return state; 17 | }; 18 | 19 | export default connect(mapStateToProps, { getSerieById })( 20 | function SerieDetails({ serie, getSerieById }) { 21 | const { id } = useParams(); 22 | 23 | const [ready, setReady] = useState("loading"); 24 | 25 | useEffect(() => { 26 | document.title = `NETFLIX | Loading ...`; 27 | scrollToTop(); 28 | return () => { 29 | scrollToTop(); 30 | }; 31 | }, []); 32 | useEffect(() => { 33 | getSerieById(id); 34 | }, [id]); 35 | 36 | useEffect(() => { 37 | if (serie.success === false) { 38 | document.title = `NETFLIX | 404 NOT FOUND`; 39 | setReady("404"); 40 | } else if (!serie.success && serie.name) { 41 | document.title = `NETFLIX | ${serie.name}`; 42 | setReady("ready"); 43 | } else { 44 | setReady("loading"); 45 | } 46 | }, [serie]); 47 | 48 | useEffect(() => { 49 | if (ready === "loading") { 50 | document.title = `NETFLIX | Loading ...`; 51 | } 52 | }, [ready]); 53 | 54 | const renderSeasons = () => { 55 | return serie?.seasons?.map((season) => { 56 | if (season.season_number > 0) { 57 | return ( 58 | 59 | ); 60 | } 61 | }); 62 | }; 63 | if (ready === "404") return <_404 />; 64 | if (ready === "loading") return ; 65 | if (ready === "ready") 66 | return ( 67 |
68 | 69 |
70 |
71 |
72 |
73 |
74 |
75 |
Movie Trailer
76 |
77 | 84 |
85 |
86 | { 89 | return el.profile_path; 90 | })} 91 | /> 92 |
93 |
94 |
95 |
96 |
97 | 103 | 104 | 105 | {serie?.external_ids?.facebook_id ? ( 106 | 112 | 113 | 114 | ) : null} 115 | {serie?.external_ids?.twitter_id ? ( 116 | 122 | 123 | 124 | ) : null} 125 | {serie?.external_ids?.instagram_id ? ( 126 | 132 | 133 | 134 | ) : null} 135 |
136 |
137 |

Status

138 |

{serie.status || "N/A"}

139 |
140 |
141 |

Original Language

142 |

{serie.original_language}

143 |
144 |
145 |

Type

146 |

{serie.type}

147 |
148 |
149 |

Budget

150 |

151 | {!serie.budget ? "N/A" : `$ ${serie.budget}`} 152 |

153 |
154 |
155 |

Revenue

156 |

157 | {!serie.revenue ? "N/A" : `$ ${serie.revenue}`} 158 |

159 |
160 | {(() => { 161 | if (serie?.keywords?.results?.length) { 162 | return ( 163 |
164 |

Keywords

165 |
    166 | {serie?.keywords?.results.map((el) => { 167 | return ( 168 |
  • 172 | {el.name} 173 |
  • 174 | ); 175 | })} 176 |
177 |
178 | ); 179 | } 180 | })()} 181 | {(() => { 182 | if (serie?.networks?.length) { 183 | return ( 184 |
185 |

Networks

186 |
    187 | {serie?.networks?.map((el) => { 188 | return ( 189 |
  • 190 | {el.name} 195 |
  • 196 | ); 197 | })} 198 |
199 |
200 | ); 201 | } 202 | })()} 203 | {(() => { 204 | if (serie?.languages?.length) { 205 | return ( 206 |
207 |

Languages

208 |
    209 | {serie?.languages?.map((el) => { 210 | return ( 211 |
  • 215 | {el} 216 |
  • 217 | ); 218 | })} 219 |
220 |
221 | ); 222 | } 223 | })()} 224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
Tv Show Seasons
233 |
234 |
{renderSeasons()}
235 |
236 |
237 |
238 | {(() => { 239 | return ( 240 |
241 |

{`Reviews (${ 242 | serie?.reviews?.results?.length || 0 243 | })`}

244 |
    245 | {serie?.reviews?.results.length ? ( 246 | serie.reviews.results.map((rev) => { 247 | return ( 248 | 255 | {rev.content} 256 | 257 | ); 258 | }) 259 | ) : ( 260 |
  • 261 | We don't have any reviews for {serie.name}. 262 |
  • 263 | )} 264 |
265 |
266 | ); 267 | })()} 268 |
269 |
270 |
271 |
272 |
273 |
274 | ); 275 | } 276 | ); 277 | -------------------------------------------------------------------------------- /src/components/SeriePageHero.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import work_bg from "../assets/images/work-bg.jpg"; 4 | import WorkScore from "./WorkScore"; 5 | import { Link } from "react-router-dom"; 6 | 7 | export default function SeriePageHero({ serie, btns }) { 8 | return ( 9 |
10 |
11 |
12 | backdrop-img 21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | movie-poster 37 |
38 |
39 |
40 |
41 |

42 | {serie?.name}{" "} 43 | 47 | {`(${serie?.first_air_date?.split("-")[0]})`} 48 | 49 |

50 |
51 | 52 | {serie?.first_air_date} 53 | 54 | {`${ 55 | serie?.number_of_seasons 56 | } ${ 57 | serie?.number_of_seasons === 1 ? "season" : "seasons" 58 | }`} 59 | {serie?.genres?.map((el) => { 60 | return ( 61 | 62 | {el.name} 63 | 64 | ); 65 | })} 66 |
67 |
68 | 69 |
70 | {serie?.tagline} 71 |
72 | {serie?.overview} 73 |
74 | {btns ? ( 75 |
76 | 80 | 81 | play 82 | 83 | {serie?.homepage ? ( 84 | 89 | Visit Website 90 | 91 | ) : null} 92 |
93 | ) : null} 94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 | ); 102 | } 103 | -------------------------------------------------------------------------------- /src/components/SerieSeasonPage.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { connect } from "react-redux"; 3 | import { useParams } from "react-router-dom"; 4 | import { getSerieById, getSerieEpisodes } from "../redux/actions"; 5 | import SeasonPageHero from "./SeasonPageHero"; 6 | import EpisodeItem from "./EpisodeItem"; 7 | import LoadWrapper from "./LoadWrapper"; 8 | import _404 from "./_404"; 9 | import scrollToTop from "../helpers/scrollToTop"; 10 | import _ from "lodash"; 11 | 12 | const mapStateToProps = (state) => { 13 | return state; 14 | }; 15 | export default connect(mapStateToProps, { getSerieById, getSerieEpisodes })( 16 | function SerieSeasonPage({ 17 | getSerieById, 18 | getSerieEpisodes, 19 | serie, 20 | episodes, 21 | }) { 22 | const { id, number } = useParams(); 23 | const [ready, setReady] = useState("loading"); 24 | const [season, setSeason] = useState(null); 25 | 26 | useEffect(() => { 27 | document.title = `NETFLIX | Loading ...`; 28 | scrollToTop(); 29 | if (_.isEmpty(serie)) { 30 | getSerieById(id); 31 | } 32 | }, [id, number]); 33 | 34 | useEffect(() => { 35 | if (serie.success === false) { 36 | setReady("404"); 37 | document.title = `NETFLIX | 404 NOT FOUND`; 38 | } else if (!serie.success && serie.name) { 39 | serie.seasons.forEach((el) => { 40 | if (el.season_number === +number) { 41 | return setSeason(el); 42 | } 43 | }); 44 | } 45 | }, [serie]); 46 | 47 | useEffect(() => { 48 | if (season === null) { 49 | setReady("loading"); 50 | document.title = `NETFLIX | Loading ...`; 51 | } 52 | if (season === undefined) { 53 | setReady("404"); 54 | document.title = `NETFLIX | 404 NOT FOUND`; 55 | } 56 | if (season) { 57 | document.title = `NETFLIX | ${serie.name} - Season ${season?.season_number}`; 58 | if (!season.episode_count) { 59 | setReady("404"); 60 | document.title = `NETFLIX | 404 NOT FOUND`; 61 | } else { 62 | for (let ep = 1; ep <= season.episode_count; ep++) { 63 | getSerieEpisodes(id, number, ep); 64 | } 65 | } 66 | } 67 | }, [season]); 68 | 69 | useEffect(() => { 70 | if (episodes.length) { 71 | setReady("ready"); 72 | } 73 | }, [episodes]); 74 | 75 | if (ready === "404") { 76 | return <_404 />; 77 | } 78 | if (ready === "loading") { 79 | return ; 80 | } 81 | if (ready === "ready") { 82 | return ( 83 | <> 84 | 90 |
91 |
92 |
93 |
94 |
95 | Episodes ( {season?.episode_count} ) 96 |
97 |
98 |
99 |
100 | {episodes 101 | ?.sort((curr, next) => { 102 | return curr.episode_number - next.episode_number; 103 | }) 104 | .map((ep) => { 105 | return ( 106 |
107 | 112 |
113 | ); 114 | })} 115 |
116 |
117 |
118 | 119 | ); 120 | } 121 | } 122 | ); 123 | -------------------------------------------------------------------------------- /src/components/SideBarFilter.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import WorksFilter from "./WorksFilter"; 3 | import "../styles/movies-page.sass"; 4 | import "../styles/works-filter.sass"; 5 | import { filterByMediaType } from "../redux/actions"; 6 | import { connect } from "react-redux"; 7 | 8 | const mapStateToProps = (state) => { 9 | return state; 10 | }; 11 | 12 | export default connect(mapStateToProps, { filterByMediaType })( 13 | function SideBarFilter({ 14 | list, 15 | label, 16 | cats, 17 | filterByMediaType, 18 | filteredList, 19 | }) { 20 | return ( 21 |
22 | {cats ? ( 23 |
24 |
25 |
Search Results
26 |
27 |
    28 |
  • 29 | 36 | 37 | { 38 | list.filter((el) => { 39 | return el.media_type === "movie"; 40 | }).length 41 | } 42 | 43 |
  • 44 |
  • 45 | 46 | 47 | { 48 | list.filter((el) => { 49 | return el.media_type === "tv"; 50 | }).length 51 | } 52 | 53 |
  • 54 |
  • 55 | 56 | 57 | { 58 | list.filter((el) => { 59 | return el.media_type === "person"; 60 | }).length 61 | } 62 | 63 |
  • 64 |
65 |
66 |
67 |
68 | ) : null} 69 | 70 |
71 | ); 72 | } 73 | ); 74 | -------------------------------------------------------------------------------- /src/components/TopRatedSlider.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import { connect } from "react-redux"; 3 | import WorksSlider from "./WorksSlider"; 4 | import { getTopMovies, getTopTv } from "../redux/actions"; 5 | 6 | const mapStateToProps = (state) => { 7 | return state; 8 | }; 9 | 10 | export default connect(mapStateToProps, { 11 | getTopMovies, 12 | getTopTv, 13 | })(function PopularSlider(props) { 14 | useEffect(() => { 15 | props.getTopMovies(); 16 | }, []); 17 | return ( 18 |
19 | 27 |
28 | ); 29 | }); 30 | -------------------------------------------------------------------------------- /src/components/TvShowsPage.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import ResultsContainer from "./ResultsContainer"; 3 | import SideBarFilter from "./SideBarFilter"; 4 | import Pagination from "./Pagination"; 5 | import { useLocation } from "react-router-dom"; 6 | import scrollToTop from "../helpers/scrollToTop"; 7 | import LoadWrapper from "./LoadWrapper"; 8 | import _ from "lodash"; 9 | import { 10 | getPopularTv, 11 | getTopTv, 12 | getNowPlayingTv, 13 | getOnTheAirTv, 14 | } from "../redux/actions"; 15 | 16 | import "../styles/movies-page.sass"; 17 | import { connect } from "react-redux"; 18 | import PageHeroSlider from "./PageHeroSlider"; 19 | 20 | const mapStateToProps = (state) => { 21 | return state; 22 | }; 23 | 24 | export default connect(mapStateToProps, { 25 | getPopularTv, 26 | getTopTv, 27 | getNowPlayingTv, 28 | getOnTheAirTv, 29 | })(function TvShowsPage(props) { 30 | const location = useLocation(); 31 | const [page, setpage] = useState(1); 32 | const [ready, setReady] = useState("loading"); 33 | const [category, setCategory] = useState(""); 34 | 35 | useEffect(() => { 36 | setCategory(location.pathname.split("/")[2]); 37 | setpage(location.search.split("=")[1] ? +location.search.split("=")[1] : 1); 38 | scrollToTop(); 39 | return () => { 40 | scrollToTop(); 41 | }; 42 | }, [location]); 43 | 44 | useEffect(() => { 45 | setReady("loading"); 46 | 47 | switch (category) { 48 | case undefined: 49 | document.title = "NETFLIX | Popular Series"; 50 | props.getPopularTv(page); 51 | break; 52 | case "airing_today": 53 | document.title = "NETFLIX | Airing Today Series"; 54 | props.getNowPlayingTv(page); 55 | break; 56 | case "on_tv": 57 | document.title = "NETFLIX | On Tv Series"; 58 | props.getOnTheAirTv(page); 59 | break; 60 | case "top_rated": 61 | document.title = "NETFLIX | Top Rated Series"; 62 | props.getTopTv(page); 63 | break; 64 | } 65 | }, [category, page]); 66 | 67 | useEffect(() => { 68 | if (!_.isEmpty(props.series)) { 69 | setReady("ready"); 70 | } 71 | }, [props.series]); 72 | 73 | if (ready === "loading") { 74 | return ; 75 | } 76 | if (ready === "ready") 77 | return ( 78 | <> 79 |
80 | 81 |
82 |
83 |
84 |
85 | 89 | 94 | 95 | 96 |
97 |
98 |
99 | 100 | ); 101 | }); 102 | -------------------------------------------------------------------------------- /src/components/VideoPlayerArea.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export default function VideoPlayerArea({ season, ep, id }) { 4 | return ( 5 |
6 |
7 |
8 |
9 | 20 |
21 |
22 |
23 |
24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /src/components/WatchMovie.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { connect } from "react-redux"; 3 | import { getMovieById } from "../redux/actions"; 4 | import { useParams } from "react-router-dom"; 5 | import MoviePageHero from "./MoviePageHero"; 6 | import "../styles/movie_details_page.sass"; 7 | import VideoPlayerArea from "./VideoPlayerArea"; 8 | import _404 from "./_404"; 9 | import LoadWrapper from "./LoadWrapper"; 10 | 11 | const mapStateToProps = (state) => { 12 | return state; 13 | }; 14 | 15 | export default connect(mapStateToProps, { getMovieById })(function WatchMovie({ 16 | movie, 17 | getMovieById, 18 | }) { 19 | const [ready, setReady] = useState("loading"); 20 | const { id } = useParams(); 21 | useEffect(() => { 22 | getMovieById(id); 23 | }, [id]); 24 | 25 | useEffect(() => { 26 | if (movie.status_code === 34) { 27 | setReady("404"); 28 | document.title = `NETFLIX | 404 NOT FOUND`; 29 | } else if (movie.title) { 30 | setReady("ready"); 31 | document.title = `NETFLIX | Watch ${movie?.title}`; 32 | } 33 | }, [movie]); 34 | if (ready === "loading") { 35 | document.title = `NETFLIX | Loading ...`; 36 | return ; 37 | } 38 | if (ready === "404") { 39 | return <_404 />; 40 | } 41 | if (ready === "ready") 42 | return ( 43 | <> 44 | 45 | 46 | 47 | ); 48 | }); 49 | -------------------------------------------------------------------------------- /src/components/WatchSerie.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { connect } from "react-redux"; 3 | import { getSerieById } from "../redux/actions"; 4 | import { useParams } from "react-router-dom"; 5 | import SeriePageHero from "./SeriePageHero"; 6 | import "../styles/movie_details_page.sass"; 7 | import VideoPlayerArea from "./VideoPlayerArea"; 8 | import LoadWrapper from "./LoadWrapper"; 9 | import _404 from "./_404"; 10 | 11 | const mapStateToProps = (state) => { 12 | return state; 13 | }; 14 | 15 | export default connect(mapStateToProps, { getSerieById })(function WatchSerie({ 16 | serie, 17 | getSerieById, 18 | }) { 19 | const [ready, setReady] = useState("loading"); 20 | const { id, season, ep } = useParams(); 21 | 22 | useEffect(() => { 23 | getSerieById(id); 24 | }, [id, season, ep]); 25 | 26 | useEffect(() => { 27 | if (serie.status_code === 34) { 28 | setReady("404"); 29 | document.title = `NETFLIX | 404 NOT FOUND`; 30 | } else if (serie.name) { 31 | setReady("ready"); 32 | document.title = `NETFLIX | Watch ${serie?.name}`; 33 | } 34 | }, [serie]); 35 | 36 | if (ready === "loading") { 37 | document.title = `NETFLIX | Loading ...`; 38 | return ; 39 | } 40 | if (ready === "404") { 41 | return <_404 />; 42 | } 43 | if (ready === "ready") 44 | return ( 45 | <> 46 | 47 | 48 | 49 | ); 50 | }); 51 | -------------------------------------------------------------------------------- /src/components/WorkScore.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | 3 | import "../styles/score.sass"; 4 | 5 | export default function WorkScore({ score }) { 6 | const [color, setColor] = useState("#adb5bd"); 7 | 8 | useEffect(() => { 9 | if (score > 10 && score < 40) { 10 | setColor("#dc3545"); 11 | } else if (score >= 40 && score < 70) { 12 | setColor("#ffc107"); 13 | } else if (score >= 70) { 14 | setColor("#198754"); 15 | } 16 | }, [score]); 17 | return ( 18 |
19 | 20 | 26 | 34 | 35 | {`${score}%`} 36 | 37 | 38 |
39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /src/components/WorksClassificationBtns.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useRef } from "react"; 2 | import { Link, useLocation } from "react-router-dom"; 3 | 4 | import "../styles/works_classification_btns.sass"; 5 | 6 | export default function WorksClassificationBtns({ btns, pathname }) { 7 | const location = useLocation(); 8 | const ref = useRef(); 9 | let path; 10 | useEffect(() => { 11 | path = location.pathname.split("/")[2]; 12 | setCurrent(path, ref); 13 | }, [location]); 14 | const setCurrent = (path, ref) => { 15 | if (!path) { 16 | [...ref.current.children].forEach((el) => { 17 | el.classList.remove("current"); 18 | }); 19 | ref.current.children[0].classList.add("current"); 20 | } else { 21 | [...ref.current.children].forEach((el) => { 22 | el.classList.remove("current"); 23 | if (el.href.split("/")[4] === path) { 24 | el.classList.add("current"); 25 | } 26 | }); 27 | } 28 | }; 29 | return ( 30 |
31 |
32 | {btns.map((btn) => { 33 | return ( 34 | 40 | {btn} 41 | 42 | ); 43 | })} 44 |
45 |
46 | ); 47 | } 48 | -------------------------------------------------------------------------------- /src/components/WorksFilter.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import { connect } from "react-redux"; 3 | import { 4 | sortRateDescending, 5 | sortRateAscending, 6 | sortDateDescending, 7 | sortDateAscending, 8 | sortTitleA_Z, 9 | sortTitleZ_A, 10 | filterByLanguage, 11 | initFilteredList, 12 | filterByGenre, 13 | } from "../redux/actions"; 14 | const mapStateToProps = (state, props) => { 15 | return { ...state, ...props }; 16 | }; 17 | export default connect(mapStateToProps, { 18 | sortRateDescending, 19 | sortRateAscending, 20 | sortTitleA_Z, 21 | sortTitleZ_A, 22 | sortDateDescending, 23 | sortDateAscending, 24 | filterByLanguage, 25 | initFilteredList, 26 | filterByGenre, 27 | })(function WorksFilter({ 28 | list, 29 | filteredList, 30 | label, 31 | sortRateDescending, 32 | sortRateAscending, 33 | sortTitleA_Z, 34 | sortTitleZ_A, 35 | sortDateDescending, 36 | sortDateAscending, 37 | filterByLanguage, 38 | initFilteredList, 39 | filterByGenre, 40 | }) { 41 | const [genres, setgenres] = useState([]); 42 | const [currentSort, setcurrentSort] = useState("None"); 43 | const [currentFilter, setcurrentFilter] = useState("None"); 44 | 45 | useEffect(() => { 46 | setcurrentSort("None"); 47 | setcurrentFilter("None"); 48 | initFilteredList(list); 49 | setgenres([]); 50 | }, [list]); 51 | 52 | const genresList = [ 53 | { name: "Action", id: 28 }, 54 | { name: "Adventure", id: 12 }, 55 | { name: "Animation", id: 16 }, 56 | { name: "Comedy", id: 35 }, 57 | { name: "Crime", id: 80 }, 58 | { name: "Documentary", id: 99 }, 59 | { name: "Drama", id: 18 }, 60 | { name: "Family", id: 10751 }, 61 | { name: "Fantasy", id: 14 }, 62 | { name: "History", id: 36 }, 63 | { name: "Horror", id: 27 }, 64 | { name: "Music", id: 10402 }, 65 | { name: "Mystery", id: 9648 }, 66 | { name: "Romance", id: 10749 }, 67 | { name: "Science Fiction", id: 878 }, 68 | { name: "TV Movie", id: 10770 }, 69 | { name: "Thriller", id: 53 }, 70 | { name: "War", id: 10752 }, 71 | { name: "Western", id: 37 }, 72 | ]; 73 | 74 | const renderLanguages = () => { 75 | let Arr = []; 76 | const languages = [...new Set(list?.map((el) => el.original_language))]; 77 | languages.map((lang) => { 78 | const count = list?.filter((el) => { 79 | return el.original_language === lang; 80 | }).length; 81 | Arr.push({ language: lang?.toUpperCase(), count }); 82 | }); 83 | return Arr; 84 | }; 85 | useEffect(() => { 86 | filterByGenre(list, genres); 87 | if (!genres.length) initFilteredList(list); 88 | }, [genres]); 89 | 90 | return ( 91 |
92 | {label ? : null} 93 |
94 |
95 |
96 |
Sort
97 |
98 |

Sort Results By

99 |
100 | 110 |
    114 |
  • 115 | 124 |
  • 125 |
  • 126 | 135 |
  • 136 |
  • 137 | 146 |
  • 147 |
  • 148 | 157 |
  • 158 |
  • 159 | 168 |
  • 169 |
  • 170 | 179 |
  • 180 |
  • 181 | 190 |
  • 191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
Filters
201 |
202 |
203 |

Language

204 |
205 | 215 |
    219 |
  • 220 | 229 |
  • 230 | {[...renderLanguages()].map((el) => { 231 | return ( 232 |
  • 233 | 243 |
  • 244 | ); 245 | })} 246 |
247 |
248 |
249 |
250 |

Genres

251 |
252 | {genresList.map((el) => { 253 | return ( 254 | 271 | ); 272 | })} 273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 | ); 281 | }); 282 | -------------------------------------------------------------------------------- /src/components/WorksSlider.jsx: -------------------------------------------------------------------------------- 1 | import React, { useRef } from "react"; 2 | import { connect } from "react-redux"; 3 | import MovieSerieView from "./MovieSerieView"; 4 | // import Swiper core and required modules 5 | import { Navigation, Scrollbar, Autoplay } from "swiper"; 6 | import { Swiper, SwiperSlide } from "swiper/react"; 7 | import { 8 | getPopularMovies, 9 | getPopularTv, 10 | getPopularPeople, 11 | } from "../redux/actions"; 12 | 13 | // Import Swiper styles 14 | import "swiper/css"; 15 | import "swiper/css/navigation"; 16 | import "swiper/css/scrollbar"; 17 | import "swiper/css/pagination"; 18 | 19 | import "../styles/works_slider.sass"; 20 | 21 | export default connect(null, { 22 | getPopularTv, 23 | getPopularMovies, 24 | getPopularPeople, 25 | })(function WorksSlider(props) { 26 | const ref = useRef(""); 27 | const off = useRef(""); 28 | 29 | const moveBtnBackground = (e) => { 30 | const offset = off.current.getBoundingClientRect().left; 31 | const width = e.target.getBoundingClientRect().width; 32 | const left = e.target.getBoundingClientRect().left - offset; 33 | ref.current.style.width = `${width - 1}px`; 34 | ref.current.style.left = `${left - 1}px`; 35 | setTimeout(() => { 36 | ref.current.innerHTML = e.target.innerHTML; 37 | }, 250); 38 | }; 39 | 40 | const renderResults = () => { 41 | return props.works.map((el) => { 42 | return ( 43 | 44 | 45 | 46 | ); 47 | }); 48 | }; 49 | 50 | const renderBtns = () => { 51 | return props.btnsGroup.map((el, index) => { 52 | return ( 53 | 62 | ); 63 | }); 64 | }; 65 | return ( 66 |
67 |
68 |
69 |
70 |
71 | 72 | 73 | {props.title} 74 | 75 | 76 |
77 |
80 |
83 |
84 |
85 | 86 | 87 | {props.btnsGroup[0]} 88 | 89 |
{renderBtns()}
90 |
91 |
92 |
93 | 123 | {renderResults()} 124 | 125 |
126 |
127 |
128 |
129 | ); 130 | }); 131 | -------------------------------------------------------------------------------- /src/components/_404.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import { Link } from "react-router-dom"; 3 | 4 | export default function _404() { 5 | useEffect(() => { 6 | document.title = `NETFLIX | 404 NOT FOUND`; 7 | }, []); 8 | return ( 9 | <> 10 |
14 |

15 | 404 16 |

17 | 26 | Back To Homepage 27 | 28 |
29 | 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /src/helpers/scrollToTop.js: -------------------------------------------------------------------------------- 1 | export default () => { 2 | document.body.scrollTop = 0; 3 | document.documentElement.scrollTop = 0; 4 | }; 5 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /// MODULES 2 | import React from "react"; 3 | import thunk from "redux-thunk"; 4 | import ReactDOM from "react-dom"; 5 | import { Provider } from "react-redux"; 6 | import reducers from "./redux/reducers"; 7 | import { createStore, compose, applyMiddleware } from "redux"; 8 | 9 | /// STYLES 10 | import "../node_modules/bootstrap/dist/css/bootstrap.min.css"; 11 | import "../node_modules/bootstrap/dist/js/bootstrap.bundle"; 12 | import "./styles/normalize.sass"; 13 | 14 | /// COMPONENTS 15 | import App from "./components/App"; 16 | 17 | const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; 18 | const store = createStore(reducers, composeEnhancers(applyMiddleware(thunk))); 19 | 20 | ReactDOM.render( 21 | 22 | 23 | , 24 | document.getElementById("root") 25 | ); 26 | -------------------------------------------------------------------------------- /src/redux/actions/changeIsLoggedIn.js: -------------------------------------------------------------------------------- 1 | const changeIsLoggedIn = () => { 2 | return { 3 | type: "CHANGE_LOG_STATE", 4 | }; 5 | }; 6 | 7 | export default changeIsLoggedIn; 8 | -------------------------------------------------------------------------------- /src/redux/actions/clear.js: -------------------------------------------------------------------------------- 1 | const clear = () => { 2 | return { 3 | type: "CLEAR", 4 | payload: null, 5 | }; 6 | }; 7 | 8 | export default clear; 9 | -------------------------------------------------------------------------------- /src/redux/actions/filterByGenre.js: -------------------------------------------------------------------------------- 1 | const filterByGenre = (list, genres) => { 2 | return { 3 | type: "FILTER_BY_GENRE", 4 | payload: list?.filter((el) => { 5 | return el?.genre_ids?.find((g) => { 6 | return genres?.includes(g); 7 | }); 8 | }), 9 | }; 10 | }; 11 | export default filterByGenre; 12 | -------------------------------------------------------------------------------- /src/redux/actions/filterByLanguage.js: -------------------------------------------------------------------------------- 1 | const filterByLanguage = (list, language) => { 2 | if (!language) { 3 | return { 4 | type: "FILTER_BY_LANGUAGE", 5 | payload: [], 6 | }; 7 | } 8 | const newList = list.filter((el) => { 9 | return el.original_language === language.toLowerCase(); 10 | }); 11 | return { 12 | type: "FILTER_BY_LANGUAGE", 13 | payload: newList, 14 | }; 15 | }; 16 | export default filterByLanguage; 17 | -------------------------------------------------------------------------------- /src/redux/actions/filterByMediaType.js: -------------------------------------------------------------------------------- 1 | const filterByMediaType = (list, type) => { 2 | if (!type) { 3 | return { 4 | type: "FILTER_BY_MEDIA_TYPE", 5 | payload: [], 6 | }; 7 | } 8 | const newList = list.filter((el) => { 9 | return el.media_type === type; 10 | }); 11 | return { 12 | type: "FILTER_BY_MEDIA_TYPE", 13 | payload: newList, 14 | }; 15 | }; 16 | export default filterByMediaType; 17 | -------------------------------------------------------------------------------- /src/redux/actions/getMovieById.js: -------------------------------------------------------------------------------- 1 | import tmdb from "../../apis/tmdb"; 2 | 3 | const getMovieById = (id) => { 4 | return async function (dispatch) { 5 | try { 6 | const res = await tmdb.get(`/movie/${id}`, { 7 | params: { 8 | append_to_response: 9 | "videos,images,credits,reviews,keywords,release_dates,external_ids", 10 | }, 11 | }); 12 | 13 | dispatch({ 14 | type: "GET_MOVIE", 15 | payload: res.data, 16 | }); 17 | } catch (error) { 18 | dispatch({ 19 | type: "GET_MOVIE", 20 | payload: error.response.data, 21 | }); 22 | } 23 | }; 24 | }; 25 | export default getMovieById; 26 | -------------------------------------------------------------------------------- /src/redux/actions/getNowPlayingMovies.js: -------------------------------------------------------------------------------- 1 | import tmdb from "../../apis/tmdb"; 2 | 3 | const getNowPlayingMovies = (page = 1) => { 4 | return async function (dispatch) { 5 | const res = await tmdb.get("/movie/now_playing", { 6 | params: { 7 | language: "en-US", 8 | page, 9 | }, 10 | }); 11 | dispatch({ 12 | type: "GET_NOW_PLAYING_TMDB_MOVIES", 13 | payload: res.data.results, 14 | }); 15 | }; 16 | }; 17 | export default getNowPlayingMovies; 18 | -------------------------------------------------------------------------------- /src/redux/actions/getNowPlayingTv.js: -------------------------------------------------------------------------------- 1 | import tmdb from "../../apis/tmdb"; 2 | 3 | const getNowPlayingTv = (page = 1) => { 4 | return async function (dispatch) { 5 | const res = await tmdb.get("/tv/airing_today", { 6 | params: { 7 | language: "en-US", 8 | page, 9 | }, 10 | }); 11 | dispatch({ 12 | type: "GET_NOW_PLAYING_TMDB_TV", 13 | payload: res.data.results, 14 | }); 15 | }; 16 | }; 17 | export default getNowPlayingTv; 18 | -------------------------------------------------------------------------------- /src/redux/actions/getOnTheAirTv.js: -------------------------------------------------------------------------------- 1 | import tmdb from "../../apis/tmdb"; 2 | 3 | const getOnTheAirTv = (page = 1) => { 4 | return async function (dispatch) { 5 | const res = await tmdb.get("/tv/on_the_air", { 6 | params: { 7 | language: "en-US", 8 | page, 9 | }, 10 | }); 11 | dispatch({ 12 | type: "GET_ON_AIR_TMDB_TV", 13 | payload: res.data.results, 14 | }); 15 | }; 16 | }; 17 | export default getOnTheAirTv; 18 | -------------------------------------------------------------------------------- /src/redux/actions/getPeople.js: -------------------------------------------------------------------------------- 1 | import tmdb from "../../apis/tmdb"; 2 | 3 | const getPeople = (page = 1) => { 4 | return async function (dispatch) { 5 | try { 6 | const res = await tmdb.get("/person/popular", { 7 | params: { 8 | language: "en-US", 9 | page, 10 | }, 11 | }); 12 | dispatch({ 13 | type: "GET_PEOPLE", 14 | payload: res.data.results, 15 | }); 16 | } catch (error) { 17 | dispatch({ 18 | type: "GET_PEOPLE", 19 | payload: error.response.data.errors, 20 | }); 21 | } 22 | }; 23 | }; 24 | 25 | export default getPeople; 26 | -------------------------------------------------------------------------------- /src/redux/actions/getPersonById.js: -------------------------------------------------------------------------------- 1 | import tmdb from "../../apis/tmdb"; 2 | 3 | const getPersonById = (id) => { 4 | return async function (dispatch) { 5 | try { 6 | const res = await tmdb.get(`/person/${id}`, { 7 | params: { 8 | append_to_response: "combined_credits,external_ids", 9 | }, 10 | }); 11 | 12 | dispatch({ 13 | type: "GET_PERSON", 14 | payload: res.data, 15 | }); 16 | } catch (error) { 17 | dispatch({ 18 | type: "GET_PERSON", 19 | payload: error.response.data, 20 | }); 21 | } 22 | }; 23 | }; 24 | export default getPersonById; 25 | -------------------------------------------------------------------------------- /src/redux/actions/getPopularMovies.js: -------------------------------------------------------------------------------- 1 | import tmdb from "../../apis/tmdb"; 2 | 3 | const getPopularMovies = (page = 1) => { 4 | return async function (dispatch) { 5 | const res = await tmdb.get("/movie/popular", { 6 | params: { 7 | language: "en-US", 8 | page, 9 | append_to_response: "release_dates", 10 | }, 11 | }); 12 | dispatch({ 13 | type: "GET_POPULAR_TMDB_MOVIES", 14 | payload: res.data.results, 15 | }); 16 | }; 17 | }; 18 | 19 | export default getPopularMovies; 20 | -------------------------------------------------------------------------------- /src/redux/actions/getPopularPeople.js: -------------------------------------------------------------------------------- 1 | import tmdb from "../../apis/tmdb"; 2 | 3 | const getPopularPeople = (page = 1) => { 4 | return async function (dispatch) { 5 | const res = await tmdb.get("/person/popular", { 6 | params: { 7 | language: "en-US", 8 | page, 9 | }, 10 | }); 11 | dispatch({ 12 | type: "GET_POPULAR_TMDB_PEOPLE", 13 | payload: res.data.results, 14 | }); 15 | }; 16 | }; 17 | export default getPopularPeople; 18 | -------------------------------------------------------------------------------- /src/redux/actions/getPopularTv.js: -------------------------------------------------------------------------------- 1 | import tmdb from "../../apis/tmdb"; 2 | 3 | const getPopularTv = (page = 1) => { 4 | return async function (dispatch) { 5 | const res = await tmdb.get("/tv/popular", { 6 | params: { 7 | language: "en-US", 8 | page, 9 | }, 10 | }); 11 | dispatch({ 12 | type: "GET_POPULAR_TMDB_SERIES", 13 | payload: res.data.results, 14 | }); 15 | }; 16 | }; 17 | 18 | export default getPopularTv; 19 | -------------------------------------------------------------------------------- /src/redux/actions/getSerieById.js: -------------------------------------------------------------------------------- 1 | import tmdb from "../../apis/tmdb"; 2 | 3 | const getSerieById = (id) => { 4 | return async function (dispatch) { 5 | try { 6 | const res = await tmdb.get(`/tv/${id}`, { 7 | params: { 8 | append_to_response: 9 | "videos,images,credits,reviews,keywords,seasons,episodes,networks,languages,release_dates,external_ids", 10 | }, 11 | }); 12 | dispatch({ 13 | type: "GET_SERIE", 14 | payload: res.data, 15 | }); 16 | } catch (error) { 17 | dispatch({ 18 | type: "GET_SERIE", 19 | payload: error.response.data, 20 | }); 21 | } 22 | }; 23 | }; 24 | export default getSerieById; 25 | -------------------------------------------------------------------------------- /src/redux/actions/getSerieEpisodes.js: -------------------------------------------------------------------------------- 1 | import tmdb from "../../apis/tmdb"; 2 | 3 | const getSerieEpisodes = (id, season, episode) => { 4 | return async function (dispatch) { 5 | try { 6 | const res = await tmdb.get( 7 | `/tv/${id}/season/${season}/episode/${episode}` 8 | ); 9 | dispatch({ 10 | type: "GET_TV_EPISODES", 11 | payload: res.data, 12 | }); 13 | } catch (error) { 14 | dispatch({ 15 | type: "GET_TV_EPISODES", 16 | payload: error.response.data, 17 | }); 18 | } 19 | }; 20 | }; 21 | export default getSerieEpisodes; 22 | -------------------------------------------------------------------------------- /src/redux/actions/getTmdbTrendings.js: -------------------------------------------------------------------------------- 1 | import tmdb from "../../apis/tmdb"; 2 | 3 | const getTMDBTrendings = () => { 4 | return async function (dispatch) { 5 | const res = await tmdb.get("/trending/all/day"); 6 | dispatch({ 7 | type: "GET_TMDB_TRENDINGS", 8 | payload: res.data.results, 9 | }); 10 | }; 11 | }; 12 | 13 | export default getTMDBTrendings; 14 | -------------------------------------------------------------------------------- /src/redux/actions/getTopMovies.js: -------------------------------------------------------------------------------- 1 | import tmdb from "../../apis/tmdb"; 2 | 3 | const getTopMovies = (page = 1) => { 4 | return async function (dispatch) { 5 | const res = await tmdb.get("/movie/top_rated", { 6 | params: { 7 | language: "en-US", 8 | page, 9 | }, 10 | }); 11 | dispatch({ 12 | type: "GET_TOP_TMDB_MOVIES", 13 | payload: res.data.results, 14 | }); 15 | }; 16 | }; 17 | export default getTopMovies; 18 | -------------------------------------------------------------------------------- /src/redux/actions/getTopTv.js: -------------------------------------------------------------------------------- 1 | import tmdb from "../../apis/tmdb"; 2 | 3 | const getTopTv = (page = 1) => { 4 | return async function (dispatch) { 5 | const res = await tmdb.get("/tv/top_rated", { 6 | params: { 7 | language: "en-US", 8 | page, 9 | }, 10 | }); 11 | dispatch({ 12 | type: "GET_TOP_TMDB_TV", 13 | payload: res.data.results, 14 | }); 15 | }; 16 | }; 17 | export default getTopTv; 18 | -------------------------------------------------------------------------------- /src/redux/actions/getUpcomingMovies.js: -------------------------------------------------------------------------------- 1 | import tmdb from "../../apis/tmdb"; 2 | 3 | const getUpcomingMovies = (page = 1) => { 4 | return async function (dispatch) { 5 | const res = await tmdb.get("/movie/upcoming", { 6 | params: { 7 | language: "en-US", 8 | page, 9 | append_to_response: "release_dates", 10 | }, 11 | }); 12 | dispatch({ 13 | type: "GET_UPCOMING_TMDB_MOVIES", 14 | payload: res.data.results, 15 | }); 16 | }; 17 | }; 18 | export default getUpcomingMovies; 19 | -------------------------------------------------------------------------------- /src/redux/actions/index.js: -------------------------------------------------------------------------------- 1 | import changeIsLoggedIn from "./changeIsLoggedIn"; 2 | import getTMDBTrendings from "./getTmdbTrendings"; 3 | import getPopularMovies from "./getPopularMovies"; 4 | import getPopularTv from "./getPopularTv"; 5 | import getPopularPeople from "./getPopularPeople"; 6 | import getNowPlayingMovies from "./getNowPlayingMovies"; 7 | import getNowPlayingTv from "./getNowPlayingTv"; 8 | import getTopMovies from "./getTopMovies"; 9 | import getTopTv from "./getTopTv"; 10 | import getMovieById from "./getMovieById"; 11 | import getSerieById from "./getSerieById"; 12 | import getUpcomingMovies from "./getUpcomingMovies"; 13 | import getSerieEpisodes from "./getSerieEpisodes"; 14 | import getOnTheAirTv from "./getOnTheAirTv"; 15 | import sortTitleA_Z from "./sortTitleA_Z"; 16 | import sortTitleZ_A from "./sortTitleZ_A"; 17 | import sortDateAscending from "./sortDateAscending"; 18 | import sortDateDescending from "./sortDateDescending"; 19 | import sortRateAscending from "./sortRateAscending"; 20 | import sortRateDescending from "./sortRateDescending"; 21 | import filterByLanguage from "./filterByLanguage"; 22 | import initFilteredList from "./initFilteredList"; 23 | import filterByGenre from "./filterByGenre"; 24 | import getPeople from "./getPeople"; 25 | import clear from "./clear"; 26 | import getPersonById from "./getPersonById"; 27 | import searchTMDB from "./searchTMDB"; 28 | import filterByMediaType from "./filterByMediaType"; 29 | export { 30 | changeIsLoggedIn, 31 | getTMDBTrendings, 32 | getPopularMovies, 33 | getPopularTv, 34 | getPopularPeople, 35 | getNowPlayingMovies, 36 | getNowPlayingTv, 37 | getTopMovies, 38 | getTopTv, 39 | getSerieById, 40 | getMovieById, 41 | getUpcomingMovies, 42 | getOnTheAirTv, 43 | sortTitleA_Z, 44 | sortTitleZ_A, 45 | sortDateAscending, 46 | sortDateDescending, 47 | sortRateAscending, 48 | sortRateDescending, 49 | filterByLanguage, 50 | initFilteredList, 51 | filterByGenre, 52 | getSerieEpisodes, 53 | clear, 54 | getPeople, 55 | getPersonById, 56 | searchTMDB, 57 | filterByMediaType, 58 | }; 59 | -------------------------------------------------------------------------------- /src/redux/actions/initFilteredList.js: -------------------------------------------------------------------------------- 1 | const initFilteredList = (list) => { 2 | return { 3 | type: "INIT_LIST", 4 | payload: list, 5 | }; 6 | }; 7 | export default initFilteredList; 8 | -------------------------------------------------------------------------------- /src/redux/actions/searchTMDB.js: -------------------------------------------------------------------------------- 1 | import tmdb from "../../apis/tmdb"; 2 | 3 | const searchTMDB = (query, page = 1) => { 4 | return async function (dispatch) { 5 | try { 6 | const res = await tmdb.get(`/search/multi`, { 7 | params: { 8 | query, 9 | page, 10 | }, 11 | }); 12 | console.log(res); 13 | dispatch({ 14 | type: "SEARCH_TMDB", 15 | payload: res.data.results, 16 | }); 17 | } catch (error) { 18 | dispatch({ 19 | type: "SEARCH_TMDB", 20 | payload: error.response.data, 21 | }); 22 | } 23 | }; 24 | }; 25 | export default searchTMDB; 26 | -------------------------------------------------------------------------------- /src/redux/actions/sortDateAscending.js: -------------------------------------------------------------------------------- 1 | const sortDateAscending = (list) => { 2 | return { 3 | type: "SORT_DATE_DES", 4 | payload: list.sort((curr, next) => { 5 | return ( 6 | Date.parse(curr.release_date) - Date.parse(next.release_date) || 7 | Date.parse(curr.first_air_date) - Date.parse(next.first_air_date) 8 | ); 9 | }), 10 | }; 11 | }; 12 | export default sortDateAscending; 13 | -------------------------------------------------------------------------------- /src/redux/actions/sortDateDescending.js: -------------------------------------------------------------------------------- 1 | const sortDateDescending = (list) => { 2 | return { 3 | type: "SORT_DATE_DES", 4 | payload: list.sort((curr, next) => { 5 | return ( 6 | Date.parse(next.release_date) - Date.parse(curr.release_date) || 7 | Date.parse(next.first_air_date) - Date.parse(curr.first_air_date) 8 | ); 9 | }), 10 | }; 11 | }; 12 | export default sortDateDescending; 13 | -------------------------------------------------------------------------------- /src/redux/actions/sortRateAscending.js: -------------------------------------------------------------------------------- 1 | const sortRateAscending = (list) => { 2 | return { 3 | type: "SORT_RATE_AS", 4 | payload: list.sort((curr, next) => { 5 | return curr.vote_average - next.vote_average; 6 | }), 7 | }; 8 | }; 9 | export default sortRateAscending; 10 | -------------------------------------------------------------------------------- /src/redux/actions/sortRateDescending.js: -------------------------------------------------------------------------------- 1 | const sortRateDescending = (list) => { 2 | return { 3 | type: "SORT_RATE_DES", 4 | payload: list.sort((curr, next) => { 5 | return next.vote_average - curr.vote_average; 6 | }), 7 | }; 8 | }; 9 | export default sortRateDescending; 10 | -------------------------------------------------------------------------------- /src/redux/actions/sortTitleA_Z.js: -------------------------------------------------------------------------------- 1 | const sortTitleA_Z = (list) => { 2 | const titles = list.map((el) => el.title || el.name).sort(); 3 | return { 4 | type: "SORT_TITLE_A_Z", 5 | payload: titles.map((title) => { 6 | return list.find((el) => { 7 | return el.title === title || el.name === title; 8 | }); 9 | }), 10 | }; 11 | }; 12 | export default sortTitleA_Z; 13 | -------------------------------------------------------------------------------- /src/redux/actions/sortTitleZ_A.js: -------------------------------------------------------------------------------- 1 | const sortTitleZ_A = (list) => { 2 | const titles = list 3 | .map((el) => el.title || el.name) 4 | .sort() 5 | .reverse(); 6 | return { 7 | type: "SORT_TITLE_Z_A", 8 | payload: titles.map((title) => { 9 | return list.find((el) => { 10 | return el.title === title || el.name === title; 11 | }); 12 | }), 13 | }; 14 | }; 15 | export default sortTitleZ_A; 16 | -------------------------------------------------------------------------------- /src/redux/reducers/Episodes.js: -------------------------------------------------------------------------------- 1 | const Episodes = (episodes = [], action) => { 2 | if (action.type === "GET_TV_EPISODES") { 3 | return [...episodes, action.payload]; 4 | } 5 | return []; 6 | }; 7 | 8 | export default Episodes; 9 | -------------------------------------------------------------------------------- /src/redux/reducers/Filter.js: -------------------------------------------------------------------------------- 1 | const FilteredList = (List = [], action) => { 2 | if (action.type === "INIT_LIST") { 3 | return [...action.payload]; 4 | } 5 | if (action.type === "SORT_RATE_DES") { 6 | return [...action.payload]; 7 | } 8 | if (action.type === "SORT_RATE_AS") { 9 | return [...action.payload]; 10 | } 11 | if (action.type === "SORT_DATE_DES") { 12 | return [...action.payload]; 13 | } 14 | if (action.type === "SORT_DATE_AS") { 15 | return [...action.payload]; 16 | } 17 | if (action.type === "SORT_TITLE_A_Z") { 18 | return [...action.payload]; 19 | } 20 | if (action.type === "SORT_TITLE_Z_A") { 21 | return [...action.payload]; 22 | } 23 | if (action.type === "FILTER_BY_LANGUAGE") { 24 | return [...action.payload]; 25 | } 26 | if (action.type === "FILTER_BY_GENRE") { 27 | return [...action.payload]; 28 | } 29 | if (action.type === "FILTER_BY_MEDIA_TYPE") { 30 | return [...action.payload]; 31 | } 32 | return []; 33 | }; 34 | 35 | export default FilteredList; 36 | -------------------------------------------------------------------------------- /src/redux/reducers/Movie.js: -------------------------------------------------------------------------------- 1 | const Movie = (movie = {}, action) => { 2 | if (action.type === "GET_MOVIE") { 3 | return { ...movie, ...action.payload }; 4 | } 5 | return {}; 6 | }; 7 | export default Movie; 8 | -------------------------------------------------------------------------------- /src/redux/reducers/Movies.js: -------------------------------------------------------------------------------- 1 | const Movies = (movies = [], action) => { 2 | if (action.type === "GET_POPULAR_TMDB_MOVIES") { 3 | return [...action.payload]; 4 | } 5 | if (action.type === "GET_TOP_TMDB_MOVIES") { 6 | return [...action.payload]; 7 | } 8 | if (action.type === "GET_NOW_PLAYING_TMDB_MOVIES") { 9 | return [...action.payload]; 10 | } 11 | if (action.type === "GET_UPCOMING_TMDB_MOVIES") { 12 | return [...action.payload]; 13 | } 14 | return movies; 15 | }; 16 | 17 | export default Movies; 18 | -------------------------------------------------------------------------------- /src/redux/reducers/Now_Playing.js: -------------------------------------------------------------------------------- 1 | const Now_Playing = (results = [], action) => { 2 | if (action.type === "GET_NOW_PLAYING_TMDB_MOVIES") { 3 | results = []; 4 | return [...results, ...action.payload]; 5 | } 6 | if (action.type === "GET_NOW_PLAYING_TMDB_TV") { 7 | results = []; 8 | return [...results, ...action.payload]; 9 | } 10 | return results; 11 | }; 12 | export default Now_Playing; 13 | -------------------------------------------------------------------------------- /src/redux/reducers/People.js: -------------------------------------------------------------------------------- 1 | const People = (people = [], action) => { 2 | if (action.type === "GET_PEOPLE") { 3 | return [...action.payload]; 4 | } 5 | return people; 6 | }; 7 | 8 | export default People; 9 | -------------------------------------------------------------------------------- /src/redux/reducers/Person.js: -------------------------------------------------------------------------------- 1 | const Person = (person = {}, action) => { 2 | if (action.type === "GET_PERSON") { 3 | return { ...person, ...action.payload }; 4 | } 5 | return {}; 6 | }; 7 | export default Person; 8 | -------------------------------------------------------------------------------- /src/redux/reducers/Populars.js: -------------------------------------------------------------------------------- 1 | const Populars = (results = [], action) => { 2 | if (action.type === "GET_POPULAR_TMDB_MOVIES") { 3 | results = []; 4 | return [...results, ...action.payload]; 5 | } 6 | if (action.type === "GET_POPULAR_TMDB_SERIES") { 7 | results = []; 8 | return [...results, ...action.payload]; 9 | } 10 | if (action.type === "GET_POPULAR_TMDB_PEOPLE") { 11 | results = []; 12 | return [...results, ...action.payload]; 13 | } 14 | return results; 15 | }; 16 | 17 | export default Populars; 18 | -------------------------------------------------------------------------------- /src/redux/reducers/Search.js: -------------------------------------------------------------------------------- 1 | const SearchList = (List = [], action) => { 2 | if (action.type === "SEARCH_TMDB") { 3 | return [...action.payload]; 4 | } 5 | 6 | if (action.type === "INIT_LIST") { 7 | return List; 8 | } 9 | if (action.type === "SORT_RATE_DES") { 10 | return List; 11 | } 12 | if (action.type === "SORT_RATE_AS") { 13 | return List; 14 | } 15 | if (action.type === "SORT_DATE_DES") { 16 | return List; 17 | } 18 | if (action.type === "SORT_DATE_AS") { 19 | return List; 20 | } 21 | if (action.type === "SORT_TITLE_A_Z") { 22 | return List; 23 | } 24 | if (action.type === "SORT_TITLE_Z_A") { 25 | return List; 26 | } 27 | if (action.type === "FILTER_BY_LANGUAGE") { 28 | return List; 29 | } 30 | if (action.type === "FILTER_BY_GENRE") { 31 | return List; 32 | } 33 | return []; 34 | }; 35 | 36 | export default SearchList; 37 | -------------------------------------------------------------------------------- /src/redux/reducers/Serie.js: -------------------------------------------------------------------------------- 1 | const Serie = (serie = {}, action) => { 2 | if (action.type === "GET_SERIE") { 3 | return { ...serie, ...action.payload }; 4 | } 5 | if (action.type === "GET_TV_EPISODES") { 6 | return { ...serie }; 7 | } 8 | return {}; 9 | }; 10 | export default Serie; 11 | -------------------------------------------------------------------------------- /src/redux/reducers/Series.js: -------------------------------------------------------------------------------- 1 | const Series = (series = [], action) => { 2 | if (action.type === "GET_POPULAR_TMDB_SERIES") { 3 | return [...action.payload]; 4 | } 5 | if (action.type === "GET_NOW_PLAYING_TMDB_TV") { 6 | return [...action.payload]; 7 | } 8 | if (action.type === "GET_TOP_TMDB_TV") { 9 | return [...action.payload]; 10 | } 11 | if (action.type === "GET_ON_AIR_TMDB_TV") { 12 | return [...action.payload]; 13 | } 14 | return series; 15 | }; 16 | export default Series; 17 | -------------------------------------------------------------------------------- /src/redux/reducers/TMDB_Trendings.js: -------------------------------------------------------------------------------- 1 | const TMDB_Trendings = (results = [], action) => { 2 | if (action.type === "GET_TMDB_TRENDINGS") { 3 | return action.payload; 4 | } 5 | return results; 6 | }; 7 | export default TMDB_Trendings; 8 | -------------------------------------------------------------------------------- /src/redux/reducers/Top_Rated.js: -------------------------------------------------------------------------------- 1 | const Top_Rated = (results = [], action) => { 2 | if (action.type === "GET_TOP_TMDB_MOVIES") { 3 | results = []; 4 | return [...results, ...action.payload]; 5 | } 6 | if (action.type === "GET_TOP_TMDB_TV") { 7 | results = []; 8 | return [...results, ...action.payload]; 9 | } 10 | return results; 11 | }; 12 | export default Top_Rated; 13 | -------------------------------------------------------------------------------- /src/redux/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from "redux"; 2 | 3 | import User_Login from "./userLogin"; 4 | import TMDB_Trendings from "./TMDB_Trendings"; 5 | import Populars from "./Populars"; 6 | import Now_Playing from "./Now_Playing"; 7 | import Top_Rated from "./Top_Rated"; 8 | import Movies from "./Movies"; 9 | import Series from "./Series"; 10 | import Movie from "./Movie"; 11 | import Serie from "./Serie"; 12 | import Episodes from "./Episodes"; 13 | import FilteredList from "./Filter"; 14 | import People from "./People"; 15 | import Person from "./Person"; 16 | import SearchList from "./Search"; 17 | 18 | export default combineReducers({ 19 | isUserLoggedIn: User_Login, 20 | trendings: TMDB_Trendings, 21 | populars: Populars, 22 | now_playing: Now_Playing, 23 | top_rated: Top_Rated, 24 | movies: Movies, 25 | series: Series, 26 | movie: Movie, 27 | serie: Serie, 28 | filteredList: FilteredList, 29 | episodes: Episodes, 30 | people: People, 31 | person: Person, 32 | search_list: SearchList, 33 | }); 34 | -------------------------------------------------------------------------------- /src/redux/reducers/userLogin.js: -------------------------------------------------------------------------------- 1 | const User_Login = (state = true, action) => { 2 | switch (action.type) { 3 | case "CHANGE_LOG_STATE": 4 | return !state; 5 | default: 6 | return state; 7 | } 8 | }; 9 | export default User_Login; 10 | -------------------------------------------------------------------------------- /src/styles/episode-item.sass: -------------------------------------------------------------------------------- 1 | @import './variables' 2 | 3 | 4 | .episodes-count span 5 | color: var(--bs-gray-600) 6 | font-size: 13px 7 | padding-left: 0.5rem 8 | .episode-item 9 | border-radius: .36rem 10 | overflow: hidden 11 | display: block 12 | color: $_bg-color !important 13 | border: 1px solid #00000057 14 | .episode-img-container 15 | position: relative 16 | height: 180px 17 | padding: 0 18 | &:hover 19 | .overlay 20 | top: 0 21 | .overlay 22 | display: flex 23 | justify-content: center 24 | align-items: center 25 | position: absolute 26 | width: 100% 27 | height: 100% 28 | top: 0 29 | left: 0 30 | z-index: 1 31 | background: #00000081 32 | top: -100% 33 | transition: .3s 34 | i 35 | &::before 36 | display: flex 37 | margin-right: -4px 38 | 39 | color: $netflix-white 40 | height: 45px 41 | width: 45px 42 | display: flex 43 | justify-content: center 44 | align-items: center 45 | font-size: 16px 46 | border: 3px solid #fff 47 | border-radius: 50% 48 | img 49 | width: 100% 50 | height: 100% 51 | object-fit: cover 52 | .episode-content 53 | padding: 1rem 54 | .episode-title 55 | font-weight: 500 56 | color: $_bg-color 57 | line-height: 5px 58 | span 59 | margin-right: 0.3rem 60 | .episode-date 61 | font-size: 12px 62 | .episode-overview 63 | font-size: 13px 64 | line-height: 1.25rem 65 | max-height: 4rem 66 | overflow: hidden 67 | -webkit-line-clamp: 3 68 | display: box 69 | display: -webkit-box 70 | -webkit-box-orient: vertical 71 | text-overflow: ellipsis 72 | white-space: normal -------------------------------------------------------------------------------- /src/styles/grid_test.sass: -------------------------------------------------------------------------------- 1 | @import './variables' 2 | 3 | .grid 4 | position: absolute 5 | left: 0 6 | top: 0 7 | width: 100% 8 | z-index: 10001 9 | #grid-btn 10 | position: fixed 11 | left: 0 12 | top: 0 13 | z-index: 2 14 | #bs-grid 15 | position: fixed 16 | width: 100% 17 | height: 100% 18 | z-index: 1 19 | .container 20 | height: 100% 21 | .row 22 | height: 100% 23 | .col div 24 | background: #0004ff1f 25 | height: 100% 26 | border-right: 1px solid #ff000044 27 | &:first-of-type 28 | border-left: 1px solid #ff000044 29 | -------------------------------------------------------------------------------- /src/styles/hero-slider.sass: -------------------------------------------------------------------------------- 1 | @import './variables' 2 | 3 | .hero-slider 4 | .hero-slide 5 | min-height: 880px 6 | padding-top: 113px 7 | .slider-wrapper 8 | // overflow: hidden 9 | .slide-bg-img 10 | z-index: 1 11 | position: absolute 12 | left: 0 13 | top: 0 14 | object-fit: cover 15 | width: 100% 16 | height: 100% 17 | .fluid-overlay 18 | z-index: 2 19 | position: absolute 20 | width: 100% 21 | height: 100% 22 | top: 0 23 | left: 0 24 | background-image: linear-gradient(to left,#00000018,#000) 25 | .slide-content 26 | position: absolute 27 | width: 100% 28 | display: flex 29 | z-index: 3 30 | margin-top: 60px 31 | .work-banner h2 32 | text-transform: uppercase 33 | line-height: 1 34 | padding: 1rem 0 35 | font-weight: 900 36 | .work-category 37 | display: flex 38 | align-items: center 39 | span 40 | letter-spacing: 6px 41 | .work-info 42 | align-items: center 43 | display: flex 44 | .work-info-tag 45 | margin: .5rem 0 46 | padding-right: 1rem 47 | font-weight: 500 48 | .age-class 49 | border: 2px solid $netflix-red 50 | text-align: center 51 | display: block 52 | border-radius: 1000px 53 | padding: .2rem 1rem 54 | margin-right: 1rem 55 | .work-description, 56 | .work-title 57 | line-height: 1.5rem 58 | max-height: 5rem 59 | overflow: hidden 60 | -webkit-line-clamp: 3 61 | display: box 62 | display: -webkit-box 63 | -webkit-box-orient: vertical 64 | text-overflow: ellipsis 65 | white-space: normal 66 | .work-actions-btns 67 | .btn 68 | background: $netflix-red 69 | color: $netflix-white 70 | border-radius: 1000px 71 | padding: 0.5rem 2rem 72 | text-transform: capitalize 73 | transition: .3s 74 | &:hover 75 | box-shadow: 1px 1px 10px $netflix-red 76 | .info-link-btn 77 | color: $bg-color 78 | background: $netflix-white 79 | &:hover 80 | box-shadow: 1px 1px 10px $netflix-white 81 | .swiper-button-prev, 82 | .swiper-button-next 83 | border-radius: 50% 84 | top: 35% 85 | transition: .2s 86 | width: 40px 87 | height: 40px 88 | background: $netflix-red 89 | color: $netflix-white 90 | &::after 91 | all: unset 92 | background: $netflix-red 93 | font-size: 20px 94 | font-family: 'Font Awesome 5 Pro' 95 | content: "\f053" 96 | &:hover 97 | box-shadow: 1px 1px 10px $netflix-red 98 | .swiper-button-prev 99 | left: 30px 100 | .swiper-button-next 101 | right: 30px 102 | &::after 103 | content: "\f054" 104 | .swiper-pagination 105 | margin: 1rem 0 106 | 107 | .swiper-pagination-bullet 108 | border-radius: 0 109 | height: 2px 110 | width: 50px 111 | background: $netflix-white 112 | .swiper-pagination-bullet-active 113 | height: 3px 114 | background: $netflix-red 115 | 116 | @media screen and (max-width : 991px) 117 | .swiper-button-prev, 118 | .swiper-button-next 119 | display: none 120 | .la-casa-banner 121 | width: 300px 122 | 123 | .squid_game_banner 124 | width: 180px 125 | margin: 1rem 0 126 | .hero-slide 127 | padding-top: 0px 128 | .work-info 129 | align-items: center 130 | flex-wrap: wrap 131 | .work-actions-btns 132 | .btn 133 | margin: .5rem .75rem .5rem 0 !important 134 | padding: 0.4rem 1rem !important -------------------------------------------------------------------------------- /src/styles/home_trendings.sass: -------------------------------------------------------------------------------- 1 | @import './variables' 2 | 3 | .home-trendings-slider-container 4 | position: relative 5 | top: -300px 6 | margin-bottom: -245px 7 | width: 100% 8 | z-index: 4 9 | min-height: 245px 10 | .swiper 11 | padding: 1rem 12 | .slider-title 13 | text-transform: capitalize 14 | font-size: 1.25rem 15 | .home-trendings-slider 16 | .swiper-wrapper 17 | margin-bottom: 1rem 18 | .swiper-slide 19 | transition: .2s 20 | &:hover 21 | transform: scale(1.1) 22 | .swiper-scrollbar 23 | width: calc( 100% - 30px ) 24 | left: 15px 25 | position: absolute 26 | bottom: 0 27 | // margin: auto 28 | .swiper-scrollbar-drag 29 | background: $netflix-red 30 | cursor: pointer -------------------------------------------------------------------------------- /src/styles/load-wrapper.sass: -------------------------------------------------------------------------------- 1 | @import './variables' 2 | 3 | .load-wrapper 4 | position: fixed 5 | left: 0 6 | top: 0 7 | width: 100% 8 | height: 100% 9 | z-index: 10000 10 | display: flex 11 | justify-content: center 12 | align-items: center 13 | background: $_bg-color 14 | transition: .7s 15 | .spinner-grow 16 | width: 5rem 17 | height: 5rem 18 | -------------------------------------------------------------------------------- /src/styles/main-menu.sass: -------------------------------------------------------------------------------- 1 | @import './variables' 2 | 3 | .main-menu 4 | background: $netflix-white 5 | color: $_bg-color 6 | .head-link 7 | color: $netflix-red 8 | font-weight: 700 9 | text-transform: uppercase 10 | letter-spacing: 6px 11 | .nav-list 12 | margin: 1rem 0 13 | a 14 | display: inline-block 15 | padding: .4rem 0 16 | color: $_bg-color 17 | p 18 | padding: 0 19 | margin: 0 20 | .rights 21 | color: $netflix-red 22 | margin: 5px 23 | font-weight: 600 24 | .social-links 25 | display: flex 26 | li 27 | margin: .5rem 2rem 28 | margin-left: 0 29 | margin-top: 0 30 | a 31 | color: $_bg-color 32 | font-size: 24px 33 | transition: all .3s 34 | &:hover 35 | color: $netflix-red 36 | 37 | @media screen and ( max-width: 991px ) 38 | .main-menu 39 | padding-bottom: 90px !important 40 | 41 | -------------------------------------------------------------------------------- /src/styles/mob-nav-menu.sass: -------------------------------------------------------------------------------- 1 | @import './variables' 2 | 3 | .mob-nav-menu 4 | position: fixed 5 | left: -100% 6 | top: 0 7 | width: 100% 8 | height: 100% 9 | background-color: $_bg-color 10 | z-index: 1001 11 | header 12 | padding: 2rem 15px 13 | ul 14 | li.active 15 | border-left: 4px solid $netflix-red 16 | background: linear-gradient(to right,#ffffff2d,#ffffff00)!important 17 | li 18 | margin: 1rem 0 19 | a 20 | text-transform: capitalize 21 | font-weight: 300 22 | font-size: 16px 23 | color: $netflix-white 24 | padding: 1rem 25 | display: inline-block 26 | .mob-nav-menu.show 27 | left: 0 28 | transition: linear 1s 29 | -------------------------------------------------------------------------------- /src/styles/mouse.sass: -------------------------------------------------------------------------------- 1 | @import './variables' 2 | 3 | .mouse 4 | position: absolute 5 | left: 0 6 | top: 0 7 | display: block 8 | width: 30px 9 | height: 30px 10 | border-radius: 50% 11 | background: $netflix-red 12 | z-index: 111 13 | opacity: .6 14 | transition: linear .1s -------------------------------------------------------------------------------- /src/styles/movie_details_page.sass: -------------------------------------------------------------------------------- 1 | @import './variables' 2 | 3 | .movie-details-page 4 | position: relative 5 | .movie-trailer 6 | .trailer-area 7 | iframe 8 | width: 100% 9 | height: 540px 10 | .movie-page-hero 11 | position: relative 12 | .movie-backdrop 13 | position: absolute 14 | height: 100% 15 | width: 100% 16 | z-index: 1 17 | .movie-backdrop-img 18 | width: 100% 19 | height: 100% 20 | object-fit: cover 21 | .fluid-overlay 22 | background-image: linear-gradient(to left,#00000018,#000) 23 | position: absolute 24 | width: 100% 25 | height: 100% 26 | z-index: 2 27 | .movie-hero-content 28 | padding-top: 113px 29 | padding-bottom: 55px 30 | position: relative 31 | z-index: 3 32 | display: flex 33 | align-items: center 34 | .movie-poster 35 | width: 80% 36 | border-radius: .75rem 37 | overflow: hidden 38 | box-shadow: 1px 1px 10px #0000007c 39 | .movie-poster-img 40 | // height: 360px 41 | width: 100% 42 | object-position: center 43 | object-fit: cover 44 | .movie-title 45 | text-transform: uppercase 46 | font-weight: 700 47 | .work-info 48 | align-items: center 49 | .work-info-tag 50 | padding-right: 1rem 51 | font-weight: 500 52 | .age-class 53 | border: 2px solid $netflix-red 54 | text-align: center 55 | display: block 56 | border-radius: 1000px 57 | padding: .2rem 1rem 58 | margin-right: 1rem 59 | .user-actions 60 | .work-rating 61 | position: initial 62 | transform: scale(1.5) 63 | margin-left: 15px 64 | .work-actions-btns 65 | .btn 66 | background: $netflix-red 67 | color: $netflix-white 68 | border-radius: 1000px 69 | padding: 0.5rem 2rem 70 | text-transform: capitalize 71 | transition: .3s 72 | &:hover 73 | box-shadow: 1px 1px 10px $netflix-red 74 | .info-link-btn 75 | color: $bg-color 76 | background: $netflix-white 77 | &:hover 78 | box-shadow: 1px 1px 10px $netflix-white 79 | .work-details-area 80 | .work-main-data 81 | .work-social-links 82 | a 83 | color: $netflix-white 84 | font-size: 24px 85 | .work-info-item 86 | .title, 87 | .value 88 | text-transform: capitalize 89 | padding: 0 90 | margin: 0 91 | .title 92 | font-weight: 600 93 | font-size: 16px 94 | .value 95 | font-weight: 300 96 | .works-keywords 97 | li 98 | display: inline-block 99 | .network-img 100 | padding: 5px 101 | background: #fff 102 | .badge 103 | font-size: 14px 104 | font-weight: 400 105 | margin-top: 12.5px 106 | margin-right: 12.5px 107 | line-height: 1.25 108 | .uppercase 109 | text-transform: uppercase 110 | .swiper-scrollbar 111 | width: 100% 112 | left: 0 113 | position: absolute 114 | 115 | .serie-seasons-area 116 | background: $netflix-white 117 | color: $_bg-color 118 | .season-container 119 | // height: 200px 120 | overflow: hidden 121 | border-radius: .5rem 122 | border: 1px solid #AAA 123 | margin-bottom: 30px 124 | .season-overview 125 | line-height: 1.5rem 126 | max-height: 5rem 127 | overflow: hidden 128 | -webkit-line-clamp: 3 129 | display: box 130 | display: -webkit-box 131 | -webkit-box-orient: vertical 132 | text-overflow: ellipsis 133 | margin: 1rem 0 134 | white-space: normal 135 | color: var(--bs-gray-700) 136 | .season-poster a 137 | width: 100% 138 | display: block 139 | height: 210px 140 | .season-poster-img 141 | width: 100% 142 | height: 100% 143 | object-fit: cover -------------------------------------------------------------------------------- /src/styles/movie_serie_view.sass: -------------------------------------------------------------------------------- 1 | @import './variables' 2 | 3 | .MovieSerieView 4 | display: block 5 | color: $netflix-white !important 6 | .poster-img-container 7 | overflow: hidden 8 | position: relative 9 | border-radius: .6rem 10 | box-shadow: 1px 1px 10px #00000034 11 | min-height: 200px 12 | .watch-btn 13 | z-index: 3 14 | position: absolute 15 | left: 50% 16 | top: 0 17 | transform: translate(-50%,-100%) 18 | transition: .3s 19 | color: $netflix-white 20 | i.fa-eye 21 | width: 50px 22 | height: 50px 23 | border-radius: 50% 24 | display: flex 25 | justify-content: center 26 | align-items: center 27 | i 28 | display: flex 29 | transition: .3s 30 | border-radius: 50% 31 | &:hover 32 | color: $netflix-white 33 | background: $netflix-red 34 | 35 | .overlay 36 | width: 100% 37 | height: 100% 38 | border-radius: .5rem 39 | overflow: hidden 40 | z-index: 2 41 | background: #00000071 42 | position: absolute 43 | left: 0 44 | top: -250px 45 | transition: .3s 46 | display: flex 47 | justify-content: center 48 | align-items: center 49 | &:hover 50 | .overlay 51 | top: 0 52 | .watch-btn 53 | top: 50% 54 | transform: translate(-50%,-50%) 55 | .work-poster 56 | width: 100% 57 | height: 250px 58 | object-fit: cover 59 | object-position: center 60 | border-radius: .5rem 61 | z-index: 1 62 | .work-info 63 | .work-title 64 | color: $netflix-white 65 | font-size: 1rem 66 | line-height: 1.25rem 67 | max-height: 2.5rem 68 | overflow: hidden 69 | margin-bottom: .25rem 70 | margin-top: 1.5rem 71 | text-overflow: ellipsis 72 | .work-date 73 | color: #ffffff56 74 | .ribbon-container 75 | z-index: 3 76 | position: absolute 77 | width: 75px 78 | height: 75px 79 | left: -5px 80 | top: 2px 81 | overflow: hidden 82 | .ribbon 83 | text-transform: uppercase 84 | display: flex 85 | justify-content: center 86 | align-items: center 87 | width: 100px 88 | background: $netflix-red 89 | position: absolute 90 | top: 19px 91 | left: -21px 92 | transform: rotate(-45deg) 93 | &::before 94 | content: '' 95 | position: absolute 96 | left: 0 97 | top: 100% 98 | z-index: -1 99 | border-left: 3px solid $netflix-red 100 | border-right: 3px solid transparent 101 | border-bottom: 3px solid transparent 102 | border-top: 3px solid $netflix-red 103 | &::after 104 | content: '' 105 | position: absolute 106 | right: 0% 107 | top: 100% 108 | z-index: -1 109 | border-right: 3px solid $netflix-red 110 | border-left: 3px solid transparent 111 | border-bottom: 3px solid transparent 112 | border-top: 3px solid $netflix-red 113 | -------------------------------------------------------------------------------- /src/styles/movie_slider_view.sass: -------------------------------------------------------------------------------- 1 | @import './variables' 2 | 3 | .trend_slider_view 4 | display: block 5 | overflow: hidden 6 | position: relative 7 | .trend_backdrop_img 8 | border-radius: .5rem 9 | height: 150px 10 | width: 100% 11 | object-fit: cover 12 | object-position: center 13 | .work-category 14 | left: 7.5px 15 | top: 7.5px 16 | position: absolute 17 | display: flex 18 | align-items: center 19 | span 20 | color: $netflix-white 21 | text-transform: uppercase 22 | letter-spacing: 2px 23 | font-weight: 600 24 | text-shadow: 1px 1px 5px #000000b6 25 | .work-title 26 | color: $netflix-white 27 | text-shadow: 1px 1px 2px #000000 28 | left: 15px 29 | bottom: 7.5px 30 | position: absolute 31 | padding-right: 15px 32 | .work-language 33 | display: block 34 | right: 7.5px 35 | top: 7.5px 36 | position: absolute 37 | text-transform: uppercase 38 | color: $netflix-white 39 | background: $netflix-red 40 | width: 25px 41 | height: 25px 42 | text-align: center 43 | line-height: 25px 44 | font-size: 12px 45 | border-radius: .3rem 46 | -------------------------------------------------------------------------------- /src/styles/movies-page.sass: -------------------------------------------------------------------------------- 1 | @import './variables' 2 | 3 | .page-hero-slider 4 | .swiper 5 | min-height: 500px 6 | .swiper-slide 7 | min-height: 500px 8 | .MovieSerieView 9 | &:hover 10 | .overlay 11 | top: 0 12 | .work-poster 13 | height: 325px 14 | .overlay 15 | top: -325px 16 | .work-title, 17 | .work-date 18 | display: none 19 | .slide-content 20 | margin: 0 21 | .swiper-button-prev, 22 | .swiper-button-next 23 | top: 50% 24 | .page-main 25 | padding: 3rem 0 26 | padding-bottom: 0 27 | .left-sidebar 28 | .results-container 29 | .container 30 | 31 | display: flex 32 | flex-direction: column 33 | .results 34 | min-height: 690px 35 | .result-view 36 | .MovieSerieView 37 | position: relative 38 | margin-bottom: 2.5rem 39 | .work-rating 40 | .ribbon-container 41 | top: -6px 42 | 43 | @media screen and ( min-width: 1200px ) 44 | .col-xl-2_5 45 | width: 20% !important 46 | 47 | @media screen and ( max-width: 991px ) 48 | .page-hero-slider 49 | .swiper 50 | .swiper-slide 51 | min-height: 600px !important 52 | .slide-content 53 | padding-top: 2rem 54 | -------------------------------------------------------------------------------- /src/styles/navbar.sass: -------------------------------------------------------------------------------- 1 | @import './variables' 2 | 3 | nav 4 | z-index: 1000 5 | top: 0 6 | left: 0 7 | width: 100% 8 | position: absolute 9 | padding: 2rem 0 10 | .navbar-right-area, 11 | .navbar-left-area 12 | display: flex 13 | align-items: center 14 | .navbar-left-area 15 | .navbar-short-links 16 | display: flex 17 | .nav-link 18 | color: $netflix-white 19 | text-transform: capitalize 20 | padding: .75rem 1rem 21 | border-color: $netflix-red 22 | .nav-link.active 23 | border-bottom: 4px solid $netflix-red 24 | background: linear-gradient(to top,#ffffff2d,#ffffff00) !important 25 | .navbar-right-area 26 | justify-content: flex-end 27 | .login_signup-link 28 | text-transform: capitalize 29 | color: $netflix-white 30 | background: $netflix-red 31 | padding: 0.5rem 2.25rem 32 | border-radius: 1000px 33 | transition: .2s 34 | &:hover 35 | box-shadow: 1px 1px 10px $netflix-red 36 | .navbar-btn 37 | font-size: 20px 38 | position: relative 39 | color: $netflix-white 40 | .user-avatar 41 | width: 40px 42 | height: 40px 43 | display: block 44 | background: red 45 | border-radius: .35rem 46 | overflow: hidden 47 | .avatar-img 48 | width: 100% 49 | height: 100% 50 | object-fit: cover 51 | .active 52 | top: 2px 53 | right: 2px 54 | position: absolute 55 | display: block 56 | width: 10px 57 | height: 10px 58 | border-radius: 50% 59 | background: $netflix-red 60 | outline: 3px solid $_bg-color 61 | 62 | 63 | .mob-navbar 64 | padding: 2rem 0 65 | color: $_bg-color 66 | position: fixed 67 | width: 100% 68 | height: 50px 69 | bottom: 0 70 | left: 0 71 | z-index: 1002 72 | background: $netflix-white 73 | display: flex 74 | align-items: center 75 | justify-content: space-around 76 | box-shadow: 1px 1px 10px #00000021 77 | 78 | .navbar-btn 79 | font-size: 20px 80 | position: relative 81 | color: $_bg-color 82 | .user-avatar 83 | width: 40px 84 | height: 40px 85 | display: block 86 | background: red 87 | border-radius: .35rem 88 | overflow: hidden 89 | .avatar-img 90 | width: 100% 91 | height: 100% 92 | object-fit: cover 93 | 94 | 95 | 96 | @media screen and ( min-width : (991px) ) 97 | nav.nav-top-fixed 98 | position: fixed 99 | nav.invert 100 | background: $netflix-white 101 | transition: background .3s 102 | padding: 0 103 | color: $netflix-white 104 | box-shadow: 1px 1px 10px #00000021 105 | .navbar-left-area 106 | .navbar-short-links 107 | .nav-link 108 | color: $_bg-color 109 | text-transform: capitalize 110 | padding: 1.25rem 1rem 111 | .nav-link.active 112 | border-bottom: 4px solid $netflix-red 113 | .navbar-right-area 114 | .navbar-btn 115 | color: $_bg-color 116 | padding: 0 117 | .user-avatar 118 | .active 119 | background: $netflix-red 120 | outline: 3px solid $netflix-white -------------------------------------------------------------------------------- /src/styles/normalize.sass: -------------------------------------------------------------------------------- 1 | @import './variables' 2 | 3 | body 4 | background: $bg-color 5 | color: $text-white 6 | font-family: $poppins-font 7 | font-size: $font-size 8 | font-weight: $font-weight 9 | overflow-x: hidden 10 | a 11 | text-decoration: none 12 | &:hover 13 | text-decoration: none 14 | button 15 | border: 0 16 | outline: none 17 | background: transparent 18 | ul 19 | list-style: none 20 | padding: 0 21 | margin: 0 22 | 23 | ::-webkit-scrollbar 24 | width: 10px 25 | ::-webkit-scrollbar-track 26 | background: transparent 27 | ::-webkit-scrollbar-thumb 28 | background: $netflix-red 29 | ::-webkit-scrollbar-thumb:hover 30 | background: $netflix-red 31 | 32 | 33 | .margined-section 34 | margin-top: 113px 35 | 36 | @media screen and (min-width: 1200px) 37 | .container 38 | max-width: 1440px 39 | padding-right: 30px 40 | padding-left: 30px 41 | @media screen and ( max-width : (991px) ) 42 | body 43 | // margin-bottom: 64px -------------------------------------------------------------------------------- /src/styles/pagination.sass: -------------------------------------------------------------------------------- 1 | @import './variables' 2 | 3 | .pagination-container 4 | display: flex 5 | align-items: center 6 | justify-content: center 7 | margin: 2rem 0 8 | a 9 | color: $netflix-white !important 10 | border-radius: 1000px 11 | overflow: hidden 12 | display: flex 13 | align-items: center 14 | justify-content: space-between 15 | margin: 1rem 16 | background: $netflix-red 17 | transition: .2s 18 | &:hover 19 | box-shadow: 1px 1px 10px $netflix-red 20 | 21 | span 22 | padding: 0 2rem 23 | i 24 | box-shadow: 1px 1px 10px #00000073 25 | display: flex 26 | justify-content: center 27 | align-items: center 28 | padding: .5rem 1rem 29 | &:last-of-type 30 | i 31 | box-shadow: -1px -1px 10px #00000073 32 | 33 | 34 | @media screen and ( max-width: 500px ) 35 | 36 | 37 | .pagination-container 38 | a 39 | display: flex 40 | align-items: center 41 | justify-content: space-between 42 | margin: .5rem 43 | span 44 | padding: 0 1.3rem !important 45 | font-size: 10px 46 | -------------------------------------------------------------------------------- /src/styles/person-page.sass: -------------------------------------------------------------------------------- 1 | @import './variables' 2 | 3 | .person-page 4 | padding-top: 150px 5 | padding-bottom: 65px 6 | background: linear-gradient(#000,#000000aa) ,url('../assets/images/work-bg.jpg') 7 | .left-sidebar 8 | .person-profile 9 | border-radius: .5rem 10 | overflow: hidden 11 | img 12 | width: 100% 13 | height: 100% 14 | object-fit: cover 15 | .person-socials 16 | display: flex 17 | a 18 | color: $netflix-white 19 | font-size: 30px 20 | margin-right: 2rem 21 | .person-fact 22 | margin: 1rem 0 23 | label 24 | display: block 25 | margin-bottom: 0.25rem 26 | text-transform: capitalize 27 | font-weight: 600 28 | font-size: 15px 29 | p 30 | margin: 0 31 | .person-works 32 | .person-facts-container 33 | .person-fact 34 | margin-top:1.5rem 35 | margin-right: 1rem 36 | width: auto 37 | label 38 | word-break: keep-all 39 | text-wrap: nowrap 40 | display: block 41 | p 42 | display: block !important 43 | .person-name 44 | text-transform: uppercase 45 | .person-biography 46 | margin-top: 0.4rem 47 | font-size: 13px 48 | .works-container 49 | display: flex 50 | overflow-x: scroll 51 | .MovieSerieView 52 | position: relative 53 | margin-bottom: 1rem 54 | .poster-img-container 55 | width: 150px 56 | .work-info, 57 | .ribbon-container 58 | display: none 59 | 60 | @media screen and ( min-width: 991px ) 61 | .person-facts-container 62 | display: flex 63 | justify-content: space-between -------------------------------------------------------------------------------- /src/styles/review-item.sass: -------------------------------------------------------------------------------- 1 | @import './variables' 2 | 3 | .tv-show-reviews-container 4 | max-height: 530px 5 | overflow-y: scroll 6 | .reviews-container 7 | max-height: 580px 8 | overflow-y: scroll 9 | .review-item 10 | border: 1px solid #ffffff44 11 | border-radius: .5rem 12 | &:first-of-type 13 | margin-top: 0 !important 14 | .author-avatar 15 | border: 2px solid #fff 16 | width: 45px 17 | height: 45px 18 | border-radius: 50% 19 | overflow: hidden 20 | img 21 | width: 100% 22 | height: 100% 23 | object-fit: cover 24 | .rate 25 | background: $netflix-white 26 | display: inline-block 27 | color: $_bg-color 28 | padding: .2rem 1rem 29 | border-radius: .5rem 30 | .review-date 31 | color: var(--bs-gray-600) 32 | font-size: 12px 33 | .review-content 34 | line-height: 1.25rem 35 | max-height: 10rem 36 | overflow: hidden 37 | -webkit-line-clamp: 5 38 | display: box 39 | display: -webkit-box 40 | -webkit-box-orient: vertical 41 | text-overflow: ellipsis 42 | white-space: normal 43 | .review-invert 44 | border: 1px solid #aaa 45 | .author-avatar 46 | border: 2px solid #aaa 47 | .rate 48 | background: $_bg-color 49 | color: $netflix-white 50 | -------------------------------------------------------------------------------- /src/styles/score.sass: -------------------------------------------------------------------------------- 1 | @import './variables' 2 | 3 | .work-rating 4 | z-index: 4 5 | position: absolute 6 | top: 5px 7 | right: 5px 8 | width: 45px 9 | height: 45px 10 | border-radius: 50% 11 | padding: .25rem 12 | background: $bg-color 13 | .circle 14 | stroke-width: 2 15 | stroke-linecap: round 16 | animation: progress 1s ease-out forwards 17 | @keyframes progress 18 | 0% 19 | stroke-dasharray: 0 100 20 | .circular-chart .circle 21 | fill: $_bg-color 22 | .percentage 23 | text-align: center 24 | fill: $netflix-white 25 | font-size: .65rem 26 | -------------------------------------------------------------------------------- /src/styles/search-area.sass: -------------------------------------------------------------------------------- 1 | @import './variables' 2 | 3 | .search-area 4 | padding-top: 113px 5 | .search-form 6 | form 7 | display: flex 8 | input 9 | width: 100% 10 | outline: none 11 | border: 0 12 | input[type='text'] 13 | padding: 0 30px 14 | a 15 | background: $netflix-red 16 | color: $netflix-white 17 | font-size: 22px 18 | padding: .5rem 3rem 19 | .cat-body 20 | padding: 0 21 | .search-filter-list 22 | li 23 | display: flex 24 | justify-content: space-between 25 | align-items: center 26 | padding: 0.5rem 0 27 | margin: 1rem 0 28 | padding-right: 24px 29 | padding-left: 24px 30 | button 31 | color: $_bg-color 32 | text-transform: capitalize 33 | span 34 | letter-spacing: 1px 35 | background: var(--bs-gray-300) 36 | color: var(--bs-gray-700) 37 | padding: 0.25rem .75rem 38 | border-radius: .6rem 39 | li 40 | &:hover 41 | background: var(--bs-gray-300) 42 | span 43 | background: $netflix-white 44 | li.current 45 | background: var(--bs-gray-300) 46 | span 47 | background: $netflix-white 48 | button 49 | font-weight: 600 50 | 51 | .search-results-container 52 | .container 53 | display: flex 54 | flex-direction: column 55 | .results 56 | min-height: 1000px 57 | .result-view 58 | position: relative 59 | .ribbon-container 60 | left: 7px 61 | .work-rating 62 | right: 15px -------------------------------------------------------------------------------- /src/styles/slider-bg-white.sass: -------------------------------------------------------------------------------- 1 | @import './variables' 2 | 3 | .slider-bg-white 4 | background: $netflix-white 5 | color: $bg-color 6 | .work-info 7 | .work-title 8 | color: $bg-color !important 9 | font-weight: 600 !important 10 | .work-date 11 | color: #474747 !important 12 | .slider-actions 13 | .actions-btns-group 14 | border: 2px solid $bg-color 15 | background: $bg-color 16 | button 17 | color: $netflix-white 18 | background: transparent 19 | .background -------------------------------------------------------------------------------- /src/styles/variables.sass: -------------------------------------------------------------------------------- 1 | // FONTS 2 | $poppins-font: 'poppins' 3 | $cairo-font: 'cairo' 4 | $font-size: 14px 5 | $font-weight: 400 6 | 7 | // COLORS 8 | $bg-color: #151515 9 | $_bg-color: #101010 10 | $netflix-red: #FF2530 11 | $netflix-white: #FFF 12 | // $netflix-white: #F2F2F2 13 | $text-white: #F2F2F2 -------------------------------------------------------------------------------- /src/styles/works-filter.sass: -------------------------------------------------------------------------------- 1 | @import './variables' 2 | .col-9.results-container .container 3 | min-height: 850px 4 | position: relative 5 | display: flex 6 | flex-direction: column 7 | .works-filter 8 | label 9 | text-transform: capitalize 10 | font-size: 20px 11 | padding-bottom: 2rem 12 | .accordion 13 | .accordion-item 14 | color: $_bg-color 15 | border-color: $netflix-white 16 | background: $netflix-white 17 | margin: 1rem 0 18 | margin-bottom: 2rem 19 | .accordion-body 20 | .dropdown 21 | button 22 | width: 100% 23 | text-align: left 24 | font-size: 14px 25 | background: $netflix-white 26 | color: $_bg-color 27 | padding: 8px 16px 28 | border: 0 29 | box-shadow: none 30 | border: 1px solid #00000075 31 | display: flex 32 | justify-content: space-between 33 | align-items: center 34 | &::after 35 | display: none 36 | .dropdown-menu 37 | z-index: 999 38 | .dropdown-item 39 | font-size: 14px 40 | border: 0 41 | background: transparent 42 | .accordion-button 43 | cursor: initial 44 | background: $netflix-red 45 | box-shadow: none 46 | color: $netflix-white 47 | &::after 48 | display: none 49 | &::before 50 | display: none 51 | .genres 52 | .genre-btn 53 | border: 1px solid #00000075 54 | border-radius: 100px 55 | padding: 0.2rem 1rem 56 | margin: .25rem 0 57 | margin-right: 0.5rem 58 | font-size: 13px 59 | 60 | .active 61 | border: 1px solid $netflix-red 62 | background: $netflix-red 63 | color: $netflix-white 64 | -------------------------------------------------------------------------------- /src/styles/works_classification_btns.sass: -------------------------------------------------------------------------------- 1 | @import './variables' 2 | .class-btns-group 3 | display: flex 4 | flex-direction: row 5 | align-items: center 6 | justify-content: flex-start 7 | margin-bottom: 2rem 8 | overflow: scroll 9 | a 10 | color: $_bg-color 11 | font-weight: 500 12 | text-transform: capitalize 13 | border: 2px solid $netflix-white 14 | border-radius: 1000px 15 | padding: 0.3rem 1.25rem 16 | margin-right: 1rem 17 | transition: all .2s 18 | white-space: nowrap 19 | background: $netflix-white 20 | &:hover 21 | color: $netflix-white 22 | background: $netflix-red 23 | border: 2px solid $netflix-red 24 | .current 25 | color: $netflix-white 26 | background: $netflix-red 27 | border: 2px solid $netflix-red 28 | 29 | 30 | @media screen and ( max-width: 991px ) 31 | .class-btns-group 32 | padding-bottom: 2rem 33 | -------------------------------------------------------------------------------- /src/styles/works_slider.sass: -------------------------------------------------------------------------------- 1 | @import './variables' 2 | 3 | .slider-actions 4 | justify-content: space-between 5 | .slider-title 6 | font-size: 20px 7 | .actions-btns-group 8 | margin-top: 1.5rem 9 | border: 2px solid $netflix-white 10 | border-radius: 1000px 11 | display: inline-flex 12 | position: relative 13 | background: $netflix-white 14 | button 15 | color: $_bg-color 16 | border-radius: 1000px 17 | padding: 0.4rem 1.6rem 18 | text-transform: capitalize 19 | .background 20 | background: $netflix-red 21 | height: 100% 22 | width: 99.5px 23 | display: block 24 | position: absolute 25 | left: 0 26 | top: 0 27 | border-radius: 1000px 28 | color: $netflix-white 29 | transition: all .5s 30 | display: flex 31 | justify-content: center 32 | align-items: center 33 | text-transform: capitalize 34 | cursor: pointer 35 | .works-slider-container 36 | padding: 3rem 0 37 | .swiper-scrollbar 38 | width: 100% 39 | position: initial 40 | margin: 0 41 | margin-bottom: 2rem 42 | left: 0 43 | bottom: 0 44 | .swiper-scrollbar-drag 45 | background: $netflix-red 46 | cursor: pointer 47 | .slider-navigation 48 | display: flex 49 | .swiper-button-prev-unique, 50 | .swiper-button-next-unique 51 | border-radius: 20% 52 | display: flex 53 | justify-content: center 54 | align-items: center 55 | transition: .2s 56 | width: 30px 57 | height: 30px 58 | background: $netflix-red 59 | color: $netflix-white 60 | cursor: pointer 61 | &::after 62 | all: unset 63 | background: $netflix-red 64 | // font-size: 20px 65 | font-family: 'Font Awesome 5 Pro' 66 | content: "\f053" 67 | &:hover 68 | box-shadow: 1px 1px 10px $netflix-red 69 | .swiper-button-next-unique 70 | &::after 71 | content: "\f054" --------------------------------------------------------------------------------