├── .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 | You need to enable JavaScript to run this app.
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 |
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 |
21 |
24 |
27 |
30 |
33 |
36 |
39 |
42 |
45 |
48 |
51 |
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 |
39 |
40 |
41 |
42 |
43 |
44 |
50 |
SERIES
51 |
52 |
53 |
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 |
99 |
100 |
101 |
102 |
103 |
104 |
110 |
SERIES
111 |
112 |
113 |
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 |
153 |
154 |
155 |
156 |
157 |
158 |
164 |
MOVIES
165 |
166 |
167 |
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 |
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 |
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 |
15 |
16 |
17 |
18 |
19 |
20 |
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 |
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 |
17 |
18 |
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 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
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 |
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 |
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 |
79 |
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 |
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 |
143 |
144 |
145 | ) : (
146 | <>
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 | >
157 | )}
158 |
159 |
160 |
161 |
162 |
163 |
164 |
170 |
171 |
172 |
173 |
174 | home
175 |
176 |
177 |
178 |
179 | movies
180 |
181 |
182 |
183 |
184 | series
185 |
186 |
187 |
188 |
189 | people
190 |
191 |
192 |
193 |
194 | favourites
195 |
196 |
197 |
198 |
199 |
200 |
201 |
206 |
207 |
208 | {!isUserLoggedIn ? (
209 |
213 | login
214 |
215 | ) : (
216 | <>
217 |
218 |
224 |
225 |
230 |
231 |
232 | >
233 | )}
234 |
235 |
236 | {
239 | menu.current.classList.add("show");
240 | }}
241 | >
242 |
243 |
244 |
245 |
246 |
247 |
248 |
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 |
21 |
22 |
23 |
24 |
25 |
26 |
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 |
80 | );
81 | })}
82 |
83 |
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 |
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 | Also Known As
105 | {person.also_known_as.map((el) => {
106 | return {`${el} , `} ;
107 | })}
108 |
109 | ) : null}
110 |
111 |
112 |
113 |
114 |
{person.name}
115 |
116 |
Biography
117 |
118 | {person.biography || "N/A"}
119 |
120 |
121 |
122 |
123 |
Known For
124 |
{person.known_for_department || "N/A"}
125 |
126 |
127 |
Known Credits
128 |
{person.combined_credits.cast.length}
129 |
130 |
131 |
Gender
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 |
Birthday
147 |
{person.birthday || "N/A"}
148 |
149 | {person.deathday ? (
150 |
151 |
Day of Death
152 |
{person.deathday || "N/A"}
153 |
154 | ) : null}
155 |
156 |
Place of Birth
157 |
{person.place_of_birth || "N/A"}
158 |
159 |
160 |
161 |
Known For
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 |
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 |
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 |
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 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
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 |
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 |
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 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
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 |
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 | {
31 | // filterByMediaType(filteredList, "movie");
32 | // }}
33 | >
34 | movies
35 |
36 |
37 | {
38 | list.filter((el) => {
39 | return el.media_type === "movie";
40 | }).length
41 | }
42 |
43 |
44 |
45 | series
46 |
47 | {
48 | list.filter((el) => {
49 | return el.media_type === "tv";
50 | }).length
51 | }
52 |
53 |
54 |
55 | people
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 |
82 |
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 |
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 ?
{label} : null}
93 |
94 |
95 |
96 |
Sort
97 |
98 |
Sort Results By
99 |
100 |
110 |
114 |
115 | {
118 | setcurrentSort("None");
119 | initFilteredList(list);
120 | }}
121 | >
122 | None
123 |
124 |
125 |
126 | {
129 | setcurrentSort("Rating Descending");
130 | sortRateDescending(filteredList);
131 | }}
132 | >
133 | Rating Descending
134 |
135 |
136 |
137 | {
140 | setcurrentSort("Rating Ascending");
141 | sortRateAscending(filteredList);
142 | }}
143 | >
144 | Rating Ascending
145 |
146 |
147 |
148 | {
151 | setcurrentSort("Release Date Descending");
152 | sortDateDescending(filteredList);
153 | }}
154 | >
155 | Release Date Descending
156 |
157 |
158 |
159 | {
162 | setcurrentSort("Release Date Ascending");
163 | sortDateAscending(filteredList);
164 | }}
165 | >
166 | Release Date Ascending
167 |
168 |
169 |
170 | {
173 | setcurrentSort("Title (A-Z)");
174 | sortTitleA_Z(filteredList);
175 | }}
176 | >
177 | Title (A-Z)
178 |
179 |
180 |
181 | {
184 | setcurrentSort("Title (Z-A)");
185 | sortTitleZ_A(filteredList);
186 | }}
187 | >
188 | Title (Z-A)
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
Filters
201 |
202 |
203 |
Language
204 |
205 |
215 |
219 |
220 | {
223 | setcurrentFilter("All");
224 | initFilteredList(list);
225 | }}
226 | >
227 | All
228 |
229 |
230 | {[...renderLanguages()].map((el) => {
231 | return (
232 |
233 | {
236 | setcurrentFilter(el.language);
237 | filterByLanguage(list, el.language);
238 | }}
239 | >
240 | {el.language || "N/A"}
241 | ({el.count})
242 |
243 |
244 | );
245 | })}
246 |
247 |
248 |
249 |
250 |
Genres
251 |
252 | {genresList.map((el) => {
253 | return (
254 | {
260 | genres.includes(el.id)
261 | ? setgenres(
262 | genres?.filter((genre) => {
263 | return genre !== el.id;
264 | })
265 | )
266 | : setgenres([...genres, el.id]);
267 | }}
268 | >
269 | {el.name}
270 |
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 | {
56 | props.btnsFunctions[index]();
57 | moveBtnBackground(e);
58 | }}
59 | >
60 | {el}
61 |
62 | );
63 | });
64 | };
65 | return (
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | {props.title}
74 |
75 |
76 |
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"
--------------------------------------------------------------------------------