├── src ├── readme.md ├── App.css ├── images │ ├── GithubLogo.png │ ├── GoogleLogo.png │ ├── EndgamePoster.jpg │ ├── WelcomePageBanner.jpg │ ├── WelcomePageImage1.png │ ├── WelcomePageImage2.png │ ├── WelcomePageImage3.png │ └── WelcomePageImage4.png ├── axios.js ├── Pages │ ├── MyList.jsx │ ├── History.jsx │ ├── LikedMovies.jsx │ ├── Series.jsx │ ├── ErrorPage.jsx │ ├── Home.jsx │ ├── Welcome.jsx │ ├── SignUp.jsx │ ├── Search.jsx │ ├── SignIn.jsx │ ├── Profile.jsx │ └── Play.jsx ├── componets │ ├── Loading │ │ └── Loading.jsx │ ├── Footer │ │ ├── Footer.jsx │ │ └── styles.module.scss │ ├── Header │ │ ├── NavbarWithoutUser.jsx │ │ └── Navbar.jsx │ ├── RowPost │ │ ├── RowPostStyles.scss │ │ └── RowPost.jsx │ ├── Banner │ │ └── Banner.jsx │ ├── UserMovieSection │ │ └── UserMovieSection.jsx │ └── PopUp │ │ └── MoviePopUp.jsx ├── Context │ ├── UserContext.jsx │ └── moviePopUpContext.jsx ├── index.css ├── CustomHooks │ ├── usePlayMovie.jsx │ ├── useGenereConverter.jsx │ ├── useUpdateWatchedMovies.jsx │ ├── useUpdateLikedMovies.jsx │ └── useUpdateMylist.jsx ├── index.jsx ├── Firebase │ └── FirebaseConfig.js ├── Constants │ ├── URLs.js │ └── Constance.js └── App.jsx ├── vercel.json ├── postcss.config.cjs ├── vite.config.js ├── .gitignore ├── .vscode └── extensions.json ├── LICENSE ├── package.json ├── index.html ├── public └── vite.svg ├── tailwind.config.cjs └── README.md /src/readme.md: -------------------------------------------------------------------------------- 1 | # Netflix UI clone with React.js 2 | ## _This is the directory_ 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "rewrites": [ 3 | {"source": "/(.*)", "destination": "/"} 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: #111; 3 | scroll-behavior: smooth; 4 | overflow-x: hidden; 5 | } 6 | -------------------------------------------------------------------------------- /src/images/GithubLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JosinJojy/Netflix-reactjs/HEAD/src/images/GithubLogo.png -------------------------------------------------------------------------------- /src/images/GoogleLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JosinJojy/Netflix-reactjs/HEAD/src/images/GoogleLogo.png -------------------------------------------------------------------------------- /src/images/EndgamePoster.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JosinJojy/Netflix-reactjs/HEAD/src/images/EndgamePoster.jpg -------------------------------------------------------------------------------- /postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /src/images/WelcomePageBanner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JosinJojy/Netflix-reactjs/HEAD/src/images/WelcomePageBanner.jpg -------------------------------------------------------------------------------- /src/images/WelcomePageImage1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JosinJojy/Netflix-reactjs/HEAD/src/images/WelcomePageImage1.png -------------------------------------------------------------------------------- /src/images/WelcomePageImage2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JosinJojy/Netflix-reactjs/HEAD/src/images/WelcomePageImage2.png -------------------------------------------------------------------------------- /src/images/WelcomePageImage3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JosinJojy/Netflix-reactjs/HEAD/src/images/WelcomePageImage3.png -------------------------------------------------------------------------------- /src/images/WelcomePageImage4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JosinJojy/Netflix-reactjs/HEAD/src/images/WelcomePageImage4.png -------------------------------------------------------------------------------- /src/axios.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { baseUrl } from "./Constants/Constance"; 3 | 4 | const instance = axios.create({ 5 | baseURL: baseUrl, 6 | }); 7 | export default instance; 8 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()] 7 | }) 8 | -------------------------------------------------------------------------------- /src/Pages/MyList.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import UserMovieSection from "../componets/UserMovieSection/UserMovieSection"; 3 | 4 | function MyList() { 5 | return ; 6 | } 7 | 8 | export default MyList; 9 | -------------------------------------------------------------------------------- /src/Pages/History.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import UserMovieSection from "../componets/UserMovieSection/UserMovieSection"; 3 | 4 | function History() { 5 | return ; 6 | } 7 | 8 | export default History; 9 | -------------------------------------------------------------------------------- /src/Pages/LikedMovies.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import UserMovieSection from "../componets/UserMovieSection/UserMovieSection"; 3 | 4 | function LikedMovies() { 5 | return ; 6 | } 7 | 8 | export default LikedMovies; 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /src/componets/Loading/Loading.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { ClipLoader } from "react-spinners"; 3 | 4 | function Loading() { 5 | return ( 6 |
7 |
8 | 9 |
10 |
11 | ); 12 | } 13 | 14 | export default Loading; 15 | -------------------------------------------------------------------------------- /src/Context/UserContext.jsx: -------------------------------------------------------------------------------- 1 | import { createContext, useState } from "react"; 2 | 3 | export const AuthContext = createContext(null); 4 | 5 | export default function Context({ children }) { 6 | const [User, setUser] = useState(null); 7 | 8 | return ( 9 | 10 | {children} 11 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | body { 6 | margin: 0; 7 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 8 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 9 | sans-serif; 10 | -webkit-font-smoothing: antialiased; 11 | -moz-osx-font-smoothing: grayscale; 12 | } 13 | -------------------------------------------------------------------------------- /src/Context/moviePopUpContext.jsx: -------------------------------------------------------------------------------- 1 | import { createContext, useState } from "react"; 2 | 3 | export const PopUpContext = createContext(null); 4 | 5 | export default function Context2({ children }) { 6 | const [showModal, setShowModal] = useState(false); 7 | 8 | return ( 9 | 10 | {children} 11 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. 3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp 4 | 5 | // List of extensions which should be recommended for users of this workspace. 6 | "recommendations": [ 7 | 8 | ], 9 | // List of extensions recommended by VS Code that should not be recommended for users of this workspace. 10 | "unwantedRecommendations": [ 11 | 12 | ] 13 | } -------------------------------------------------------------------------------- /src/CustomHooks/usePlayMovie.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useNavigate } from "react-router-dom"; 3 | import useUpdateWatchedMovies from "./useUpdateWatchedMovies"; 4 | 5 | function usePlayMovie() { 6 | const { addToWatchedMovies } = useUpdateWatchedMovies(); 7 | const navigate = useNavigate(); 8 | 9 | const playMovie = (movie, from) => { 10 | addToWatchedMovies(movie); 11 | navigate(`/play/${movie.id}`, { replace: true, state: { From: from } }); 12 | }; 13 | 14 | return { playMovie }; 15 | } 16 | 17 | export default usePlayMovie; 18 | -------------------------------------------------------------------------------- /src/CustomHooks/useGenereConverter.jsx: -------------------------------------------------------------------------------- 1 | import { genresList } from "../Constants/Constance"; 2 | 3 | const useGenereConverter = () => { 4 | const convertGenere = (genreIds) => { 5 | const genresConvertedList = []; 6 | genreIds 7 | .slice(0, 3) 8 | .map((genreId) => 9 | genresList 10 | .filter((el) => el.id === genreId) 11 | .map((el) => genresConvertedList.push(el.name)) 12 | ); 13 | 14 | return genresConvertedList; 15 | }; 16 | 17 | return { convertGenere }; 18 | }; 19 | 20 | export default useGenereConverter; 21 | -------------------------------------------------------------------------------- /src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App"; 4 | import "./index.css"; 5 | 6 | import { BrowserRouter as Router } from "react-router-dom"; 7 | import { FirebaseApp } from "./Firebase/FirebaseConfig"; 8 | import Context from "./Context/UserContext"; 9 | import Context2 from "./Context/moviePopUpContext"; 10 | 11 | ReactDOM.createRoot(document.getElementById("root")).render( 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ); 22 | -------------------------------------------------------------------------------- /src/Firebase/FirebaseConfig.js: -------------------------------------------------------------------------------- 1 | import { initializeApp } from "firebase/app"; 2 | import { getAnalytics } from "firebase/analytics"; 3 | import { getFirestore } from "firebase/firestore"; 4 | 5 | const firebaseConfig = { 6 | apiKey: "AIzaSyBIhBiO3flFpAcL2Fm_Ef22QQo6udFp5b4", 7 | authDomain: "react-netflix-eb4f0.firebaseapp.com", 8 | projectId: "react-netflix-eb4f0", 9 | storageBucket: "react-netflix-eb4f0.appspot.com", 10 | messagingSenderId: "29045190704", 11 | appId: "1:29045190704:web:a7c74bd778aa5f993c7df5", 12 | measurementId: "G-9TB7LL3YPM", 13 | }; 14 | 15 | // Initialize Firebase 16 | export const FirebaseApp = initializeApp(firebaseConfig); 17 | export const db = getFirestore(FirebaseApp); 18 | const analytics = getAnalytics(FirebaseApp); 19 | -------------------------------------------------------------------------------- /src/Constants/URLs.js: -------------------------------------------------------------------------------- 1 | import { API_KEY } from "../Constants/Constance"; 2 | export const TopRated = `/movie/top_rated?api_key=${API_KEY}&language=en-US`; 3 | export const originals = `discover/tv?api_key=${API_KEY}&with_networks=213&sort_by=popularity.desc&language=en-US`; 4 | export const action = `discover/movie?api_key=${API_KEY}&with_genres=28`; 5 | export const comedy = `discover/movie?api_key=${API_KEY}&with_genres=35`; 6 | export const horror = `discover/movie?api_key=${API_KEY}&with_genres=27`; 7 | export const Adventure = `discover/movie?api_key=${API_KEY}&with_genres=12`; 8 | export const SciFi = `discover/movie?api_key=${API_KEY}&with_genres=878`; 9 | export const Animated = `discover/movie?api_key=${API_KEY}&with_genres=16`; 10 | export const War = `discover/movie?api_key=${API_KEY}&with_genres=10752`; 11 | export const trending = `trending/all/week?api_key=${API_KEY}&sort_by=popularity.desc&language=en-US`; 12 | export const trendingSeries = `/trending/tv/week?api_key=${API_KEY}&sort_by=popularity.desc&language=en-US`; 13 | export const UpcomingMovies = `/movie/upcoming?api_key=${API_KEY}&language=en-US`; 14 | -------------------------------------------------------------------------------- /src/componets/Footer/Footer.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import styles from "./styles.module.scss"; 3 | 4 | function Footer2() { 5 | return ( 6 |
7 | 31 |
32 | ); 33 | } 34 | 35 | export default Footer2; 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Josin Jojy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "netflix-reactjs", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "@headlessui/react": "^1.7.4", 13 | "@tailwindcss/line-clamp": "^0.4.2", 14 | "@tanstack/react-query": "^4.28.0", 15 | "@tanstack/react-query-devtools": "^4.29.0", 16 | "axios": "^1.2.1", 17 | "firebase": "^9.14.0", 18 | "react": "^18.2.0", 19 | "react-dom": "^18.2.0", 20 | "react-hot-toast": "^2.4.0", 21 | "react-reveal": "^1.2.2", 22 | "react-router-dom": "^6.4.4", 23 | "react-spinners": "^0.13.7", 24 | "react-star-ratings": "^2.3.0", 25 | "react-youtube": "^10.1.0", 26 | "swiper": "^8.4.5" 27 | }, 28 | "devDependencies": { 29 | "@types/react": "^18.0.24", 30 | "@types/react-dom": "^18.0.8", 31 | "@vitejs/plugin-react": "^2.2.0", 32 | "autoprefixer": "^10.4.13", 33 | "postcss": "^8.4.19", 34 | "react-hot-loader": "^4.13.1", 35 | "sass": "^1.56.1", 36 | "tailwindcss": "^3.2.4", 37 | "tailwindcss-textshadow": "^2.1.3", 38 | "vite": "^3.2.3" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Netflix Clone React.js 9 | 10 | 11 | 12 | 13 | 14 | 20 | 25 | 26 | 27 |
28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Pages/Series.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Banner from "../componets/Banner/Banner"; 3 | import Footer from "../componets/Footer/Footer"; 4 | import RowPost from "../componets/RowPost/RowPost"; 5 | import { 6 | originals, 7 | comedy, 8 | horror, 9 | Adventure, 10 | SciFi, 11 | Animated, 12 | War, 13 | trendingSeries, 14 | UpcomingMovies, 15 | } from "../Constants/URLs"; 16 | 17 | function Series() { 18 | return ( 19 |
20 | 21 |
22 | 28 | 29 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
42 | 43 |
44 | ); 45 | } 46 | 47 | export default Series; 48 | -------------------------------------------------------------------------------- /src/componets/Header/NavbarWithoutUser.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import { Link } from "react-router-dom"; 3 | 4 | function NavbarWithoutUser() { 5 | const [show, handleShow] = useState(false); 6 | const transitionNavBar = () => { 7 | if (window.scrollY > 100) { 8 | handleShow(true); 9 | } else { 10 | handleShow(false); 11 | } 12 | }; 13 | 14 | useEffect(() => { 15 | window.addEventListener("scroll", transitionNavBar); 16 | return () => { 17 | window.removeEventListener("scroll", transitionNavBar); 18 | }; 19 | }, []); 20 | 21 | return ( 22 |
23 |
28 |
29 | NETFLIX 34 |
35 | 36 |
37 | 38 | 41 | 42 |
43 |
44 |
45 | ); 46 | } 47 | 48 | export default NavbarWithoutUser; 49 | -------------------------------------------------------------------------------- /tailwind.config.cjs: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | "./index.html", 5 | "./src/**/*.{js,ts,jsx,tsx}", 6 | ], 7 | theme: { 8 | screens:{ 9 | 'sm': '640px', 10 | 'md': '768px', 11 | 'lg': '1024px', 12 | 'xl': '1280px', 13 | '2xl': '1536px', 14 | '3xl': '2200px', 15 | }, 16 | extend: { 17 | padding:{ 18 | '85vh': '85vh', 19 | '50vh': '50vh', 20 | }, 21 | spacing:{ 22 | '40rem': "40rem", 23 | '45rem': "45rem", 24 | '55rem': "55rem", 25 | '63rem': "63rem", 26 | '70rem': "70rem", 27 | 28 | }, 29 | width:{ 30 | '96%' :"96%", 31 | }, 32 | background:{ 33 | 'avengers': "linear-gradient(to right bottom, rgba('#7ed56f',0.8), rgba('#28b485',0.8)),url()", 34 | 'fadeBottom': "linear-gradient(180deg,hsl(0deg 0% 0% / 0%),#000000a2,hsl(0deg 0% 7%));", 35 | 'fadeBlack': "background: linear-gradient(1turn,hsl(0deg 0% 0% / 60%),hsl(0deg 0% 0% / 0%) 65%);", 36 | 'fadeRed' : "linear-gradient(90deg, hsl(0deg 77% 42% / 44%) 0%, hsl(0deg 59% 46% / 51%) 35%, hsl(220deg 26% 44% / 0%) 100%) " 37 | }, 38 | color:{ 39 | 'black': "#010511", 40 | 'transparenWhite': "#33333380", 41 | 'transparentBlack': "#000000bf" 42 | }, 43 | margin:{ 44 | '-6%': "-6%", 45 | '50%': "50%", 46 | } 47 | }, 48 | }, 49 | plugins: [ 50 | require('@tailwindcss/line-clamp'), 51 | require('tailwindcss-textshadow'), 52 | ], 53 | } 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Netflix Clone React.js 2 | 3 | ## Overview 4 | This project is a Netflix clone built using React.js, designed to enhance skills in web development. It features a fully interactive user interface with various functionalities, making it a comprehensive movie-watching experience. The project is powered by TMDB API, utilizing Firebase for database management. 5 | 6 | ## Screenshots 7 | 8 | ![PC screen](https://i.imgur.com/FLNs9Qy.jpg) 9 | 10 | 11 | 12 | ### mobile experience 13 | ![mobile screens](https://i.imgur.com/ForTeQi.jpg) 14 | 15 | ## Key Functionalities 16 | - Sign In / Sign Up 17 | - Home Page for browsing movies 18 | - My List Section for user-specific movie selections 19 | - Liked Movies Page 20 | - Watched Movies Page 21 | - Profile Page 22 | - Play Movie Page 23 | - Search Movie Page 24 | 25 | ## Technologies Used 26 | - [React.js](https://react.dev/) 27 | - [TMDB API](https://www.themoviedb.org/) 28 | - [Firebase](https://firebase.google.com/) 29 | - [Axios](https://www.npmjs.com/package/axios) 30 | - [Swiper.js](https://swiperjs.com/) 31 | - [React-Youtube](https://www.npmjs.com/package/react-youtube) 32 | - [Tailwind CSS](https://tailwindcss.com/) 33 | 34 | ## Description 35 | This Netflix clone project was developed to deepen understanding and proficiency in React.js. Leveraging popular technologies and APIs like TMDB and Firebase, it encompasses a range of features, from user authentication to dynamic movie listings. The design is tailored to provide an immersive streaming experience, and the codebase reflects best practices in modern web development. 36 | 37 | ## Link to the Site 38 | [Netflix Clone](https://movieflix-reactjs.vercel.app/) 39 | -------------------------------------------------------------------------------- /src/CustomHooks/useUpdateWatchedMovies.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext, useState } from "react"; 2 | import { updateDoc, doc, arrayUnion, arrayRemove } from "firebase/firestore"; 3 | import { db } from "../Firebase/FirebaseConfig"; 4 | import { AuthContext } from "../Context/UserContext"; 5 | import toast, { Toaster } from "react-hot-toast"; 6 | 7 | function useUpdateWatchedMovies() { 8 | const { User } = useContext(AuthContext); 9 | const [Error, setError] = useState(false); 10 | 11 | function notify() { 12 | toast.success(" Movie removed from Watched List "); 13 | } 14 | function alertError(message) { 15 | toast.error(message); 16 | } 17 | const addToWatchedMovies = (movie) => { 18 | updateDoc(doc(db, "WatchedMovies", User.uid), { 19 | movies: arrayUnion(movie), 20 | }); 21 | }; 22 | 23 | const removeFromWatchedMovies = (movie) => { 24 | updateDoc(doc(db, "WatchedMovies", User.uid), { 25 | movies: arrayRemove(movie), 26 | }) 27 | .then(() => { 28 | notify(); 29 | }) 30 | .catch((error) => { 31 | console.log(error.code); 32 | console.log(error.message); 33 | alertError(error.message); 34 | setError(true); 35 | }); 36 | }; 37 | 38 | const removePopupMessage = ( 39 | 48 | ); 49 | 50 | return { addToWatchedMovies, removeFromWatchedMovies, removePopupMessage }; 51 | } 52 | 53 | export default useUpdateWatchedMovies; 54 | -------------------------------------------------------------------------------- /src/Pages/ErrorPage.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useNavigate } from "react-router-dom"; 3 | 4 | function ErrorPage() { 5 | const navigate = useNavigate(); 6 | return ( 7 |
8 |
9 |

