├── .env.example ├── .eslintrc.js ├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── index.html ├── logo.png ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt └── src ├── app └── store.js ├── assets ├── genres │ ├── action.png │ ├── adventure.png │ ├── animation.png │ ├── comedy.png │ ├── crime.png │ ├── documentary.png │ ├── drama.png │ ├── family.png │ ├── fantasy.png │ ├── history.png │ ├── horror.png │ ├── index.js │ ├── music.png │ ├── mystery.png │ ├── popular.png │ ├── romance.png │ ├── science fiction.png │ ├── thriller.png │ ├── top rated.png │ ├── tv movie.png │ ├── upcoming.png │ ├── war.png │ └── western.png └── images │ ├── Filmpire.jpg │ ├── cinema.png │ ├── cinemas.svg │ ├── darkmode.png │ ├── infodark.png │ ├── infolight.png │ ├── lightmode.png │ ├── movieNight.svg │ ├── moviesflix.png │ └── nightmode.svg ├── components ├── Actors │ ├── Actors.jsx │ └── styles.js ├── Alan.jsx ├── App.jsx ├── FeaturedMovie │ ├── FeaturedMovie.jsx │ └── styles.js ├── Movie │ ├── Movie.jsx │ └── styles.js ├── MovieInfo │ ├── MovieInfo.jsx │ └── styles.js ├── MovieList │ ├── MovieList.jsx │ └── styles.js ├── Movies │ └── Movies.jsx ├── Navbar │ ├── Navbar.jsx │ └── styles.js ├── Pagination │ ├── Pagination.jsx │ └── styles.js ├── Profile │ └── Profile.jsx ├── RatedCards │ ├── RatedCards.jsx │ └── styles.js ├── Search │ ├── Search.jsx │ └── styles.js ├── Sidebar │ ├── Sidebar.jsx │ └── styles.js ├── index.js └── styles.js ├── features ├── auth.js └── currentGenreOrCategory.js ├── index.css ├── index.js ├── services └── TMDB.js └── utils ├── ToggleColorMode.jsx └── index.js /.env.example: -------------------------------------------------------------------------------- 1 | ESLINT_NO_DEV_ERRORS = true 2 | REACT_APP_TMDB_KEY 3 | REACT_APP_ALAN_SDK_KEY -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es2021: true, 5 | }, 6 | extends: [ 7 | 'plugin:react/recommended', 8 | 'airbnb', 9 | ], 10 | parserOptions: { 11 | ecmaFeatures: { 12 | jsx: true, 13 | }, 14 | ecmaVersion: 'latest', 15 | sourceType: 'module', 16 | }, 17 | plugins: [ 18 | 'react', 19 | ], 20 | rules: { 21 | 'import/extensions': 0, 22 | 'react/prop-types': 0, 23 | 'linebreak-style': 0, 24 | 'react/state-in-constructor': 0, 25 | 'import/prefer-default-export': 0, 26 | 'max-len': [2, 250], 27 | 'no-multiple-empty-lines': ['error', { max: 1, maxEOF: 1 }], 28 | 'no-underscore-dangle': ['error', { allow: ['_d', '_dh', '_h', '_id', '_m', '_n', '_t', '_text'] }], 29 | 'object-curly-newline': 0, 30 | 'react/jsx-filename-extension': 0, 31 | 'react/jsx-one-expression-per-line': 0, 32 | 'jsx-a11y/click-events-have-key-events': 0, 33 | 'jsx-a11y/alt-text': 0, 34 | 'jsx-a11y/no-autofocus': 0, 35 | 'jsx-a11y/no-static-element-interactions': 0, 36 | 'react/no-array-index-key': 0, 37 | 'no-param-reassign': 0, 38 | 'react/react-in-jsx-scope': 0, 39 | 'jsx-a11y/anchor-is-valid': ['error', { components: ['Link'], specialLink: ['to', 'hrefLeft', 'hrefRight'], aspects: ['noHref', 'invalidHref', 'preferButton'] }], 40 | }, 41 | }; 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | .env 3 | build 4 | .env.production -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Filmpire 2 | 3 | ![App Screenshot](src/assets/images/Filmpire.jpg) 4 | 5 | Filmpire combines the desire to unleash powerful creativity with the industry's most advanced JavaScript tools including React.js, Redux, Material UI, Alan AI, and more. 6 | 7 | This application includes user authentication, dark mode, sort movie on the basis of categories or genres, viewing movie and actor details, adding a movie to favorites or watchlist and many more functionalities. 8 | 9 | Alan works as in-app voice assistant which create conversational experiences for filmpire. 10 | 11 | # Getting Started with Create React App 12 | 13 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 14 | 15 | ## Available Scripts 16 | 17 | In the project directory, you can run: 18 | 19 | ### `npm start` 20 | 21 | Runs the app in the development mode.\ 22 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser. 23 | 24 | The page will reload when you make changes.\ 25 | You may also see any lint errors in the console. 26 | 27 | ### `npm test` 28 | 29 | Launches the test runner in the interactive watch mode.\ 30 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 31 | 32 | ### `npm run build` 33 | 34 | Builds the app for production to the `build` folder.\ 35 | It correctly bundles React in production mode and optimizes the build for the best performance. 36 | 37 | The build is minified and the filenames include the hashes.\ 38 | Your app is ready to be deployed! 39 | 40 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 41 | 42 | ### `npm run eject` 43 | 44 | **Note: this is a one-way operation. Once you `eject`, you can't go back!** 45 | 46 | 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. 47 | 48 | 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. 49 | 50 | 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. 51 | 52 | ## Learn More 53 | 54 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 55 | 56 | To learn React, check out the [React documentation](https://reactjs.org/). 57 | 58 | ### Code Splitting 59 | 60 | 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) 61 | 62 | ### Analyzing the Bundle Size 63 | 64 | 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) 65 | 66 | ### Making a Progressive Web App 67 | 68 | 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) 69 | 70 | ### Advanced Configuration 71 | 72 | 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) 73 | 74 | ### Deployment 75 | 76 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 77 | 78 | ### `npm run build` fails to minify 79 | 80 | 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) 81 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "filmpire", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@alan-ai/alan-sdk-web": "^1.8.33", 7 | "@emotion/react": "^11.9.0", 8 | "@emotion/styled": "^11.8.1", 9 | "@mui/icons-material": "^5.8.2", 10 | "@mui/material": "^5.8.2", 11 | "@mui/styles": "^5.8.0", 12 | "@reduxjs/toolkit": "^1.8.2", 13 | "@testing-library/jest-dom": "^5.16.4", 14 | "@testing-library/react": "^13.3.0", 15 | "@testing-library/user-event": "^13.5.0", 16 | "axios": "^0.27.2", 17 | "react": "^18.1.0", 18 | "react-dom": "^18.1.0", 19 | "react-redux": "^8.0.2", 20 | "react-router-dom": "^6.3.0", 21 | "react-scripts": "5.0.1", 22 | "web-vitals": "^2.1.4" 23 | }, 24 | "scripts": { 25 | "start": "react-scripts start", 26 | "build": "react-scripts build", 27 | "test": "react-scripts test", 28 | "eject": "react-scripts eject" 29 | }, 30 | "eslintConfig": { 31 | "extends": [ 32 | "react-app", 33 | "react-app/jest" 34 | ] 35 | }, 36 | "browserslist": { 37 | "production": [ 38 | ">0.2%", 39 | "not dead", 40 | "not op_mini all" 41 | ], 42 | "development": [ 43 | "last 1 chrome version", 44 | "last 1 firefox version", 45 | "last 1 safari version" 46 | ] 47 | }, 48 | "devDependencies": { 49 | "eslint": "^8.17.0", 50 | "eslint-config-airbnb": "^19.0.4", 51 | "eslint-plugin-import": "^2.26.0", 52 | "eslint-plugin-jsx-a11y": "^6.5.1", 53 | "eslint-plugin-react": "^7.30.0", 54 | "eslint-plugin-react-hooks": "^4.5.0" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Filmpire 13 | 14 | 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/public/logo.png -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/public/logo512.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/app/store.js: -------------------------------------------------------------------------------- 1 | import { configureStore } from '@reduxjs/toolkit'; 2 | import { tmdbApi } from '../services/TMDB'; 3 | import genreOrCategoryReducer from '../features/currentGenreOrCategory'; 4 | import userReducer from '../features/auth'; 5 | 6 | export default configureStore({ 7 | reducer: { 8 | [tmdbApi.reducerPath]: tmdbApi.reducer, 9 | currentGenreOrCategory: genreOrCategoryReducer, 10 | user: userReducer, 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /src/assets/genres/action.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/genres/action.png -------------------------------------------------------------------------------- /src/assets/genres/adventure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/genres/adventure.png -------------------------------------------------------------------------------- /src/assets/genres/animation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/genres/animation.png -------------------------------------------------------------------------------- /src/assets/genres/comedy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/genres/comedy.png -------------------------------------------------------------------------------- /src/assets/genres/crime.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/genres/crime.png -------------------------------------------------------------------------------- /src/assets/genres/documentary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/genres/documentary.png -------------------------------------------------------------------------------- /src/assets/genres/drama.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/genres/drama.png -------------------------------------------------------------------------------- /src/assets/genres/family.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/genres/family.png -------------------------------------------------------------------------------- /src/assets/genres/fantasy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/genres/fantasy.png -------------------------------------------------------------------------------- /src/assets/genres/history.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/genres/history.png -------------------------------------------------------------------------------- /src/assets/genres/horror.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/genres/horror.png -------------------------------------------------------------------------------- /src/assets/genres/index.js: -------------------------------------------------------------------------------- 1 | import action from './action.png'; 2 | import adventure from './adventure.png'; 3 | import animation from './animation.png'; 4 | import comedy from './comedy.png'; 5 | import crime from './crime.png'; 6 | import documentary from './documentary.png'; 7 | import drama from './drama.png'; 8 | import family from './family.png'; 9 | import fantasy from './fantasy.png'; 10 | import horror from './horror.png'; 11 | import history from './history.png'; 12 | import mystery from './mystery.png'; 13 | import music from './music.png'; 14 | import romance from './romance.png'; 15 | import scienceFiction from './science fiction.png'; 16 | import thriller from './thriller.png'; 17 | import tvMovie from './tv movie.png'; 18 | import war from './war.png'; 19 | import western from './western.png'; 20 | 21 | import popular from './popular.png'; 22 | import topRated from './top rated.png'; 23 | import upcoming from './upcoming.png'; 24 | 25 | export default { 26 | action, 27 | adventure, 28 | animation, 29 | comedy, 30 | crime, 31 | documentary, 32 | drama, 33 | family, 34 | fantasy, 35 | horror, 36 | history, 37 | mystery, 38 | music, 39 | romance, 40 | 'science fiction': scienceFiction, 41 | thriller, 42 | 'tv movie': tvMovie, 43 | war, 44 | western, 45 | popular, 46 | 'top rated': topRated, 47 | upcoming, 48 | }; 49 | -------------------------------------------------------------------------------- /src/assets/genres/music.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/genres/music.png -------------------------------------------------------------------------------- /src/assets/genres/mystery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/genres/mystery.png -------------------------------------------------------------------------------- /src/assets/genres/popular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/genres/popular.png -------------------------------------------------------------------------------- /src/assets/genres/romance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/genres/romance.png -------------------------------------------------------------------------------- /src/assets/genres/science fiction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/genres/science fiction.png -------------------------------------------------------------------------------- /src/assets/genres/thriller.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/genres/thriller.png -------------------------------------------------------------------------------- /src/assets/genres/top rated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/genres/top rated.png -------------------------------------------------------------------------------- /src/assets/genres/tv movie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/genres/tv movie.png -------------------------------------------------------------------------------- /src/assets/genres/upcoming.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/genres/upcoming.png -------------------------------------------------------------------------------- /src/assets/genres/war.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/genres/war.png -------------------------------------------------------------------------------- /src/assets/genres/western.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/genres/western.png -------------------------------------------------------------------------------- /src/assets/images/Filmpire.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/images/Filmpire.jpg -------------------------------------------------------------------------------- /src/assets/images/cinema.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/images/cinema.png -------------------------------------------------------------------------------- /src/assets/images/cinemas.svg: -------------------------------------------------------------------------------- 1 | home_cinema -------------------------------------------------------------------------------- /src/assets/images/darkmode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/images/darkmode.png -------------------------------------------------------------------------------- /src/assets/images/infodark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/images/infodark.png -------------------------------------------------------------------------------- /src/assets/images/infolight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/images/infolight.png -------------------------------------------------------------------------------- /src/assets/images/lightmode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/images/lightmode.png -------------------------------------------------------------------------------- /src/assets/images/movieNight.svg: -------------------------------------------------------------------------------- 1 | movie_night -------------------------------------------------------------------------------- /src/assets/images/moviesflix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderGhost37/Filmpire/bbf76e6da89961d3e6a71a32b88bdee2964a7e5f/src/assets/images/moviesflix.png -------------------------------------------------------------------------------- /src/assets/images/nightmode.svg: -------------------------------------------------------------------------------- 1 | home_cinema -------------------------------------------------------------------------------- /src/components/Actors/Actors.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { Box, Button, CircularProgress, Grid, Typography } from '@mui/material'; 3 | import { useNavigate, useParams } from 'react-router-dom'; 4 | import { ArrowBack } from '@mui/icons-material'; 5 | 6 | import useStyles from './styles'; 7 | import { useGetActorQuery, useGetMoviesByActorIdQuery } from '../../services/TMDB'; 8 | import { MovieList, Pagination } from '../index'; 9 | 10 | function Actors() { 11 | const classes = useStyles(); 12 | const [page, setPage] = useState(1); 13 | const navigate = useNavigate(); 14 | const { id } = useParams(); 15 | const { data, isFetching, error } = useGetActorQuery(id); 16 | const { data: movies } = useGetMoviesByActorIdQuery({ id, page }); 17 | 18 | if (isFetching) { 19 | return ( 20 | 21 | 22 | 23 | ); 24 | } 25 | 26 | if (error) { 27 | return ( 28 | 29 | 32 | 33 | ); 34 | } 35 | 36 | return ( 37 | <> 38 | 39 | 40 | {data.name} 45 | 46 | 47 | {data?.name} 48 | Born: {new Date(data?.birthday).toDateString()} 49 | {data?.biography || 'Sorry, no biography yet...'} 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | Movies 58 | {movies && } 59 | 60 | 61 | 62 | ); 63 | } 64 | 65 | export default Actors; 66 | -------------------------------------------------------------------------------- /src/components/Actors/styles.js: -------------------------------------------------------------------------------- 1 | import { makeStyles } from '@mui/styles'; 2 | 3 | export default makeStyles(() => ({ 4 | image: { 5 | maxWidth: '90%', 6 | borderRadius: '20px', 7 | objectFit: 'cover', 8 | boxShadow: '0.5em 0.5em 1em', 9 | }, 10 | btns: { 11 | marginTop: '2rem', 12 | display: 'flex', 13 | justifyContent: 'space-around', 14 | }, 15 | })); 16 | -------------------------------------------------------------------------------- /src/components/Alan.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useContext } from 'react'; 2 | import alanBtn from '@alan-ai/alan-sdk-web'; 3 | import { useDispatch } from 'react-redux'; 4 | import { useNavigate } from 'react-router-dom'; 5 | 6 | import { ColorModeContext } from '../utils/ToggleColorMode'; 7 | import { fetchToken } from '../utils/index'; 8 | import { selectGenreOrCategory, searchMovie } from '../features/currentGenreOrCategory'; 9 | 10 | function useAlan() { 11 | const { setMode } = useContext(ColorModeContext); 12 | const dispatch = useDispatch(); 13 | const navigate = useNavigate(); 14 | 15 | useEffect(() => { 16 | alanBtn({ 17 | key: process.env.REACT_APP_ALAN_SDK_KEY, 18 | onCommand: ({ command, mode, genres, genreOrCategory, query }) => { 19 | if (command === 'chooseGenre') { 20 | const foundGenre = genres.find((g) => g.name.toLowerCase() === genreOrCategory.toLowerCase()); 21 | if (foundGenre) { 22 | navigate('/'); 23 | dispatch(selectGenreOrCategory(foundGenre.id)); 24 | } else { 25 | const category = genreOrCategory.startsWith('top') ? 'top_rated' : genreOrCategory; 26 | navigate('/'); 27 | dispatch(selectGenreOrCategory(category)); 28 | } 29 | } else if (command === 'changeMode') { 30 | if (mode === 'light') { 31 | setMode('light'); 32 | } else { 33 | setMode('dark'); 34 | } 35 | } else if (command === 'login') { 36 | fetchToken(); 37 | } else if (command === 'logout') { 38 | localStorage.clear(); 39 | navigate('/'); 40 | } else if (command === 'search') { 41 | dispatch(searchMovie(query)); 42 | } 43 | }, 44 | }); 45 | }, []); 46 | } 47 | 48 | export default useAlan; 49 | -------------------------------------------------------------------------------- /src/components/App.jsx: -------------------------------------------------------------------------------- 1 | import React, { useRef } from 'react'; 2 | import { CssBaseline } from '@mui/material'; 3 | import { Routes, Route } from 'react-router-dom'; 4 | 5 | import useStyles from './styles'; 6 | import useAlan from './Alan'; 7 | 8 | import { Movies, Actors, MovieInfo, Navbar, Profile } from './index'; 9 | 10 | function App() { 11 | const classes = useStyles(); 12 | const alanBtnContainer = useRef(); 13 | 14 | useAlan(); 15 | 16 | return ( 17 |
18 | 19 | 20 |
21 |
22 | 23 | } /> 24 | } /> 25 | } /> 26 | } /> 27 | } /> 28 | 29 |
30 |
31 |
32 | ); 33 | } 34 | 35 | export default App; 36 | -------------------------------------------------------------------------------- /src/components/FeaturedMovie/FeaturedMovie.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Box, Typography, Card, CardContent, CardMedia } from '@mui/material'; 3 | import { Link } from 'react-router-dom'; 4 | 5 | import useStyles from './styles'; 6 | 7 | function FeaturedMovie({ movie }) { 8 | const classes = useStyles(); 9 | 10 | if (!movie) return null; 11 | 12 | return ( 13 | 14 | 15 | 22 | 23 | 24 | {movie.title} 25 | {movie.overview} 26 | 27 | 28 | 29 | 30 | ); 31 | } 32 | 33 | export default FeaturedMovie; 34 | -------------------------------------------------------------------------------- /src/components/FeaturedMovie/styles.js: -------------------------------------------------------------------------------- 1 | import { makeStyles } from '@mui/styles'; 2 | 3 | export default makeStyles((theme) => ({ 4 | featuredCardContainer: { 5 | marginBottom: '20px', 6 | display: 'flex', 7 | justifyContent: 'center', 8 | height: '490px', 9 | textDecoration: 'none', 10 | }, 11 | card: { 12 | width: '100%', 13 | display: 'flex', 14 | justifyContent: 'flex-end', 15 | flexDirection: 'column', 16 | }, 17 | cardRoot: { 18 | position: 'relative', 19 | }, 20 | cardMedia: { 21 | position: 'absolute', 22 | top: 0, 23 | right: 0, 24 | height: '100%', 25 | width: '100%', 26 | backgroundColor: 'rgba(0,0,0,0.575)', 27 | backgroundBlendMode: 'darken', 28 | }, 29 | cardContent: { 30 | color: '#fff', 31 | width: '40%', 32 | [theme.breakpoints.down('sm')]: { 33 | width: '100%', 34 | }, 35 | }, 36 | cardContentRoot: { 37 | position: 'relative', 38 | backgroundColor: 'transparent', 39 | }, 40 | })); 41 | -------------------------------------------------------------------------------- /src/components/Movie/Movie.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Typography, Grid, Grow, Tooltip, Rating } from '@mui/material'; 3 | import { Link } from 'react-router-dom'; 4 | 5 | import useStyles from './styles'; 6 | 7 | function Movie({ movie, i }) { 8 | const classes = useStyles(); 9 | 10 | return ( 11 | 12 | 13 | 14 | {movie.title} 19 | {movie.title} 20 | 21 |
22 | 23 |
24 |
25 | 26 |
27 |
28 | ); 29 | } 30 | 31 | export default Movie; 32 | -------------------------------------------------------------------------------- /src/components/Movie/styles.js: -------------------------------------------------------------------------------- 1 | import { makeStyles } from '@mui/styles'; 2 | 3 | export default makeStyles((theme) => ({ 4 | movie: { 5 | padding: '10px', 6 | }, 7 | title: { 8 | color: theme.palette.text.primary, 9 | textOverflow: 'ellipsis', 10 | width: '230px', 11 | overflow: 'hidden', 12 | whiteSpace: 'nowrap', 13 | marginTop: '10px', 14 | marginBottom: 0, 15 | textAlign: 'center', 16 | }, 17 | links: { 18 | alignItems: 'center', 19 | fontWeight: 'bolder', 20 | textDecoration: 'none', 21 | [theme.breakpoints.up('xs')]: { 22 | display: 'flex', 23 | flexDirection: 'column', 24 | }, 25 | '&:hover': { 26 | cursor: 'pointer', 27 | }, 28 | }, 29 | image: { 30 | borderRadius: '20px', 31 | height: '300px', 32 | marginBottom: '10px', 33 | '&:hover': { 34 | transform: 'scale(1.05)', 35 | }, 36 | }, 37 | })); 38 | -------------------------------------------------------------------------------- /src/components/MovieInfo/MovieInfo.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { Modal, Typography, Button, ButtonGroup, Grid, Box, CircularProgress, Rating } from '@mui/material'; 3 | import { Movie as MovieIcon, Theaters, Language, PlusOne, Favorite, FavoriteBorderOutlined, Remove, ArrowBack } from '@mui/icons-material'; 4 | import { Link, useParams } from 'react-router-dom'; 5 | import { useDispatch, useSelector } from 'react-redux'; 6 | import axios from 'axios'; 7 | 8 | import useStyles from './styles'; 9 | import { MovieList } from '../index'; 10 | import { useGetMovieQuery, useGetRecommendationsQuery, useGetListQuery } from '../../services/TMDB'; 11 | import { selectGenreOrCategory } from '../../features/currentGenreOrCategory'; 12 | import genreIcons from '../../assets/genres'; 13 | 14 | function MovieInfo() { 15 | const classes = useStyles(); 16 | const dispatch = useDispatch(); 17 | const { user } = useSelector((state) => state.user); 18 | const { id } = useParams(); 19 | 20 | const { data, error, isFetching } = useGetMovieQuery(id); 21 | const { data: favoriteMovies } = useGetListQuery({ listName: 'favorite/movies', accountId: user.id, sessionId: localStorage.getItem('session_id'), page: 1 }); 22 | const { data: watchlistMovies } = useGetListQuery({ listName: 'watchlist/movies', accountId: user.id, sessionId: localStorage.getItem('session_id'), page: 1 }); 23 | const { data: recommendations } = useGetRecommendationsQuery({ list: '/recommendations', movie_id: id }); 24 | 25 | const [open, setOpen] = useState(false); 26 | const [isMovieFavorited, setIsMovieFavorited] = useState(false); 27 | const [isMovieWatchlisted, setIsMovieWatchlisted] = useState(false); 28 | 29 | useEffect(() => { 30 | setIsMovieFavorited(!!favoriteMovies?.results?.find((movie) => movie?.id === data?.id)); 31 | }, [favoriteMovies, data]); 32 | useEffect(() => { 33 | setIsMovieWatchlisted(!!watchlistMovies?.results?.find((movie) => movie?.id === data?.id)); 34 | }, [watchlistMovies, data]); 35 | 36 | const addToFavorites = async () => { 37 | await axios.post(`https://api.themoviedb.org/3/account/${user.id}/favorite?api_key=${process.env.REACT_APP_TMDB_KEY}&session_id=${localStorage.getItem('session_id')}`, { 38 | media_type: 'movie', 39 | media_id: id, 40 | favorite: !isMovieFavorited, 41 | }); 42 | 43 | setIsMovieFavorited((prev) => !prev); 44 | }; 45 | 46 | const addToWatchList = async () => { 47 | await axios.post(`https://api.themoviedb.org/3/account/${user.id}/watchlist?api_key=${process.env.REACT_APP_TMDB_KEY}&session_id=${localStorage.getItem('session_id')}`, { 48 | media_type: 'movie', 49 | media_id: id, 50 | watchlist: !isMovieWatchlisted, 51 | }); 52 | 53 | setIsMovieWatchlisted((prev) => !prev); 54 | }; 55 | 56 | if (isFetching) { 57 | return ( 58 | 59 | 60 | 61 | ); 62 | } 63 | 64 | if (error) { 65 | return ( 66 | 67 | Something went wrong - Go back. 68 | 69 | ); 70 | } 71 | 72 | return ( 73 | 74 | 75 | {data?.title} 80 | 81 | 82 | 83 | {data?.title} ({data.release_date.split('-')[0]}) 84 | 85 | 86 | {data?.tagline} 87 | 88 | 89 | 90 | 91 | 92 | {data?.vote_average} / 10 93 | 94 | 95 | {data?.runtime}min 96 | 97 | 98 | {data?.genres?.map((genre) => ( 99 | dispatch(selectGenreOrCategory(genre.id))}> 100 | 101 | {genre?.name} 102 | 103 | ))} 104 | 105 | Overview 106 | {data?.overview} 107 | Top Cast 108 | 109 | {data && data?.credits?.cast?.map((character, i) => ( 110 | character.profile_path && ( 111 | 112 | {character.name} 117 | {character?.name} 118 | 119 | {character.character.split('/')[0]} 120 | 121 | 122 | ) 123 | )).slice(0, 6)} 124 | 125 | 126 |
127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 139 | 142 | 147 | 148 | 149 |
150 |
151 |
152 | 153 | 154 | You might also like 155 | 156 | {recommendations 157 | ? 158 | : Sorry, nothing was found.} 159 | 160 | setOpen(false)} 165 | > 166 | {data?.videos?.results?.length > 0 && ( 167 |