10 | 404 error 11 |

12 |

13 | Page not found 14 |

15 | 37 |
38 |
39 | ); 40 | } 41 | 42 | export default ErrorPage; 43 | -------------------------------------------------------------------------------- /src/componets/Footer/styles.module.scss: -------------------------------------------------------------------------------- 1 | .footer { 2 | max-width: 980px; 3 | margin: 25px auto; 4 | padding: 0 30px; 5 | color: #808080; 6 | font-size: 1rem; 7 | } 8 | 9 | .containerFooter { 10 | display: flex; 11 | flex-direction: column; 12 | align-items: flex-start; 13 | 14 | .icons { 15 | display: flex; 16 | margin-bottom: 10px; 17 | 18 | svg { 19 | height: 30px; 20 | width: 41px; 21 | margin-right: 8px; 22 | cursor: pointer; 23 | } 24 | 25 | :first-child { 26 | margin-left: -9px; 27 | } 28 | } 29 | 30 | .details { 31 | display: flex; 32 | align-items: flex-start; 33 | flex-wrap: wrap; 34 | 35 | li { 36 | list-style: none; 37 | margin-bottom: 16px; 38 | flex-basis: 25%; 39 | text-align: left; 40 | cursor: pointer; 41 | 42 | &:hover { 43 | text-decoration: underline; 44 | } 45 | } 46 | } 47 | 48 | .security { 49 | display: flex; 50 | flex-direction: column; 51 | 52 | div { 53 | border: 1px solid #808080; 54 | padding: 7px 10px; 55 | cursor: pointer; 56 | margin-bottom: 15px; 57 | transition: all 0.2s ease; 58 | 59 | &:hover { 60 | color: white; 61 | } 62 | } 63 | } 64 | } 65 | 66 | @media (max-width: 710px) { 67 | .footer { 68 | font-size: 12px; 69 | } 70 | 71 | .containerFooter .details li { 72 | flex-basis: 33%; 73 | } 74 | 75 | .containerFooter .security { 76 | flex-direction: row; 77 | align-items: center; 78 | 79 | div { 80 | margin-bottom: 0; 81 | } 82 | 83 | span { 84 | margin-left: 15px; 85 | } 86 | } 87 | } 88 | 89 | @media (max-width: 600px) { 90 | .containerFooter .details li { 91 | flex-basis: 50%; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/CustomHooks/useUpdateLikedMovies.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext, useState } from "react"; 2 | import { updateDoc, doc, arrayUnion, arrayRemove } from "firebase/firestore"; 3 | import { db } from "../Firebase/FirebaseConfig"; 4 | import { AuthContext } from "../Context/UserContext"; 5 | import toast, { Toaster } from "react-hot-toast"; 6 | 7 | function useUpdateLikedMovies() { 8 | const { User } = useContext(AuthContext); 9 | const [Error, setError] = useState(false); 10 | 11 | function notify() { 12 | toast.success(" Movie added to Liked List "); 13 | } 14 | function removeNotify() { 15 | toast.success(" Movie removed from Liked List "); 16 | } 17 | function alertError(message) { 18 | toast.error(message); 19 | } 20 | 21 | const addToLikedMovies = (movie) => { 22 | updateDoc(doc(db, "LikedMovies", User.uid), { 23 | movies: arrayUnion(movie), 24 | }).then(() => { 25 | notify(); 26 | }); 27 | }; 28 | 29 | const removeFromLikedMovies = (movie) => { 30 | updateDoc(doc(db, "LikedMovies", User.uid), { 31 | movies: arrayRemove(movie), 32 | }) 33 | .then(() => { 34 | removeNotify(); 35 | }) 36 | .catch((error) => { 37 | console.log(error.code); 38 | console.log(error.message); 39 | alertError(error.message); 40 | setError(true); 41 | }); 42 | }; 43 | 44 | const LikedMoviePopupMessage = ( 45 | 54 | ); 55 | 56 | return { addToLikedMovies, removeFromLikedMovies, LikedMoviePopupMessage }; 57 | } 58 | 59 | export default useUpdateLikedMovies; 60 | -------------------------------------------------------------------------------- /src/CustomHooks/useUpdateMylist.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext, useState } from "react"; 2 | import { updateDoc, doc, arrayUnion, arrayRemove } from "firebase/firestore"; 3 | import { db } from "../Firebase/FirebaseConfig"; 4 | import { AuthContext } from "../Context/UserContext"; 5 | import toast, { Toaster } from "react-hot-toast"; 6 | 7 | function useUpdateMylist() { 8 | const { User } = useContext(AuthContext); 9 | const [isMyListUpdates, setisMyListUpdates] = useState(false); 10 | 11 | function notify() { 12 | toast.success(" Movie added to MyList "); 13 | } 14 | function alertError(message) { 15 | toast.error(message); 16 | } 17 | 18 | const addToMyList = (movie) => { 19 | updateDoc(doc(db, "MyList", User.uid), { movies: arrayUnion(movie) }) 20 | .then(() => { 21 | console.log("Data added to my List"); 22 | notify(); 23 | setisMyListUpdates(true); 24 | }) 25 | .catch((error) => { 26 | console.log(error.code); 27 | console.log(error.message); 28 | alertError(error.message); 29 | }); 30 | }; 31 | 32 | const removeFromMyList = (movie) => { 33 | updateDoc(doc(db, "MyList", User.uid), { movies: arrayRemove(movie) }) 34 | .then(() => { 35 | toast.success(" Movie removed from MyList "); 36 | setisMyListUpdates(true); 37 | }) 38 | .catch((error) => { 39 | console.log(error.code); 40 | console.log(error.message); 41 | }); 42 | }; 43 | 44 | const PopupMessage = ( 45 | 54 | ); 55 | 56 | return { addToMyList, removeFromMyList, PopupMessage, isMyListUpdates }; 57 | } 58 | 59 | export default useUpdateMylist; 60 | -------------------------------------------------------------------------------- /src/Constants/Constance.js: -------------------------------------------------------------------------------- 1 | export const baseUrl = "https://api.themoviedb.org/3"; 2 | export const API_KEY = "ecb37597e45cfeed0586f3cd57233d0b"; 3 | export const imageUrl = "https://image.tmdb.org/t/p/original"; 4 | export const imageUrl2 = "https://image.tmdb.org/t/p/w500"; 5 | 6 | export const genresList = [ 7 | { 8 | id: 28, 9 | name: "Action", 10 | }, 11 | { 12 | id: 12, 13 | name: "Adventure", 14 | }, 15 | { 16 | id: 16, 17 | name: "Animation", 18 | }, 19 | { 20 | id: 35, 21 | name: "Comedy", 22 | }, 23 | { 24 | id: 80, 25 | name: "Crime", 26 | }, 27 | { 28 | id: 99, 29 | name: "Documentary", 30 | }, 31 | { 32 | id: 18, 33 | name: "Drama", 34 | }, 35 | { 36 | id: 10751, 37 | name: "Family", 38 | }, 39 | { 40 | id: 14, 41 | name: "Fantasy", 42 | }, 43 | { 44 | id: 36, 45 | name: "History", 46 | }, 47 | { 48 | id: 27, 49 | name: "Horror", 50 | }, 51 | { 52 | id: 10402, 53 | name: "Music", 54 | }, 55 | { 56 | id: 9648, 57 | name: "Mystery", 58 | }, 59 | { 60 | id: 10749, 61 | name: "Romance", 62 | }, 63 | { 64 | id: 878, 65 | name: "Science Fiction", 66 | }, 67 | { 68 | id: 10770, 69 | name: "TV Movie", 70 | }, 71 | { 72 | id: 53, 73 | name: "Thriller", 74 | }, 75 | { 76 | id: 10752, 77 | name: "War", 78 | }, 79 | { 80 | id: 37, 81 | name: "Western", 82 | }, 83 | { 84 | id: 10759, 85 | name: "Action & Adventure", 86 | }, 87 | { 88 | id: 10762, 89 | name: "Kids", 90 | }, 91 | { 92 | id: 10763, 93 | name: "News", 94 | }, 95 | { 96 | id: 10764, 97 | name: "Reality", 98 | }, 99 | { 100 | id: 10765, 101 | name: "Sci-Fi & Fantasy", 102 | }, 103 | { 104 | id: 10766, 105 | name: "Soap", 106 | }, 107 | { 108 | id: 10767, 109 | name: "Talk", 110 | }, 111 | { 112 | id: 10768, 113 | name: "War & Politics", 114 | }, 115 | ]; 116 | -------------------------------------------------------------------------------- /src/Pages/Home.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useEffect, useState, useContext } from "react"; 3 | import Banner from "../componets/Banner/Banner"; 4 | import Footer from "../componets/Footer/Footer"; 5 | import RowPost from "../componets/RowPost/RowPost"; 6 | import { 7 | originals, 8 | trending, 9 | comedy, 10 | horror, 11 | Adventure, 12 | SciFi, 13 | Animated, 14 | War, 15 | trendingSeries, 16 | UpcomingMovies, 17 | } from "../Constants/URLs"; 18 | import { doc, getDoc } from "firebase/firestore"; 19 | import { db } from "../Firebase/FirebaseConfig"; 20 | import { AuthContext } from "../Context/UserContext"; 21 | 22 | function Home() { 23 | const { User } = useContext(AuthContext); 24 | const [watchedMovies, setWatchedMovies] = useState([]); 25 | 26 | useEffect(() => { 27 | getDoc(doc(db, "WatchedMovies", User.uid)).then((result) => { 28 | if (result.exists()) { 29 | const mv = result.data(); 30 | setWatchedMovies(mv.movies); 31 | } 32 | }); 33 | }, []); 34 | 35 | return ( 36 |
37 | 38 |
39 | 40 | 41 | {watchedMovies.length != 0 ? ( 42 | 47 | ) : null} 48 | 54 | 59 | 60 | 61 | 62 | 63 | 64 | 65 |
66 |
67 |
68 | ); 69 | } 70 | 71 | export default Home; 72 | -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useContext, lazy, Suspense } from "react"; 2 | import "./App.css"; 3 | 4 | const Home = lazy(() => import("./Pages/Home")); 5 | const Series = lazy(() => import("./Pages/Series")); 6 | const Search = lazy(() => import("./Pages/Search")); 7 | const Profile = lazy(() => import("./Pages/Profile")); 8 | const MyList = lazy(() => import("./Pages/MyList")); 9 | const SignIn = lazy(() => import("./Pages/SignIn")); 10 | const SignUp = lazy(() => import("./Pages/SignUp")); 11 | const Welcome = lazy(() => import("./Pages/Welcome")); 12 | const ErrorPage = lazy(() => import("./Pages/ErrorPage")); 13 | const Play = lazy(() => import("./Pages/Play")); 14 | const LikedMovies = lazy(() => import("./Pages/LikedMovies")); 15 | const History = lazy(() => import("./Pages/History")); 16 | 17 | import { Routes, Route, Navigate } from "react-router-dom"; 18 | import { AuthContext } from "./Context/UserContext"; 19 | import { getAuth, onAuthStateChanged } from "firebase/auth"; 20 | import Loading from "./componets/Loading/Loading"; 21 | import Navbar from "./componets/Header/Navbar"; 22 | import NavbarWithoutUser from "./componets/Header/NavbarWithoutUser"; 23 | 24 | function App() { 25 | const { User, setUser } = useContext(AuthContext); 26 | useEffect(() => { 27 | const auth = getAuth(); 28 | onAuthStateChanged(auth, (user) => { 29 | setUser(user); 30 | console.log(user); 31 | }); 32 | }, []); 33 | 34 | return ( 35 |
36 | {User ? : } 37 | }> 38 | 39 | : } /> 40 | {User ? ( 41 | <> 42 | } /> 43 | } /> 44 | } /> 45 | } /> 46 | } /> 47 | } /> 48 | } /> 49 | } /> 50 | 51 | ) : null} 52 | } /> 53 | 54 | } /> 55 | } /> 56 | } /> 57 | 58 | 59 |
60 | ); 61 | } 62 | 63 | export default App; 64 | -------------------------------------------------------------------------------- /src/componets/RowPost/RowPostStyles.scss: -------------------------------------------------------------------------------- 1 | .SwiperStyle:hover { 2 | .swiper-button-prev { 3 | opacity: 1; 4 | transition: all 400ms ease-out 0s; 5 | } 6 | .swiper-button-next { 7 | opacity: 1; 8 | transition: all 400ms ease-out 0s; 9 | } 10 | 11 | .swiper-pagination { 12 | opacity: 1; 13 | } 14 | } 15 | 16 | .swiper-button-prev { 17 | color: white; 18 | opacity: 0; 19 | transition: all 400ms ease-out 0s; 20 | } 21 | .swiper-button-next { 22 | color: white; 23 | opacity: 0; 24 | transition: all 400ms ease-out 0s; 25 | } 26 | 27 | .swiper-pagination { 28 | position: initial; 29 | display: flex; 30 | justify-content: flex-end; 31 | opacity: 0; 32 | margin-top: -0.8rem; 33 | margin-bottom: 0.8rem; 34 | } 35 | .swiper-pagination-bullet { 36 | cursor: pointer; 37 | width: 12px; 38 | height: 4px; 39 | display: inline-block; 40 | opacity: 1; 41 | background-color: hsl(0deg 0% 30%); 42 | border-radius: 0px; 43 | transition: all 0.2s ease-in-out 0s; 44 | margin: 0px 0px 0px 2px !important; 45 | } 46 | .swiper-pagination-bullet-active { 47 | background-color: white; 48 | cursor: pointer; 49 | } 50 | 51 | .swiper-wrapper { 52 | padding: 40px 0; 53 | &:hover .swiper-slide { 54 | transform: translateX(-17%); 55 | z-index: -1; 56 | } 57 | } 58 | 59 | .swiper-slide:hover ~ .swiper-slide { 60 | transform: translateX(17%); 61 | } 62 | .swiper-slide:hover { 63 | z-index: 20; 64 | transition: all 350ms ease-out 0s; 65 | cursor: pointer; 66 | // border-left: 2px solid red; 67 | } 68 | .swiper-wrapper:hover { 69 | .swiper-slide { 70 | opacity: 0.4; 71 | } 72 | } 73 | .swiper-wrapper .swiper-slide:hover { 74 | opacity: 1; 75 | } 76 | 77 | .swiper-wrapper .swiper-slide:hover { 78 | transform: scale(1.5); 79 | z-index: 5; 80 | } 81 | .swiper-slide { 82 | transition: all 350ms ease-out 0s; 83 | 84 | &:hover img { 85 | z-index: 1; 86 | } 87 | &:first-child:hover { 88 | margin: 0 75px; 89 | } 90 | &:last-child:hover { 91 | margin: 0 -75px; 92 | } 93 | } 94 | .swiper-slide:hover { 95 | transition: all 350ms ease-out 0s; 96 | } 97 | 98 | .content { 99 | transition: all 0.5; 100 | background: linear-gradient( 101 | 0.05turn, 102 | rgba(0, 0, 0, 0.871), 103 | rgba(0, 0, 0, 0.023) 65% 104 | ); 105 | position: absolute; 106 | bottom: -1.25rem; 107 | left: 0; 108 | padding-bottom: 1rem; 109 | width: 100%; 110 | display: none; 111 | box-sizing: border-box; 112 | } 113 | 114 | .swiper-slide:hover { 115 | .content { 116 | transition: all 0.5s; 117 | display: initial; 118 | bottom: 0; 119 | } 120 | } 121 | 122 | .swiper-slide.large { 123 | &:hover { 124 | transform: scale(1.2) !important; 125 | } 126 | 127 | .swiper-wrapper { 128 | padding: 40px 0; 129 | &:hover .swiper-slide { 130 | transform: translateX(-12%) !important; 131 | z-index: -1; 132 | } 133 | } 134 | 135 | .swiper-slide:hover ~ .swiper-slide { 136 | transform: translateX(12%) !important; 137 | } 138 | } 139 | 140 | .YouTubeVid { 141 | iframe { 142 | height: 27rem; 143 | } 144 | } 145 | 146 | @media only screen and (max-width: 650px) { 147 | .YouTubeVid { 148 | iframe { 149 | height: 13rem; 150 | } 151 | } 152 | } 153 | 154 | @media only screen and (max-width: 1050px) { 155 | .swiper-wrapper { 156 | padding: 0; 157 | &:hover.swiper-slide { 158 | transform: translateX(0); 159 | } 160 | } 161 | .swiper-wrapper:hover .swiper-slide { 162 | transform: translateX(0%); 163 | } 164 | .swiper-slide:hover ~ .swiper-slide { 165 | transform: translateX(0); 166 | } 167 | .swiper-wrapper .swiper-slide:hover { 168 | transform: scale(1.03); 169 | } 170 | .swiper-slide.large { 171 | &:hover { 172 | transform: scale(1.03) !important; 173 | } 174 | } 175 | 176 | .swiper-slide { 177 | transition: all 350ms ease-out 0s; 178 | 179 | &:hover img { 180 | z-index: 1; 181 | } 182 | &:first-child:hover { 183 | margin: 0; 184 | } 185 | &:last-child:hover { 186 | margin: 0; 187 | } 188 | } 189 | 190 | .swiper-slide:hover { 191 | .content { 192 | transition: all 0.5s; 193 | display: initial; 194 | bottom: -10.25rem; 195 | } 196 | } 197 | } 198 | 199 | .ytp-title-expanded-heading { 200 | display: none; 201 | } 202 | -------------------------------------------------------------------------------- /src/Pages/Welcome.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useEffect } from "react"; 3 | 4 | import Footer from "../componets/Footer/Footer"; 5 | 6 | import WelcomePageImage1 from "../images/WelcomePageImage1.png"; 7 | import WelcomePageImage2 from "../images/WelcomePageImage2.png"; 8 | import WelcomePageImage3 from "../images/WelcomePageImage3.png"; 9 | import WelcomePageImage4 from "../images/WelcomePageImage4.png"; 10 | import WelcomePageBanner from "../images/WelcomePageBanner.jpg"; 11 | 12 | import { Fade } from "react-reveal"; 13 | import { Link } from "react-router-dom"; 14 | 15 | function Welcome() { 16 | useEffect(() => { 17 | //alert("This is NOT REAL NETFLIX so don't Enter your REAL CREDENTIALS") 18 | const image1 = WelcomePageImage1; 19 | }, []); 20 | 21 | return ( 22 |
23 | {/*Hero Section*/} 24 |
30 |
31 |
32 | 33 |

34 | Unlimited movies, TV shows and more. 35 |

36 |

37 | Watch anywahere.Cancel anytime 38 |

39 |

40 | Ready to watch? Enter your email to create or restart your 41 | membership. 42 |

43 |
44 | 48 | 49 | 52 | 53 |
54 |
55 |
56 |
57 |
63 |
64 | 65 | {/* Section 2 */} 66 |
67 | 68 |
69 |
70 |
71 |

72 | Enjoy on your TV. 73 |

74 |

75 | Watch on smart TVs, PlayStation, Xbox, Chromecast, Apple TV, 76 | Blu-ray players and more. 77 |

78 |
79 |
80 | 81 |
82 |
83 |
84 |
85 |
86 | 87 | {/* Section 3 */} 88 |
89 | 90 |
91 |
92 |
93 | 94 |
95 |
96 |

97 | Download your shows to watch offline. 98 |

99 |

100 | Save your favourites easily and always have something to 101 | watch. 102 |

103 |
104 |
105 |
106 |
107 |
108 | 109 | {/* Section 4 */} 110 |
111 | 112 |
113 |
114 |
115 |

116 | Watch everywhere. 117 |

118 |

119 | Stream unlimited movies and TV shows on your phone, tablet, 120 | laptop, and TV. 121 |

122 |
123 |
124 | 125 |
126 |
127 |
128 |
129 |
130 | 131 | {/* Section 5 */} 132 |
133 | 134 |
135 |
136 |
137 | 138 |
139 |
140 |

141 | Create profiles for children. 142 |

143 |

144 | Send children on adventures with their favourite characters in 145 | a space made just for them—free with your membership. 146 |

147 |
148 |
149 |
150 |
151 |
152 | 153 | {/* Section 6 */} 154 |
155 | 156 | {/* Footer */} 157 |
158 |
159 | ); 160 | } 161 | 162 | export default Welcome; 163 | -------------------------------------------------------------------------------- /src/Pages/SignUp.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useState, useContext } from "react"; 3 | 4 | import { Link, useNavigate } from "react-router-dom"; 5 | import { Fade } from "react-reveal"; 6 | import { 7 | getAuth, 8 | createUserWithEmailAndPassword, 9 | onAuthStateChanged, 10 | } from "firebase/auth"; 11 | import { setDoc, doc } from "firebase/firestore"; 12 | import { db } from "../Firebase/FirebaseConfig"; 13 | import { AuthContext } from "../Context/UserContext"; 14 | import { ClipLoader } from "react-spinners"; 15 | import WelcomePageBanner from "../images/WelcomePageBanner.jpg"; 16 | 17 | function SignUp() { 18 | const { User, setUser } = useContext(AuthContext); 19 | 20 | const [email, setEmail] = useState(""); 21 | const [password, setPassword] = useState(""); 22 | const [ErrorMessage, setErrorMessage] = useState(""); 23 | const [loader, setLoader] = useState(false); 24 | 25 | const navigate = useNavigate(); 26 | 27 | const handleSubmit = (e) => { 28 | e.preventDefault(); 29 | setLoader(true); 30 | 31 | const auth = getAuth(); 32 | createUserWithEmailAndPassword(auth, email, password) 33 | .then((userCredential) => { 34 | // Signed in 35 | onAuthStateChanged(auth, (user) => { 36 | const EmptyArray = []; 37 | setDoc(doc(db, "Users", user.uid), { 38 | email: email, 39 | Uid: user.uid, 40 | }).then(() => { 41 | setDoc( 42 | doc(db, "MyList", user.uid), 43 | { 44 | movies: EmptyArray, 45 | }, 46 | { merge: true } 47 | ).then(() => { 48 | setDoc( 49 | doc(db, "WatchedMovies", user.uid), 50 | { 51 | movies: EmptyArray, 52 | }, 53 | { merge: true } 54 | ); 55 | setDoc( 56 | doc(db, "LikedMovies", user.uid), 57 | { 58 | movies: EmptyArray, 59 | }, 60 | { merge: true } 61 | ); 62 | }); 63 | }); 64 | }); 65 | 66 | const user = userCredential.user; 67 | if (user != null) { 68 | navigate("/"); 69 | } 70 | }) 71 | .catch((error) => { 72 | const errorCode = error.code; 73 | const errorMessage = error.message; 74 | setLoader(false); 75 | setErrorMessage(errorMessage); 76 | console.log(errorCode); 77 | console.log(errorMessage); 78 | }); 79 | }; 80 | 81 | return ( 82 |
88 |
89 |
90 | 91 |
92 |
93 |

94 | Create a new account 95 |

96 |

97 | Not Real Netflix 98 |

99 |
104 |
105 | 111 | setEmail(e.target.value)} 113 | type="email" 114 | name="email" 115 | id="email" 116 | className={ 117 | ErrorMessage 118 | ? "bg-stone-700 text-white sm:text-sm rounded-sm border-2 border-red-700 focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:text-white " 119 | : "bg-stone-700 text-white sm:text-sm rounded-sm focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:text-white " 120 | } 121 | placeholder="name@emil.com" 122 | required="" 123 | > 124 |
125 |
126 | 132 | setPassword(e.target.value)} 134 | type="password" 135 | name="password" 136 | id="password" 137 | placeholder="••••••••" 138 | className={ 139 | ErrorMessage 140 | ? "bg-stone-700 text-white sm:text-sm rounded-sm border-2 border-red-700 focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5" 141 | : "bg-stone-700 text-white sm:text-sm rounded-sm focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:text-white" 142 | } 143 | required="" 144 | > 145 |
146 |
147 | {ErrorMessage && ( 148 |

149 | 157 | 162 | 163 | 164 | {ErrorMessage} 165 |

166 | )} 167 |
168 |
169 |
170 |
171 | 178 |
179 |
180 | 183 |
184 |
185 |
186 | 196 |

197 | Already have one?{" "} 198 | 202 | Sign in 203 | 204 |

205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 | ); 213 | } 214 | 215 | export default SignUp; 216 | -------------------------------------------------------------------------------- /src/componets/Banner/Banner.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect, useContext } from "react"; 2 | import { API_KEY, imageUrl } from "../../Constants/Constance"; 3 | import axios from "../../axios"; 4 | import { PopUpContext } from "../../Context/moviePopUpContext"; 5 | import { Fade } from "react-reveal"; 6 | import StarRatings from "react-star-ratings"; 7 | import MoviePopUp from "../PopUp/MoviePopUp"; 8 | import usePlayMovie from "../../CustomHooks/usePlayMovie"; 9 | 10 | function Banner(props) { 11 | const { showModal, setShowModal } = useContext(PopUpContext); 12 | const { playMovie } = usePlayMovie(); 13 | 14 | const [movie, setMovie] = useState([]); 15 | const [moviePopupInfo, setMoviePopupInfo] = useState({}); 16 | const [urlId, setUrlId] = useState(""); 17 | 18 | function getWindowSize() { 19 | const {innerWidth:width } = window; 20 | return { 21 | width 22 | } 23 | } 24 | 25 | const [windowSeize, setWindowSeize] = useState(getWindowSize()) 26 | 27 | 28 | useEffect(() => { 29 | axios.get(props.url).then((response) => { 30 | setMovie( 31 | response.data.results.sort(function (a, b) { 32 | return 0.5 - Math.random(); 33 | })[0] 34 | ); 35 | console.log(movie); 36 | }); 37 | 38 | function handleWindowResize() { 39 | setWindowSeize(getWindowSize()) 40 | } 41 | 42 | window.addEventListener('resize', handleWindowResize) 43 | 44 | }, []); 45 | 46 | const handleMoviePopup = (movieInfo) => { 47 | setMoviePopupInfo(movieInfo); 48 | setShowModal(true); 49 | 50 | axios 51 | .get(`/movie/${movieInfo.id}/videos?api_key=${API_KEY}&language=en-US`) 52 | .then((responce) => { 53 | console.log(responce.data); 54 | if (responce.data.results.length !== 0) { 55 | setUrlId(responce.data.results[0]); 56 | } else { 57 | console.log("Array Emptey"); 58 | } 59 | }); 60 | }; 61 | 62 | return ( 63 | <> 64 |
74 |
75 | 76 | {movie.title || movie.name ? ( 77 | <> 78 |

79 | {movie.title || movie.name} 80 |

81 | 82 | ) : ( 83 |
84 |
85 |
86 | )} 87 | 88 | 89 |
90 |
91 | {movie.vote_average ? ( 92 |

93 |
94 | 102 |
103 |

104 | ) : null} 105 |
106 |
107 | {movie.release_date || movie.first_air_date ? ( 108 |

109 | {movie.release_date || movie.first_air_date} 110 |

111 | ) : null} 112 |
113 | {movie.id && ( 114 |

115 | HD 116 |

117 | )} 118 |
119 | 120 |
121 | {movie.overview ? ( 122 | <> 123 |

124 | {movie.overview} 125 |

126 | 127 | ) : ( 128 | <> 129 |
130 |
131 |
132 |
133 |
134 | 135 | )} 136 |
137 | 138 |
139 | {movie.id ? ( 140 | <> 141 | 161 | 181 | 182 | ) : ( 183 | <> 184 | 206 | 223 | 224 | )} 225 |
226 |
227 |
228 |
235 |
236 | 237 | {showModal ? : null} 238 | 239 | ); 240 | } 241 | 242 | export default Banner; 243 | -------------------------------------------------------------------------------- /src/Pages/Search.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useState, useContext } from "react"; 3 | import { API_KEY, imageUrl2 } from "../Constants/Constance"; 4 | import { PopUpContext } from "../Context/moviePopUpContext"; 5 | import useUpdateMylist from "../CustomHooks/useUpdateMylist"; 6 | import axios from "../axios"; 7 | import MoviePopUp from "../componets/PopUp/MoviePopUp"; 8 | import usePlayMovie from "../CustomHooks/usePlayMovie"; 9 | import useUpdateLikedMovies from "../CustomHooks/useUpdateLikedMovies"; 10 | import useGenereConverter from "../CustomHooks/useGenereConverter"; 11 | import StarRatings from "react-star-ratings"; 12 | 13 | function Search() { 14 | const { showModal, setShowModal } = useContext(PopUpContext); 15 | const { addToMyList, PopupMessage } = useUpdateMylist(); 16 | const { playMovie } = usePlayMovie(); 17 | const { addToLikedMovies } = useUpdateLikedMovies(); 18 | const { convertGenere } = useGenereConverter(); 19 | 20 | const [searchQuery, setSearchQuery] = useState(""); 21 | const [movies, setMovies] = useState([]); 22 | const [moviePopupInfo, setMoviePopupInfo] = useState({}); 23 | 24 | const Search = (e) => { 25 | setSearchQuery(e.target.value); 26 | e.preventDefault(); 27 | console.log(searchQuery); 28 | 29 | axios 30 | .get( 31 | `/search/movie?api_key=${API_KEY}&language=en-US&query=${searchQuery}&page=1&include_adult=false` 32 | ) 33 | .then((response) => { 34 | console.log(response.data.results); 35 | setMovies(response.data.results); 36 | }); 37 | 38 | if (searchQuery === "") { 39 | setMovies([]); 40 | } 41 | }; 42 | 43 | const handleMoviePopup = (movieInfo) => { 44 | setMoviePopupInfo(movieInfo); 45 | setShowModal(true); 46 | }; 47 | 48 | return ( 49 |
50 | {PopupMessage} 51 | 52 |
53 | 60 | 80 |
81 | 82 | {/* Search results */} 83 |
84 | {movies.length !== 0 ? ( 85 | movies.map((movie) => { 86 | const converted = convertGenere(movie.genre_ids); 87 | return ( 88 |
89 |
90 | 94 | handleMoviePopup(movie)} 96 | className="" 97 | src={ 98 | movie.backdrop_path 99 | ? imageUrl2 + movie.backdrop_path 100 | : "https://i.ytimg.com/vi/Mwf--eGs05U/maxresdefault.jpg" 101 | } 102 | /> 103 | 104 | 218 |
219 |
220 | ); 221 | }) 222 | ) : ( 223 | <> 224 |
225 |
226 |
227 |
228 | 229 | )} 230 |
231 | 232 | {showModal ? : null} 233 |
234 | ); 235 | } 236 | 237 | export default Search; 238 | -------------------------------------------------------------------------------- /src/Pages/SignIn.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useState, useContext } from "react"; 3 | import { Link, useNavigate } from "react-router-dom"; 4 | import { Fade } from "react-reveal"; 5 | import { ClipLoader } from "react-spinners"; 6 | import { 7 | getAuth, 8 | signInWithEmailAndPassword, 9 | GoogleAuthProvider, 10 | signInWithPopup, 11 | } from "firebase/auth"; 12 | import { setDoc, doc, getDoc } from "firebase/firestore"; 13 | import { db } from "../Firebase/FirebaseConfig"; 14 | import { AuthContext } from "../Context/UserContext"; 15 | 16 | import GoogleLogo from "../images/GoogleLogo.png"; 17 | import WelcomePageBanner from "../images/WelcomePageBanner.jpg"; 18 | 19 | function SignIn() { 20 | const { User, setUser } = useContext(AuthContext); 21 | const navigate = useNavigate(); 22 | 23 | const [email, setEmail] = useState(""); 24 | const [password, setPassword] = useState(""); 25 | const [ErrorMessage, setErrorMessage] = useState(""); 26 | const [loader, setLoader] = useState(false); 27 | 28 | const handleSubmit = (e) => { 29 | e.preventDefault(); 30 | setLoader(true); 31 | 32 | const auth = getAuth(); 33 | signInWithEmailAndPassword(auth, email, password) 34 | .then((userCredential) => { 35 | // Signed in 36 | const user = userCredential.user; 37 | console.log(user); 38 | if (user != null) { 39 | navigate("/"); 40 | } 41 | }) 42 | .catch((error) => { 43 | const errorCode = error.code; 44 | const errorMessage = error.message; 45 | setErrorMessage(error.message); 46 | setLoader(false); 47 | console.log(errorCode); 48 | console.log(errorMessage); 49 | }); 50 | }; 51 | 52 | const loginWithGoogle = (e) => { 53 | e.preventDefault(); 54 | const auth = getAuth(); 55 | const provider = new GoogleAuthProvider(); 56 | 57 | signInWithPopup(auth, provider) 58 | .then((result) => { 59 | const user = result.user; 60 | console.log(user); 61 | const EmptyArray = []; 62 | 63 | setDoc( 64 | doc(db, "Users", user.uid), 65 | { 66 | email: user.email, 67 | Uid: user.uid, 68 | }, 69 | { merge: true } 70 | ).then(() => { 71 | getDoc(doc(db, "MyList", user.uid)).then((result) => { 72 | if (result.exists()) { 73 | // Data exist in MyList section for this user 74 | } else { 75 | // Creating a new MyList, WatchedMovies List, LikedMovies List for the user in the database 76 | setDoc( 77 | doc(db, "MyList", user.uid), 78 | { 79 | movies: EmptyArray, 80 | }, 81 | { merge: true } 82 | ); 83 | setDoc( 84 | doc(db, "WatchedMovies", user.uid), 85 | { 86 | movies: EmptyArray, 87 | }, 88 | { merge: true } 89 | ); 90 | setDoc( 91 | doc(db, "LikedMovies", user.uid), 92 | { 93 | movies: EmptyArray, 94 | }, 95 | { merge: true } 96 | ).then(() => { 97 | navigate("/"); 98 | }); 99 | } 100 | }); 101 | }); 102 | if (user != null) { 103 | navigate("/"); 104 | } 105 | }) 106 | .catch((error) => { 107 | const errorCode = error.code; 108 | const errorMessage = error.message; 109 | setErrorMessage(error.message); 110 | setLoader(false); 111 | // The email of the user's account used. 112 | const email = error.customData.email; 113 | // The AuthCredential type that was used. 114 | const credential = GoogleAuthProvider.credentialFromError(error); 115 | }); 116 | }; 117 | 118 | return ( 119 |
125 |
126 |
127 | 128 |
129 |
130 |

131 | Sign in to your account 132 |

133 |

134 | Not Real Netflix 135 |

136 |
141 |
142 | 148 | setEmail(e.target.value)} 160 | > 161 |
162 |
163 | 169 | setPassword(e.target.value)} 181 | > 182 |
183 |
184 | {ErrorMessage && ( 185 |

186 | 194 | 199 | 200 | {ErrorMessage} 201 |

202 | )} 203 |
204 |
205 |
206 |
207 | 214 |
215 |
216 | 222 |
223 |
224 |
225 | 235 | 252 |

253 | Don’t have an account yet?{" "} 254 | 258 | Sign up 259 | 260 |

261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 | ); 269 | } 270 | 271 | export default SignIn; 272 | -------------------------------------------------------------------------------- /src/componets/Header/Navbar.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect, useContext } from "react"; 2 | 3 | import { Transition } from "@headlessui/react"; 4 | import { Fade } from "react-reveal"; 5 | import { Link, useNavigate } from "react-router-dom"; 6 | import { getAuth, signOut } from "firebase/auth"; 7 | import { AuthContext } from "../../Context/UserContext"; 8 | 9 | function Navbar(props) { 10 | const { User } = useContext(AuthContext); 11 | const [profilePic, setProfilePic] = useState(""); 12 | 13 | const navigate = useNavigate(); 14 | 15 | useEffect(() => { 16 | if (User != null) { 17 | setProfilePic(User.photoURL); 18 | } 19 | window.addEventListener("scroll", transitionNavBar); 20 | console.log("Navbar", User); 21 | return () => { 22 | window.removeEventListener("scroll", transitionNavBar); 23 | }; 24 | }, []); 25 | const [isOpen, setIsOpen] = useState(false); 26 | 27 | const [show, handleShow] = useState(false); 28 | const transitionNavBar = () => { 29 | if (window.scrollY > 80) { 30 | handleShow(true); 31 | } else { 32 | handleShow(false); 33 | } 34 | }; 35 | 36 | const NavBlack = () => { 37 | handleShow(true); 38 | }; 39 | const NavTransparent = () => { 40 | handleShow(false); 41 | }; 42 | 43 | const SignOut = () => { 44 | const auth = getAuth(); 45 | signOut(auth) 46 | .then(() => { 47 | navigate("/"); 48 | }) 49 | .catch((error) => { 50 | alert(error.message); 51 | }); 52 | }; 53 | 54 | return ( 55 | 56 |
63 | 310 |
311 |
312 | ); 313 | } 314 | 315 | export default Navbar; 316 | -------------------------------------------------------------------------------- /src/Pages/Profile.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useContext, useEffect, useRef } from "react"; 2 | import { getAuth, updateProfile, signOut } from "firebase/auth"; 3 | import { db } from "../Firebase/FirebaseConfig"; 4 | import { 5 | ref, 6 | uploadBytesResumable, 7 | getDownloadURL, 8 | getStorage, 9 | } from "firebase/storage"; 10 | import { useNavigate } from "react-router-dom"; 11 | import { Fade } from "react-reveal"; 12 | import toast, { Toaster } from "react-hot-toast"; 13 | 14 | import { AuthContext } from "../Context/UserContext"; 15 | import WelcomePageBanner from "../images/WelcomePageBanner.jpg"; 16 | 17 | import "swiper/css"; 18 | import "swiper/css/navigation"; 19 | import "swiper/css/pagination"; 20 | 21 | function Profile() { 22 | const { User } = useContext(AuthContext); 23 | 24 | const [profilePic, setProfilePic] = useState(""); 25 | const [newProfielPicURL, setNewProfielPicURL] = useState(""); 26 | const [newProfielPic, setNewProfielPic] = useState(""); 27 | const [isUserNameChanged, setIsUserNameChanged] = useState(false); 28 | const [userName, setUserName] = useState(""); 29 | const [isMyListUpdated, setisMyListUpdated] = useState(false); 30 | 31 | const navigate = useNavigate(); 32 | 33 | useEffect(() => { 34 | if (User != null) { 35 | console.log(User.photoURL, "hello"); 36 | setProfilePic(User.photoURL); 37 | } 38 | }, []); 39 | 40 | const inputRef = useRef(null); 41 | 42 | const handleClick = () => { 43 | inputRef.current.click(); 44 | }; 45 | 46 | function notify() { 47 | toast.success(" Data Updated Sucessfuly "); 48 | } 49 | 50 | const handleFileChange = (event) => { 51 | const fileObj = event.target.files[0]; 52 | setNewProfielPic(fileObj); 53 | setNewProfielPicURL(URL.createObjectURL(fileObj)); 54 | if (!fileObj) { 55 | return; 56 | } 57 | console.log("fileObj is", fileObj); 58 | event.target.value = null; 59 | }; 60 | 61 | const changeUserName = (e) => { 62 | e.preventDefault(); 63 | if (isUserNameChanged) { 64 | if (userName !== "") { 65 | const auth = getAuth(); 66 | updateProfile(auth.currentUser, { displayName: userName }) 67 | .then(() => { 68 | notify(); 69 | }) 70 | .catch((error) => { 71 | alert(error.message); 72 | }); 73 | } else { 74 | setIsUserNameChanged(false); 75 | } 76 | } 77 | 78 | if (newProfielPic != "") { 79 | const storage = getStorage(); 80 | const storageRef = ref(storage, `/ProfilePics/${User.uid}`); 81 | const uploadTask = uploadBytesResumable(storageRef, newProfielPic); 82 | 83 | uploadTask.on( 84 | "state_changed", 85 | (snapshot) => { 86 | const prog = Math.round( 87 | (snapshot.bytesTransferred / snapshot.totalBytes) * 100 88 | ); 89 | }, 90 | (error) => { 91 | alert(error.message); 92 | alert(error.code); 93 | }, 94 | () => { 95 | getDownloadURL(uploadTask.snapshot.ref).then((url) => { 96 | console.log(url, "This is the new Url for Profile Pic"); 97 | setProfilePic(url); 98 | const auth = getAuth(); 99 | updateProfile(auth.currentUser, { photoURL: url }) 100 | .then(() => { 101 | notify(); 102 | setisMyListUpdated(true); 103 | }) 104 | .catch((error) => { 105 | alert(error.message); 106 | }); 107 | }); 108 | } 109 | ); 110 | } 111 | }; 112 | 113 | const updateProfilePic = (imageURL) => { 114 | const auth = getAuth(); 115 | updateProfile(auth.currentUser, { photoURL: imageURL }) 116 | .then(() => { 117 | setProfilePic(User.photoURL); 118 | notify(); 119 | }) 120 | .catch((error) => { 121 | alert(error.message); 122 | }); 123 | }; 124 | 125 | const SignOut = () => { 126 | const auth = getAuth(); 127 | signOut(auth) 128 | .then(() => { 129 | navigate("/"); 130 | }) 131 | .catch((error) => { 132 | alert(error.message); 133 | }); 134 | }; 135 | 136 | return ( 137 |
138 |
144 | {isMyListUpdated ? ( 145 | 154 | ) : null} 155 | 156 |
157 |

158 | Edit your Profile 159 |

160 |
161 | NETFLIX 174 |
175 |
176 |

177 | User Name 178 |

179 | 182 | setUserName(e.target.value) || setIsUserNameChanged(true) 183 | } 184 | className="block w-full rounded-md bg-stone-900 text-white border-gray-300 p-2 mb-6 focus:border-indigo-500 focus:ring-indigo-500 sm:text-base" 185 | placeholder={User ? User.displayName : null} 186 | /> 187 |

Email

188 |

189 | {User ? User.email : null} 190 |

191 |

192 | Unique ID : {User ? User.uid : null} 193 |

194 |
195 | 196 |

197 | Who is Watching ? 198 |

199 |
200 | 202 | updateProfilePic( 203 | "https://i.pinimg.com/originals/ba/2e/44/ba2e4464e0d7b1882cc300feceac683c.png" 204 | ) 205 | } 206 | className="w-16 h-16 rounded-md cursor-pointer" 207 | src="https://i.pinimg.com/originals/ba/2e/44/ba2e4464e0d7b1882cc300feceac683c.png" 208 | /> 209 | 211 | updateProfilePic( 212 | "https://i.pinimg.com/736x/db/70/dc/db70dc468af8c93749d1f587d74dcb08.jpg" 213 | ) 214 | } 215 | className="w-16 h-16 rounded-md cursor-pointer" 216 | src="https://i.pinimg.com/736x/db/70/dc/db70dc468af8c93749d1f587d74dcb08.jpg" 217 | /> 218 | 220 | updateProfilePic( 221 | "https://upload.wikimedia.org/wikipedia/commons/0/0b/Netflix-avatar.png" 222 | ) 223 | } 224 | className="w-16 h-16 rounded-md cursor-pointer" 225 | src="https://upload.wikimedia.org/wikipedia/commons/0/0b/Netflix-avatar.png" 226 | /> 227 | 229 | updateProfilePic( 230 | "https://ih0.redbubble.net/image.618363037.0853/flat,1000x1000,075,f.u2.jpg" 231 | ) 232 | } 233 | className="w-16 h-16 rounded-md cursor-pointer" 234 | src="https://ih0.redbubble.net/image.618363037.0853/flat,1000x1000,075,f.u2.jpg" 235 | /> 236 | 242 | 251 | 256 | 257 |
258 | {newProfielPicURL ? ( 259 | 260 | ) : null} 261 |
262 |
263 |
264 | 284 | {userName != "" || newProfielPic != "" ? ( 285 | 305 | ) : ( 306 | 326 | )} 327 |
328 |
329 |
330 |
331 |
332 | ); 333 | } 334 | 335 | export default Profile; 336 | -------------------------------------------------------------------------------- /src/componets/UserMovieSection/UserMovieSection.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useEffect, useState, useContext } from "react"; 3 | import { useNavigate } from "react-router-dom"; 4 | import MoviePopUp from "../PopUp/MoviePopUp"; 5 | import { imageUrl2, API_KEY } from "../../Constants/Constance"; 6 | import useUpdateMylist from "../../CustomHooks/useUpdateMylist"; 7 | import usePlayMovie from "../../CustomHooks/usePlayMovie"; 8 | import useUpdateWatchedMovies from "../../CustomHooks/useUpdateWatchedMovies"; 9 | import useUpdateLikedMovies from "../../CustomHooks/useUpdateLikedMovies"; 10 | import useGenereConverter from "../../CustomHooks/useGenereConverter"; 11 | import { db } from "../../Firebase/FirebaseConfig"; 12 | import { doc, getDoc } from "firebase/firestore"; 13 | import { AuthContext } from "../../Context/UserContext"; 14 | import { PopUpContext } from "../../Context/moviePopUpContext"; 15 | import axios from "../../axios"; 16 | import StarRatings from "react-star-ratings"; 17 | import { ClipLoader } from "react-spinners"; 18 | 19 | function UserMovieSection(props) { 20 | const { User } = useContext(AuthContext); 21 | const { showModal, setShowModal } = useContext(PopUpContext); 22 | 23 | const { addToMyList, removeFromMyList, PopupMessage } = useUpdateMylist(); 24 | const { removeFromWatchedMovies, removePopupMessage } = 25 | useUpdateWatchedMovies(); 26 | const { addToLikedMovies, removeFromLikedMovies, LikedMoviePopupMessage } = 27 | useUpdateLikedMovies(); 28 | const { playMovie } = usePlayMovie(); 29 | const { convertGenere } = useGenereConverter(); 30 | 31 | const [myMovies, setMyMovies] = useState([]); 32 | const [moviePopupInfo, setMoviePopupInfo] = useState({}); 33 | const [title, setTitle] = useState(""); 34 | const [isResultEmpty, setIsResultEmpty] = useState(false); 35 | 36 | const navigate = useNavigate(); 37 | 38 | function getMovies() { 39 | getDoc(doc(db, props.from, User.uid)).then((result) => { 40 | const mv = result.data(); 41 | setMyMovies(mv.movies); 42 | if (mv.movies.length == 0) { 43 | setIsResultEmpty(true); 44 | } 45 | }); 46 | } 47 | 48 | useEffect(() => { 49 | getMovies(); 50 | if (props.from === "MyList") { 51 | setTitle("Movies in My List"); 52 | } else if (props.from === "WatchedMovies") { 53 | setTitle("Watched Movies"); 54 | } else if (props.from === "LikedMovies") { 55 | setTitle("Movies you Liked"); 56 | } 57 | }, []); 58 | 59 | const removeMovie = (movie) => { 60 | if (props.from === "MyList") { 61 | removeFromMyList(movie); 62 | } else if (props.from === "WatchedMovies") { 63 | removeFromWatchedMovies(movie); 64 | } else if (props.from === "LikedMovies") { 65 | removeFromLikedMovies(movie); 66 | } 67 | getMovies(); 68 | }; 69 | 70 | const handleMoviePopup = (movieInfo) => { 71 | setMoviePopupInfo(movieInfo); 72 | setShowModal(true); 73 | }; 74 | 75 | return ( 76 |
77 | {PopupMessage} 78 | 79 |
80 |

81 | {!isResultEmpty ? title : null} 82 |

83 |
84 | 85 |
86 | {myMovies.length !== 0 ? ( 87 | myMovies 88 | .slice(0) 89 | .reverse() 90 | .map((movie) => { 91 | let converted 92 | if (movie.genre_ids) { 93 | converted = convertGenere(movie.genre_ids); 94 | } 95 | return ( 96 |
97 |
handleMoviePopup(movie)} 100 | > 101 | 102 | handleMoviePopup(movie)} 104 | className="" 105 | src={imageUrl2 + movie.backdrop_path} 106 | /> 107 | 108 | 273 |
274 |
275 | ); 276 | }) 277 | ) : ( 278 | <> 279 |
280 |
281 | {!isResultEmpty ? ( 282 | 283 | ) : ( 284 |
285 |

286 | No Movies Present 287 |

288 |

289 | 311 |
312 | )} 313 |
314 |
315 | 316 | )} 317 |
318 | {showModal ? ( 319 | 320 | ) : null} 321 |
322 | ); 323 | } 324 | 325 | export default UserMovieSection; 326 | -------------------------------------------------------------------------------- /src/componets/PopUp/MoviePopUp.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect, useContext } from "react"; 2 | import { Fade } from "react-reveal"; 3 | import StarRatings from "react-star-ratings"; 4 | import { imageUrl } from "../../Constants/Constance"; 5 | import { PopUpContext } from "../../Context/moviePopUpContext"; 6 | import useUpdateMylist from "../../CustomHooks/useUpdateMylist"; 7 | import usePlayMovie from "../../CustomHooks/usePlayMovie"; 8 | import useGenereConverter from "../../CustomHooks/useGenereConverter"; 9 | import useUpdateLikedMovies from "../../CustomHooks/useUpdateLikedMovies"; 10 | import useUpdateWatchedMovies from "../../CustomHooks/useUpdateWatchedMovies"; 11 | 12 | function MoviePopUp(props) { 13 | const { showModal, setShowModal } = useContext(PopUpContext); 14 | const { addToMyList, removeFromMyList, PopupMessage } = useUpdateMylist(); 15 | const { addToLikedMovies, removeFromLikedMovies, LikedMoviePopupMessage } = useUpdateLikedMovies(); 16 | const { removeFromWatchedMovies, removePopupMessage } = 17 | useUpdateWatchedMovies(); 18 | const { playMovie } = usePlayMovie(); 19 | const { convertGenere } = useGenereConverter(); 20 | 21 | const [PopupInfo, setPopupInfo] = useState({}); 22 | 23 | useEffect(() => { 24 | setPopupInfo(props.data1); 25 | }, []); 26 | 27 | return ( 28 | <> 29 | {PopupMessage} 30 | {showModal && ( 31 | <> 32 |
33 |
34 | {/*content*/} 35 | 36 |
37 | {/*header*/} 38 | 57 | {/*Movie Trailer or Image*/} 58 | {PopupInfo.backdrop_path ? ( 59 | 60 | ) : null} 61 | 62 |
63 | 85 | {props.from === "LikedMovies" ? ( 86 |
removeFromLikedMovies(PopupInfo)} 88 | className="text-white w-10 h-10 border-[2px] rounded-full p-2 mr-1 backdrop-blur-[1px] hover:bg-white hover:text-black shadow-md cursor-pointer ease-linear transition-all duration-150" 89 | > 90 | 97 | 102 | 103 |
104 | ) : ( 105 |
addToLikedMovies(PopupInfo)} 107 | className="text-white w-10 h-10 border-[2px] rounded-full p-2 mr-1 backdrop-blur-[1px] hover:bg-white hover:text-black shadow-md cursor-pointer ease-linear transition-all duration-150" 108 | > 109 | 116 | 121 | 122 |
123 | )} 124 |
125 | 126 | 127 |
128 |

129 | {PopupInfo.title || PopupInfo.name} 130 |

131 |

132 | {PopupInfo.release_date} 133 |

134 |
135 |
136 | {/*body*/} 137 | 138 |
139 |
140 |

141 | {PopupInfo.overview} 142 |

143 |
144 |
145 |
146 | {/*footer*/} 147 |
148 | {/*More Info*/} 149 | 150 |
151 |

152 | Rating : 153 |
154 | {PopupInfo.vote_average && ( 155 | 163 | )} 164 |
165 |

166 |

167 | Released on :{" "} 168 |

169 | {PopupInfo.release_date || PopupInfo.first_air_date} 170 |

171 |

172 |

173 | Language : 174 |

175 | {PopupInfo.original_language} 176 |

177 |

178 | 179 |

180 | Genere : 181 | {PopupInfo.genre_ids && 182 | convertGenere(PopupInfo.genre_ids).map((genere) => { 183 | return ( 184 | 185 | {genere} 186 | 187 | ); 188 | })} 189 |

190 |
191 |
192 | 193 |
194 | {props.from === "MyList" ? ( 195 | 216 | ) : ( 217 | <> 218 | {props.from === "WatchedMovies" ? ( 219 | 240 | ) : ( 241 | 262 | )} 263 | 264 | )} 265 | 266 | 287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 | 295 | )} 296 | 297 | ); 298 | } 299 | 300 | export default MoviePopUp; 301 | -------------------------------------------------------------------------------- /src/Pages/Play.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { useParams, useNavigate, useLocation } from "react-router-dom"; 3 | import StarRatings from "react-star-ratings"; 4 | import axios from "../axios"; 5 | import { API_KEY, imageUrl, imageUrl2 } from "../Constants/Constance"; 6 | 7 | import Navbar from "../componets/Header/Navbar"; 8 | import Footer from "../componets/Footer/Footer"; 9 | import useUpdateMylist from "../CustomHooks/useUpdateMylist"; 10 | import useUpdateLikedMovies from "../CustomHooks/useUpdateLikedMovies"; 11 | 12 | import "swiper/css"; 13 | import "swiper/css/navigation"; 14 | import "swiper/css/pagination"; 15 | import usePlayMovie from "../CustomHooks/usePlayMovie"; 16 | import useUpdateWatchedMovies from "../CustomHooks/useUpdateWatchedMovies"; 17 | 18 | function Play() { 19 | const [urlId, setUrlId] = useState(""); 20 | const [movieDetails, setMovieDetails] = useState({}); 21 | const [isFromMyList, setIsFromMyList] = useState(false); 22 | const [isFromLikedMovies, setIsFromLikedMovies] = useState(false); 23 | const [isFromWatchedMovies, setIsFromWatchedMovies] = useState(false); 24 | const [moreTrailerVideos, setMoreTrailerVideos] = useState([]); 25 | const [similarMovies, setSimilarMovies] = useState([]); 26 | 27 | const { addToMyList, removeFromMyList, PopupMessage } = useUpdateMylist(); 28 | const { addToLikedMovies, removeFromLikedMovies, LikedMoviePopupMessage } = 29 | useUpdateLikedMovies(); 30 | const { removeFromWatchedMovies, removePopupMessage } = 31 | useUpdateWatchedMovies(); 32 | const { playMovie } = usePlayMovie(); 33 | 34 | const { id } = useParams(); 35 | const navigate = useNavigate(); 36 | const location = useLocation(); 37 | 38 | useEffect(() => { 39 | if (location.state.From === "MyList") { 40 | setIsFromMyList(true); 41 | } 42 | if (location.state.From === "LikedMovies") { 43 | setIsFromLikedMovies(true); 44 | } 45 | if (location.state.From === "WatchedMovies") { 46 | setIsFromWatchedMovies(true); 47 | } 48 | 49 | axios 50 | .get(`/movie/${id}/videos?api_key=${API_KEY}&language=en-US`) 51 | .then((responce) => { 52 | console.log(responce.data, "This is the data"); 53 | if (responce.data.results.length !== 0) { 54 | setUrlId(responce.data.results[0]); 55 | setMoreTrailerVideos(responce.data.results); 56 | } else { 57 | console.log("Array Emptey"); 58 | } 59 | }); 60 | 61 | if (urlId === "") { 62 | axios 63 | .get(`/tv/${id}/videos?api_key=${API_KEY}&language=en-US`) 64 | .then((responce) => { 65 | if (responce.data.results.length !== 0) { 66 | console.log(responce.data.results[0], "This is using find "); 67 | setUrlId(responce.data.results[0]); 68 | setMoreTrailerVideos(responce.data.results); 69 | console.log(moreTrailerVideos); 70 | } else { 71 | console.log("Array Emptey"); 72 | } 73 | }); 74 | } 75 | axios 76 | .get(`/movie/${id}?api_key=${API_KEY}&language=en-US`) 77 | .then((responce) => { 78 | console.log(responce.data, "Movie deatils"); 79 | setMovieDetails(responce.data); 80 | console.log(responce.data.genres[0]); 81 | 82 | axios 83 | .get( 84 | `movie/${id}/recommendations?api_key=${API_KEY}&language=en-US&page=1` 85 | ) 86 | .then((res) => { 87 | console.log( 88 | res.data.results.slice(0, 8), 89 | "ksdjfk ahdsfjksadhfjsdahf" 90 | ); 91 | setSimilarMovies(res.data.results.slice(0, 8)); 92 | }); 93 | }); 94 | }, []); 95 | 96 | return ( 97 |
98 | 99 | 100 | {PopupMessage} 101 | 102 |
103 | {urlId ? ( 104 | 112 | ) : ( 113 | 114 | )} 115 |
116 | 117 | {movieDetails.id ? ( 118 | <> 119 | {/* Movie details Section */} 120 |
128 |
129 |

130 | {movieDetails.original_title || movieDetails.title} 131 |

132 | 140 |

{movieDetails.overview}

141 |
142 | 143 |
144 |

145 | Released on :{" "} 146 | 147 | {movieDetails.release_date || movieDetails.air_date} 148 | 149 |

150 |

151 | Language :{" "} 152 | 153 | {movieDetails.original_language} 154 | 155 |

156 |

157 | Geners :{" "} 158 | {movieDetails.genres && 159 | movieDetails.genres.map((gener) => { 160 | return ( 161 | <> 162 | {gener.name} 163 | 164 | ); 165 | })} 166 |

167 |
168 | {isFromMyList ? ( 169 | 189 | ) : isFromWatchedMovies ? ( 190 | 210 | ) : ( 211 | 231 | )} 232 | 233 | {isFromLikedMovies ? ( 234 | 253 | ) : ( 254 | 273 | )} 274 |
275 |
276 |
277 |
278 |
279 |
280 |

281 | Released on :{" "} 282 | 283 | {movieDetails.release_date || movieDetails.air_date} 284 | 285 |

286 |

287 | Language :{" "} 288 | 289 | {movieDetails.original_language} 290 | 291 |

292 |

293 | Geners :{" "} 294 | {movieDetails.genres && 295 | movieDetails.genres.slice(0, 2).map((gener) => { 296 | return ( 297 | <> 298 | 299 | {gener.name} 300 | 301 | 302 | ); 303 | })} 304 |

305 |
306 |
307 | 327 | 347 |
348 |
349 | 1024 355 | ? movieDetails.backdrop_path 356 | ? movieDetails.backdrop_path 357 | : "https://i.ytimg.com/vi/Mwf--eGs05U/maxresdefault.jpg" 358 | : movieDetails.poster_path) 359 | }` 360 | } 361 | className="w-40 rounded-sm lg:w-[45rem] ml-4 lg:ml-0" 362 | alt= 363 | /> 364 |
365 |
366 | 367 | {/* Similar movies section */} 368 | {similarMovies.length !== 0 && ( 369 |
370 |
371 |
372 |

373 | Similar Movies 374 |

375 |
376 | {similarMovies && 377 | similarMovies.map((similarMovie) => { 378 | return ( 379 |
380 | { 389 | playMovie(similarMovie); 390 | window.location.reload(true); 391 | }} 392 | /> 393 |
394 |
395 | {similarMovie.original_title || 396 | similarMovie.title} 397 |
398 |
399 |
400 |
401 |

402 | {Math.floor( 403 | Math.random() * (100 - 60 + 1) + 60 404 | )} 405 | % match 406 |

407 |

408 | {similarMovie.release_date || 409 | (similarMovie.first_air_date && 410 | similarMovie.release_date) || 411 | similarMovie.first_air_date} 412 |

413 |
414 |

415 | HD 416 |

417 |
418 |
419 | addToMyList(similarMovie)} 421 | xmlns="http://www.w3.org/2000/svg" 422 | fill="none" 423 | viewBox="0 0 24 24" 424 | strokeWidth={1.5} 425 | stroke="currentColor" 426 | className="w-9 h-9 cursor-pointer hidden sm:grid" 427 | > 428 | 433 | 434 |
435 |
436 |

437 | {similarMovie.overview} 438 |

439 |
440 |
441 | ); 442 | })} 443 |
444 |
445 |
446 |
447 | )} 448 | 449 | ) : ( 450 | <> 451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 | 459 | )} 460 |
461 |
462 | ); 463 | } 464 | 465 | export default Play; 466 | -------------------------------------------------------------------------------- /src/componets/RowPost/RowPost.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useEffect, useState } from "react"; 3 | 4 | import axios from "../../axios"; 5 | import { imageUrl, imageUrl2, API_KEY } from "../../Constants/Constance"; 6 | import useUpdateMylist from "../../CustomHooks/useUpdateMylist"; 7 | import { Fade } from "react-reveal"; 8 | import YouTube from "react-youtube"; 9 | import StarRatings from "react-star-ratings"; 10 | 11 | import usePlayMovie from "../../CustomHooks/usePlayMovie"; 12 | import useUpdateWatchedMovies from "../../CustomHooks/useUpdateWatchedMovies"; 13 | import useUpdateLikedMovies from "../../CustomHooks/useUpdateLikedMovies"; 14 | import useGenereConverter from "../../CustomHooks/useGenereConverter"; 15 | 16 | import { Swiper, SwiperSlide } from "swiper/react"; 17 | import { Navigation, Pagination } from "swiper"; 18 | 19 | import "swiper/css"; 20 | import "swiper/css/navigation"; 21 | import "swiper/css/pagination"; 22 | import "./RowPostStyles.scss"; 23 | 24 | function RowPost(props) { 25 | const { addToMyList, PopupMessage } = useUpdateMylist(); 26 | const { playMovie } = usePlayMovie(); 27 | const { removeFromWatchedMovies, removePopupMessage } = 28 | useUpdateWatchedMovies(); 29 | const { addToLikedMovies, LikedMoviePopupMessage } = useUpdateLikedMovies(); 30 | const { convertGenere } = useGenereConverter(); 31 | 32 | const [movies, setMovies] = useState([]); 33 | const [showModal, setShowModal] = useState(false); 34 | const [moviePopupInfo, setMoviePopupInfo] = useState({}); 35 | const [shouldPop, setshouldPop] = useState(true); 36 | const [urlId, setUrlId] = useState(""); 37 | 38 | useEffect(() => { 39 | if (props.movieData != null) { 40 | setMovies(props.movieData); 41 | } else { 42 | axios.get(props.url).then((response) => { 43 | console.log(response.data.results); 44 | setMovies(response.data.results); 45 | }); 46 | } 47 | }, []); 48 | 49 | const customSettings = { 50 | breakpoints: { 51 | 1800: { slidesPerView: 6.1, slidesPerGroup: 5 }, 52 | 1690: { slidesPerView: 5.5, slidesPerGroup: 5 }, 53 | 1536: { slidesPerView: 5, slidesPerGroup: 5 }, 54 | 1280: { slidesPerView: 4.3, slidesPerGroup: 4 }, 55 | 768: { slidesPerView: 3.3, slidesPerGroup: 3 }, 56 | 625: { slidesPerView: 3.1, slidesPerGroup: 3 }, 57 | 330: { slidesPerView: 2.1, slidesPerGroup: 2 }, 58 | 0: { slidesPerView: 2, slidesPerGroup: 2 }, 59 | }, 60 | }; 61 | 62 | const opts = { 63 | width: "100%", 64 | height: "auto", 65 | playerVars: { 66 | autoplay: 1, 67 | controls: 0, 68 | }, 69 | modestbranding: 1, 70 | rel: 0, 71 | autohide: 1, 72 | showinfo: 0, 73 | }; 74 | 75 | const handleMoviePopup = (movieInfo) => { 76 | if (shouldPop) { 77 | setMoviePopupInfo(movieInfo); 78 | setShowModal(true); 79 | axios 80 | .get(`/movie/${movieInfo.id}/videos?api_key=${API_KEY}&language=en-US`) 81 | .then((responce) => { 82 | console.log(responce.data); 83 | if (responce.data.results.length !== 0) { 84 | setUrlId(responce.data.results[0]); 85 | } else { 86 | console.log("Array Emptey"); 87 | } 88 | }); 89 | } 90 | }; 91 | 92 | return ( 93 |
97 | {PopupMessage} 98 | {removePopupMessage} 99 | 100 | {movies[0] ? ( 101 | <> 102 |

103 | {props.title} 104 |

105 | 106 | console.log("slide change")} 114 | onSwiper={(swiper) => console.log(swiper)} 115 | className="SwiperStyle" 116 | > 117 | {movies.map((obj, index) => { 118 | const converted = convertGenere(obj.genre_ids); 119 | return ( 120 | handleMoviePopup(obj)} 123 | > 124 | {props.islarge ? ( 125 | <> 126 | 130 | 131 | ) : ( 132 | <> 133 | handleMoviePopup(obj)} 146 | /> 147 | 148 | )} 149 |
150 | 151 |
152 |
playMovie(obj)} 154 | onMouseEnter={() => setshouldPop(false)} 155 | onMouseLeave={() => setshouldPop(true)} 156 | className="text-white w-9 h-9 border-[2px] rounded-full p-2 mr-1 backdrop-blur-[2px] shadow-md ease-linear transition-all duration-150 hover:text-black hover:bg-white" 157 | > 158 | 165 | 170 | 171 |
172 | 173 | {props.movieData != null ? ( 174 | <> 175 |
removeFromWatchedMovies(obj)} 177 | onMouseEnter={() => setshouldPop(false)} 178 | onMouseLeave={() => setshouldPop(true)} 179 | className="text-white w-9 h-9 border-[2px] rounded-full p-2 mr-1 backdrop-blur-[1px] shadow-md ease-linear transition-all duration-150 hover:text-black hover:bg-white" 180 | > 181 | 188 | 193 | 194 |
195 | 196 | ) : ( 197 | <> 198 |
addToMyList(obj)} 200 | onMouseEnter={() => setshouldPop(false)} 201 | onMouseLeave={() => setshouldPop(true)} 202 | className="text-white w-9 h-9 border-[2px] rounded-full p-2 mr-1 backdrop-blur-[1px] shadow-md ease-linear transition-all duration-150 hover:text-black hover:bg-white" 203 | > 204 | 211 | 216 | 217 |
218 | 219 | )} 220 | 221 |
addToLikedMovies(obj)} 223 | onMouseEnter={() => setshouldPop(false)} 224 | onMouseLeave={() => setshouldPop(true)} 225 | className="text-white w-9 h-9 border-[2px] rounded-full p-2 mr-1 backdrop-blur-[1px] shadow-md ease-linear transition-all duration-150 hover:text-black hover:bg-white" 226 | > 227 | 234 | 239 | 240 |
241 | 242 |
handleMoviePopup(obj)} 244 | className="text-white w-9 h-9 border-[2px] rounded-full p-2 mr-1 backdrop-blur-[1px] shadow-md ease-linear transition-all duration-150 hover:text-black hover:bg-white" 245 | > 246 | 254 | 259 | 260 |
261 |
262 | 263 |

264 | {obj.name || obj.title} 265 |

266 | 267 |

268 | {obj.release_date || 269 | (obj.first_air_date && obj.release_date) || 270 | obj.first_air_date} 271 |

272 | 273 |
274 | 282 |
283 | 284 | {converted && 285 | converted.map((genre) => { 286 | return ( 287 | 288 | {genre} 289 | 290 | ); 291 | })} 292 |
293 |
294 |
295 | ); 296 | })} 297 |
298 | 299 | ) : ( 300 | <> 301 |
302 |
303 |
304 |
305 | 306 | )} 307 | 308 | <> 309 | {/* Movie Pop Up section */} 310 | {showModal && ( 311 | <> 312 |
313 |
314 | {/*content*/} 315 | 316 |
317 | {/*header*/} 318 | 337 | {/*Movie Trailer or Image*/} 338 | {urlId ? ( 339 | 344 | ) : ( 345 | 346 | )} 347 | 348 |
349 | 370 |
{ 372 | addToMyList(moviePopupInfo); 373 | }} 374 | className="group text-white w-10 h-10 border-[2px] rounded-full p-2 mr-3 backdrop-blur-[1px] hover:bg-white hover:text-black shadow-md cursor-pointer ease-linear transition-all duration-150 " 375 | > 376 | 383 | 388 | 389 |
390 |
addToLikedMovies(moviePopupInfo)} 392 | className="text-white w-10 h-10 border-[2px] rounded-full p-2 mr-1 backdrop-blur-[1px] hover:bg-white hover:text-black shadow-md cursor-pointer ease-linear transition-all duration-150" 393 | > 394 | 401 | 406 | 407 |
408 |
409 | 410 | 411 |
412 |

413 | {moviePopupInfo.title || moviePopupInfo.name} 414 |

415 |

416 | {moviePopupInfo.release_date} 417 |

418 |
419 |
420 | {/*body*/} 421 | 422 |
423 |
424 |

425 | {moviePopupInfo.overview} 426 |

427 |
428 |
429 |
430 | {/*footer*/} 431 |
432 | {/*More Info*/} 433 | 434 |
435 |

436 | Rating : 437 |
438 | 446 |
447 |

448 |

449 | Released on :{" "} 450 |

451 | {moviePopupInfo.release_date || 452 | moviePopupInfo.first_air_date} 453 |

454 |

455 |

456 | Language : 457 |

458 | {moviePopupInfo.original_language} 459 |

460 |

461 | 462 |

463 | Genere : 464 | {convertGenere(moviePopupInfo.genre_ids).slice(0,2).map( 465 | (genere) => { 466 | return ( 467 | 468 | {genere} 469 | 470 | ); 471 | } 472 | )} 473 |

474 |
475 |
476 | 477 |
478 | 499 | 500 | 521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 | 529 | )} 530 | 531 |
532 | ); 533 | } 534 | 535 | export default RowPost; 536 | --------------------------------------------------------------------------------