├── .eslintignore ├── .eslintrc ├── .gitattributes ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc ├── README.md ├── package.json ├── pnpm-lock.yaml ├── public ├── img │ ├── favicon.ico │ ├── logo192.png │ └── logo512.png ├── index.html ├── manifest.json └── robots.txt └── src ├── App.css ├── App.js ├── components ├── AccountSection │ ├── index.css │ └── index.js ├── FailurePage │ ├── index.css │ └── index.js ├── Footer │ ├── index.css │ └── index.js ├── HomePage │ ├── index.css │ └── index.js ├── LoginPage │ ├── index.css │ └── index.js ├── MovieDetails │ ├── index.css │ └── index.js ├── MovieItems │ ├── index.css │ └── index.js ├── NavBar │ ├── index.css │ └── index.js ├── NotFound │ ├── index.css │ └── index.js ├── PopularSection │ ├── index.css │ └── index.js ├── ProtectedRoute │ └── index.js ├── SearchRoute │ ├── index.css │ └── index.js └── TopRatedMovie │ ├── index.css │ └── index.js ├── index.js └── setupTests.js /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | build 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true 5 | }, 6 | "parser": "babel-eslint", 7 | "extends": ["react-app", "airbnb", "prettier"], 8 | "parserOptions": { 9 | "ecmaFeatures": { 10 | "jsx": true 11 | }, 12 | "ecmaVersion": 12, 13 | "sourceType": "module" 14 | }, 15 | "plugins": ["prettier"], 16 | "overrides": [ 17 | { 18 | "files": ["styledComponents.js"], 19 | "rules": { 20 | "import/prefer-default-export": "off" 21 | } 22 | } 23 | ], 24 | "rules": { 25 | "prettier/prettier": "error", 26 | "react/jsx-filename-extension": [1, {"extensions": [".js", ".jsx"]}], 27 | "react/state-in-constructor": "off", 28 | "react/react-in-jsx-scope": "off", 29 | "react/jsx-uses-react": "off", 30 | "no-console": "off", 31 | "react/prop-types": "off", 32 | "jsx-a11y/label-has-associated-control": [ 33 | 2, 34 | { 35 | "labelAttributes": ["htmlFor"] 36 | } 37 | ], 38 | "jsx-a11y/click-events-have-key-events": 0, 39 | "jsx-a11y/no-noninteractive-element-interactions": [ 40 | "off", 41 | { 42 | "handlers": ["onClick"] 43 | } 44 | ], 45 | "react/prefer-stateless-function": [ 46 | 0, 47 | { 48 | "ignorePureComponents": true 49 | } 50 | ], 51 | "no-unused-vars": "warn", 52 | "jsx-a11y/alt-text": 1, 53 | "react/no-unused-state": "warn", 54 | "react/button-has-type": "warn", 55 | "react/no-unescaped-entities": "warn", 56 | "react/jsx-props-no-spreading": "off", 57 | "operator-assignment": ["warn", "always"], 58 | "radix": "off" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | /node_modules 3 | /.pnp 4 | .pnp.js 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | 23 | .idea/ 24 | .eslintcache 25 | .vscode/ 26 | .results -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmjs.org/ 2 | package-lock=true 3 | save-exact=true 4 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | build 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "bracketSpacing": false, 4 | "endOfLine": "lf", 5 | "htmlWhitespaceSensitivity": "css", 6 | "insertPragma": false, 7 | "jsxBracketSameLine": false, 8 | "jsxSingleQuote": false, 9 | "printWidth": 80, 10 | "overrides": [ 11 | { 12 | "files": "*.md", 13 | "options": { 14 | "printWidth": 1000 15 | } 16 | } 17 | ], 18 | "proseWrap": "always", 19 | "quoteProps": "as-needed", 20 | "requirePragma": false, 21 | "semi": false, 22 | "singleQuote": true, 23 | "tabWidth": 2, 24 | "trailingComma": "all", 25 | "useTabs": false 26 | } 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | In this project let's build a **Movies App** by applying the concepts we have learned till now. This project allows you to practice the concepts and techniques learned till React Course and apply them in a concrete project. 2 | 3 | You will demonstrate your skills by creating an app that will fetch data from an internal server using a class component, displaying that data, using **component lifecycle** methods, **routing** concepts, **authentication**, and **authorization**, and adding responsiveness to the website. 4 | 5 | This is an individual assessment. All work must be your own. 6 | 7 | ### Prerequisites 8 | 9 | #### UI Prerequisites 10 | 11 |
12 | Click to view 13 | 14 | - What is Figma? 15 | - Figma is a vector graphics editor and prototyping tool which is primarily web-based. You can check more info on the Website. 16 | - Create a Free account in Figma 17 | - Kindly follow the instructions as shown in this video to create a Free Figma account. Watch the video upto **00:50**. 18 | - How to Check CSS in Figma? 19 | - Kindly follow the instructions as shown in this video to check CSS in the Figma screen. Watch the video upto **02:45**. 20 | - Export Images in Figma screen 21 | 22 | - Kindly follow the instructions as shown in this video to export images from the Figma screen. 23 | - Click on the Export button to get Export options as shown in the below image. 24 | 25 |
26 | 27 |
28 | 29 | - Upload your exported images from Figma to Cloudinary and get image URLs from Cloudinary. Refer this session for better understanding. 30 | 31 |
32 | 33 | #### Design Files 34 | 35 |
36 | Click to view 37 | 38 | - You can check the **Design Files** for different devices here. 39 | 40 |
41 | 42 | ### Set Up Instructions 43 | 44 |
45 | Click to view 46 | 47 | - Download dependencies by running `npm install` 48 | - Start up the app using `npm start` 49 |
50 | 51 | ### Completion Instructions 52 | 53 |
54 | Functionality to be added 55 |
56 | The app must have the following functionalities 57 | 58 | - **Login Route** 59 | 60 | - When an invalid username and password are provided and the **Login** button is clicked, then the respective error message received from the response should be displayed 61 | - When a valid username and password are provided and the **Login** button is clicked, then the page should be navigated to the Home Route 62 | - When an _unauthenticated_ user tries to access the Home Route, Popular Route, Search Route, Account Route and Movie Item Details Route, then the page should be navigated to Login Route 63 | - When an _authenticated_ user tries to access the Home Route, Popular Route, Search Route, Account Route and Movie Item Details Route, then the page should be navigated to the respective route 64 | - When an _authenticated_ user tries to access the Login Route, then the page should be navigated to the Home Route 65 | 66 | - **Home Route** 67 | 68 | - When an authenticated user opens the Home Route, 69 | 70 | - An HTTP Get request should be made to **Trending Now Movies API URL**, **Originals API URL** with `jwt_token` in the Cookies 71 | 72 | - **_Loader_** should be displayed while fetching the each data 73 | - After the data is successfully fetched from both the API's 74 | - A **random** movie title and movie poster with its details should be displayed from the **Originals Response** 75 | - Display the list of movies received from the Trending Now Movies Response 76 | - Display the list of movies received from the Originals Response 77 | - If any of the HTTP GET request made is unsuccessful, then the failure view given in the **Figma** screens should be displayed respectively 78 | - When the **Try Again** button is clicked, then the respective HTTP GET request should be made 79 | 80 | - When a **Movie** item is clicked, then the page should be navigated to the Movie Item Details Route 81 | 82 | - **Header** 83 | 84 | - When the **Movies** logo in the header is clicked, then the page should be navigated to the Home Route 85 | - When the **Home** link in the Header is clicked, then the page should be navigated to the Home Route 86 | - When the **Popular** link in the header is clicked, then the page should be navigated to the Popular Route 87 | - When the **Search** icon in the header is clicked, then the page should be navigated to the Search Route 88 | - When the **Profile** logo in the header is clicked, then the page should be navigated to the Account Route 89 | 90 | - **Popular Route** 91 | 92 | - When an authenticated user opens the Popular Route 93 | 94 | - An HTTP GET request should be made to **Popular Movies API URL** with `jwt_token` in the Cookies 95 | 96 | - **_Loader_** should be displayed while fetching the data 97 | - After the data is fetched successfully, the response received should be displayed 98 | - If the HTTP GET request made is unsuccessful, then the failure view given in the **Figma** screens should be displayed 99 | - When the **Try Again** button is clicked, an HTTP GET request should be made to **Popular Movies API URL** 100 | 101 | - When a **Movie** item is clicked, then the page should be navigated to the Movie Item Details Route 102 | - All the header functionalities mentioned in the Home Route should work in this route accordingly 103 | 104 | - **Movie Item details Route** 105 | 106 | - When an authenticated user opens the Movie Item Details Route 107 | 108 | - An HTTP GET request should be made to **Movie Item Details API URL** with `jwt_token` in the Cookies 109 | 110 | - **_Loader_** should be displayed while fetching the data 111 | - After the data is fetched successfully, 112 | - Movie item details received from the response should be displayed 113 | - Display the list of similar movies received from the response 114 | - If the HTTP GET request made is unsuccessful, then the failure view given in the **Figma** screens should be displayed 115 | - When the **Try Again** button is clicked, an HTTP GET request should be made to **Movie Item Details API URL** 116 | 117 | - All the header functionalities mentioned in the Home Route should work in this route accordingly 118 | 119 | 120 | - **Search Route** 121 | 122 | - When an authenticated user opens the Search Route 123 | 124 | - When a value is provided in the search input and the button with the search icon is clicked 125 | 126 | - Make an HTTP GET request to the **Search Movies API URL** with `jwt_token` in the Cookies and query parameter `search` with value as the text provided in the search input 127 | - **_Loader_** should be displayed while fetching the data 128 | - After the data is fetched successfully, display the list of movies received from the response 129 | - If the HTTP GET request made is unsuccessful, then the failure view given in the **Figma** screens should be displayed 130 | - When the **Try Again** button is clicked, an HTTP GET request should be made to **Search Movies API URL** 131 | - When the HTTP GET request made to the **Search Movies API URL** returns an empty list for movies then **Search no results** view should be displayed 132 | 133 | - When a **Movie** item is clicked, then the page should be navigated to the Movie Item Details Route 134 | - All the header functionalities mentioned in the Home Route should work in this route accordingly 135 | 136 | - **Account Route** 137 | 138 | - When an authenticated user opens the Account Route 139 | 140 | - The username which was provided in the login, should be displayed 141 | - The password which was provided in the login, should be displayed in masked 142 | - When the **Logout** button is clicked, then the page should be navigated to the Login Route 143 | 144 | - All the header functionalities mentioned in the Home Route should work in this route accordingly 145 | 146 | 147 | - **Not Found Route** 148 | 149 | - When a random path is provided as the URL, then the page should navigate to the Not Found Route 150 | 151 | - Users should be able to view the website responsively in mobile view, tablet view as well 152 | 153 |
154 | 155 | ### Quick Tips 156 | 157 |
158 | Click to view 159 | 160 | - Third party packages to be used to achieve the design or functionality 161 | 162 | - React Slick 163 | 164 | - React Slick Documentation 165 | - React Slick implementation CodeSandbox 166 | - Update the CSS accordingly to style the React Slider and arrow buttons, you can check the CodeSandbox 167 | - Add the below CDN links in your `public > index.html` file for CSS and Font, you can check the CodeSandbox for adding below lines 168 | 169 | ```jsx 170 | 171 | 172 | ``` 173 | 174 | - Use date-fns format function to format the date. Refer to the documentation Link for the usage of format function. 175 | 176 |
177 | 178 | ### Important Note 179 | 180 |
181 | Click to view 182 | 183 |
184 | 185 | **The following instructions are required for the tests to pass** 186 | 187 | - **Note:** 188 | 189 | - Don't use any third-party packages other than packages mentioned in the **Quick Tips** 190 | - Use media queries for responsiveness. Instead of rendering the same elements twice for responsiveness. 191 | - For Mini Projects, You have to use normal HTML elements to style the React Components. Usage of `styled-components` (CSS in JS) to style React components are not supported in Mini Projects. Test cases won't be passed, If you use styled components. 192 | - Refer to the below Example for the usage of `testid` in the HTML elements. 193 | 194 | - Example: `
`. 195 | 196 | - **Routes** 197 | 198 | - Render `Login` Route component when the path in URL matches `/login` 199 | - Render `Home` Route component when the path in URL matches `/` 200 | - Render `Popular` Route component when the path in URL matches `/popular` 201 | - Render `Movie Item Details` Route component when the path in URL matches `/movies/:id` 202 | - Render `Search` Route component when the path in URL matches `/search` 203 | - Render `Account` Route component when the path in URL matches `/account` 204 | 205 | - Wrap the `Loader` component with an HTML container element and add the `testid` attribute value as **loader** to it 206 | 207 | ```jsx 208 |
209 | 210 |
211 | ``` 212 | 213 | - **Login Route** 214 | 215 | - The Movies App Logo image should consist of alt attribute value as `login website logo` 216 | - The Cookies should be set by using the key name `jwt_token` 217 | 218 | - **Home Route** 219 | 220 | - The movie images in the Home Route should have the alt attribute as the value of the key `title` from each object in Trending Now Movies Response, Originals Response 221 | 222 | - **Movie Item Details Route** 223 | 224 | - The movie images in the Movie Item Details Route should have the alt as the value of the key `title` from each object in similarMoviesResponse 225 | - The `runtime` key value received from the movie Item Details response, should be converted from minutes to hours and minutes and displayed in Movie Item Details Route 226 | - The censor rating of the movie in the Movie Item Details Route should be displayed as **A** if the `adult` key value received from the movie Item Details response is true. Otherwise, it should be displayed as U/A 227 | 228 | - **Search Route** 229 | 230 | - When the search results return an empty list, then the No Movies image should consist of alt attribute value as `no movies` 231 | - When the search results return an empty list, then the text content as `Your search for {searchValue} did not find any matches.` should be displayed where searchValue is the value provided in Search Input 232 | - The HTML button element with search icon in the header should have the `testid` attribute value as **searchButton** to it 233 | 234 | - **Not Found Route** 235 | 236 | - The Not Found image should consist of alt attribute value as `not found` 237 | 238 | - **Header** 239 | 240 | - The Movies App Logo image in Header should consist of alt attribute value as `website logo` 241 | - The Profile image in the Header should consist of alt attribute value as `profile` 242 | - The Failure View image should consist of alt attribute value as `failure view` 243 | - `HiOutlineSearch` icon from react-icons should be used for the **Search Icon** button in Header 244 | - The HTML button element with search icon in the header should have the `testid` attribute value as **searchButton** to it 245 | 246 | - **Footer** 247 | 248 | - `FaGoogle` icon from react-icons should be used for the **Google Icon** button in Footer 249 | - `FaTwitter` icon from react-icons should be used for the **Twitter Icon** button in Footer 250 | - `FaInstagram` icon from react-icons should be used for the **Instagram Icon** button in Footer 251 | - `FaYoutube` icon from react-icons should be used for the **Youtube Icon** button in Footer 252 | 253 |
254 | 255 | ### Resources 256 | 257 |
258 | Data fetch URLs 259 | 260 | - **Note:** Use the below sample code snippet to make a POST request on Login using valid username and password. 261 | 262 | ```js 263 | const options = { 264 | method: 'POST', 265 | body: JSON.stringify(userDetails), 266 | } 267 | ``` 268 | 269 | **Login API** 270 | 271 | #### API: `https://apis.ccbp.in/login` 272 | 273 | #### Method: `POST` 274 | 275 | #### Description: 276 | 277 | Returns a response based on the credentials provided 278 | 279 | #### Sample request object: 280 | 281 | ```json 282 | { 283 | "username": "rahul", 284 | "password": "rahul@2021" 285 | } 286 | ``` 287 | 288 | #### Sample Success Response 289 | 290 | ```json 291 | { 292 | "jwt_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InJhaHVsIiwicm9sZSI6IlBSSU1FX1VTRVIiLCJpYXQiOjE2MTk2Mjg2MTN9. nZDlFsnSWArLKKeF0QbmdVfLgzUbx1BGJsqa2kc_21Y" 293 | } 294 | ``` 295 | 296 | #### Sample Failure Response 297 | 298 | ```json 299 | { 300 | "status_code": 404, 301 | "error_msg": "Username is not found" 302 | } 303 | ``` 304 | 305 | **Trending Now Movies API** 306 | 307 | #### API: `https://apis.ccbp.in/movies-app/trending-movies` 308 | 309 | #### Method: `GET` 310 | 311 | #### Description: 312 | 313 | Returns a response containing the list of all movies 314 | 315 | #### Sample Response 316 | 317 | ```json 318 | { 319 | "results": [ 320 | { 321 | "backdrop_path": "https://assets.ccbp.in/frontend/react-js/movies-app/no-time-to-die-movie-background-v0.png", 322 | "id": "92c2cde7-d740-443d-8929-010b46cb0305", 323 | "overview": "Bond has left active service and is enjoying a tranquil life in Jamaica. His peace is short-lived when his old friend Felix Leiter from the CIA turns up asking for help. The mission to rescue a kidnapped scientist turns out to be far more treacherous than expected, leading Bond onto the trail of a mysterious villain armed with dangerous new technology.", 324 | "poster_path": "https://assets.ccbp.in/frontend/react-js/movies-app/no-time-to-die-movie-poster.png", 325 | "title": "No Time to Die" 326 | }, 327 | ... 328 | ], 329 | "total": 10 330 | } 331 | ``` 332 | 333 | **Top Rated Movies API** 334 | 335 | #### API: `https://apis.ccbp.in/movies-app/top-rated-movies` 336 | 337 | #### Method: `GET` 338 | 339 | #### Description: 340 | 341 | Returns a response containing the list of all movies 342 | 343 | #### Sample Response 344 | 345 | ```json 346 | { 347 | "results": [ 348 | { 349 | "backdrop_path": "https://assets.ccbp.in/frontend/react-js/movies-app/ghostbusters-afterlife-british-movie-background-v0.png", 350 | "id": "ef6b65e0-3fbf-4ad7-ae0e-25a478648e69", 351 | "overview": "Ghostbusters: Afterlife is a 2021 American supernatural comedy film directed by Jason Reitman, who co-wrote the screenplay with Gil Kenan.", 352 | "poster_path": "https://assets.ccbp.in/frontend/react-js/movies-app/ghostbusters-afterlife-british-movie-poster.png", 353 | "title": "Ghostbusters: Afterlife" 354 | }, 355 | ... 356 | ], 357 | "total": 10 358 | } 359 | ``` 360 | 361 | **Originals API** 362 | 363 | #### API: `https://apis.ccbp.in/movies-app/originals` 364 | 365 | #### Method: `GET` 366 | 367 | #### Description: 368 | 369 | Returns a response containing the list of all movies 370 | 371 | #### Sample Response 372 | 373 | ```json 374 | { 375 | "results": [ 376 | { 377 | "backdrop_path": "https://assets.ccbp.in/frontend/react-js/movies-app/grindhouse-movie-background-v0.png", 378 | "id": "efb33428-5527-44d0-a713-1aeef4d56968", 379 | "overview": "Austin's hottest DJ, Jungle Julia, sets out into the night to unwind with her two friends Shanna and Arlene. Covertly tracking their moves is Stuntman Mike, a scarred rebel leering from behind the wheel of his muscle car, revving just feet away.", 380 | "poster_path": "https://assets.ccbp.in/frontend/react-js/movies-app/grindhouse-movie-poster.png", 381 | "title": "Death Proof" 382 | }, 383 | ... 384 | ], 385 | "total": 10 386 | } 387 | ``` 388 | 389 | **Popular Movies API** 390 | 391 | #### API: `https://apis.ccbp.in/movies-app/popular-movies` 392 | 393 | #### Method: `GET` 394 | 395 | #### Description: 396 | 397 | Returns a response containing the list of all movies 398 | 399 | #### Sample Response 400 | 401 | ```json 402 | { 403 | "results": [ 404 | { 405 | "backdrop_path": "https://assets.ccbp.in/frontend/react-js/movies-app/venom-movie-background-v0.png", 406 | "id": "320dee56-fdb2-40cf-8df8-92b251bd781f", 407 | "overview": "Investigative journalist Eddie Brock attempts a comeback following a scandal, but accidentally becomes the host of Venom, a violent, super powerful alien symbiote.", 408 | "poster_path": "https://assets.ccbp.in/frontend/react-js/movies-app/venom-movie-poster.png", 409 | "title": "Venom" 410 | }, 411 | ... 412 | ], 413 | "total": 10 414 | } 415 | ``` 416 | 417 | **Movie Item Details API** 418 | 419 | #### API: `https://apis.ccbp.in/movies-app/movies/{movieId}` 420 | 421 | #### Example: `https://apis.ccbp.in/movies-app/movies/92c2cde7-d740-443d-8929-010b46cb0305` 422 | 423 | #### Method: `GET` 424 | 425 | #### Description: 426 | 427 | Returns a response containing the details of the movie 428 | 429 | #### Sample Response 430 | 431 | ```json 432 | { 433 | "movie_details": { 434 | "adult": false, 435 | "backdrop_path": "https://assets.ccbp.in/frontend/react-js/movies-app/venom-let-there-be-carnage-movie-background-v0.png", 436 | "budget": "11 Crores", 437 | "genres": [ 438 | { 439 | "id": "af2384dc-494b-48a7-a94d-91e6b279f20b", 440 | "name": "Science Fiction" 441 | }, 442 | { 443 | "id": "16106068-2d4e-438f-8a9a-fa0b91e4246a", 444 | "name": "Action" 445 | }, 446 | { 447 | "id": "0c29016b-ff7f-4d67-8f95-f8681bc7ff1c", 448 | "name": "Adventure" 449 | } 450 | ], 451 | "id": "51b4602f-b0f2-4c81-98e0-a2a409b13926", 452 | "overview": "Supervillains Harley Quinn, Bloodsport, Peacemaker and a collection of nutty cons at Belle Reve prison join the super-secret, super-shady Task Force X as they are dropped off at the remote, enemy-infused island of Corto Maltese.", 453 | "poster_path": "/rjkmN1dniUHVYAtwuV3Tji7FsDO.jpg", 454 | "release_date": "2021-09-30", 455 | "runtime": 97, 456 | "similar_movies": [ 457 | { 458 | "backdrop_path": "https://assets.ccbp.in/frontend/react-js/movies-app/dune-movie-background-v0.png", 459 | "id": "c6ef2389-078a-4117-b2dd-1dee027e5e8e", 460 | "overview": "Paul Atreides, a brilliant and gifted young man born into a great destiny beyond his understanding, must travel to the most dangerous planet in the universe to ensure the future of his family and his people.", 461 | "poster_path": "https://assets.ccbp.in/frontend/react-js/movies-app/dune-movie-poster.png", 462 | "title": "Dune" 463 | }, 464 | { 465 | "backdrop_path": "https://assets.ccbp.in/frontend/react-js/movies-app/no-time-to-die-movie-background-v0.png", 466 | "id": "92c2cde7-d740-443d-8929-010b46cb0305", 467 | "overview": "Bond has left active service and is enjoying a tranquil life in Jamaica. His peace is short-lived when his old friend Felix Leiter from the CIA turns up asking for help. The mission to rescue a kidnapped scientist turns out to be far more treacherous than expected, leading Bond onto the trail of a mysterious villain armed with dangerous new technology.", 468 | "poster_path": "https://assets.ccbp.in/frontend/react-js/movies-app/no-time-to-die-movie-poster.png", 469 | "title": "No Time to Die" 470 | }, 471 | { 472 | "backdrop_path": "https://assets.ccbp.in/frontend/react-js/movies-app/shang-chi-and-the-legend-of-the-ten-rings-movie-background-v0.png", 473 | "id": "046084e1-a782-4086-b723-f98c5c57ebc0", 474 | "overview": "Shang-Chi must confront the past he thought he left behind when he is drawn into the web of the mysterious Ten Rings organization.", 475 | "poster_path": "https://assets.ccbp.in/frontend/react-js/movies-app/shang-chi-and-the-legend-of-the-ten-rings-movie-poster.png", 476 | "title": "Shang-Chi and the Legend of the Ten Rings" 477 | }, 478 | { 479 | "backdrop_path": "https://assets.ccbp.in/frontend/react-js/movies-app/grindhouse-movie-background-v0.png", 480 | "id": "efb33428-5527-44d0-a713-1aeef4d56968", 481 | "overview": "Austin's hottest DJ, Jungle Julia, sets out into the night to unwind with her two friends Shanna and Arlene. Covertly tracking their moves is Stuntman Mike, a scarred rebel leering from behind the wheel of his muscle car, revving just feet away.", 482 | "poster_path": "https://assets.ccbp.in/frontend/react-js/movies-app/grindhouse-movie-poster.png", 483 | "title": "Death Proof" 484 | } 485 | ], 486 | "spoken_languages": [ 487 | { 488 | "id": "4bc5f2cf-04d6-4064-bd0d-fc927fda507d", 489 | "english_name": "English" 490 | } 491 | ], 492 | "title": "Venom: Let There Be Carnage", 493 | "vote_average": 6.8, 494 | "vote_count": 1514 495 | } 496 | } 497 | ``` 498 | 499 | **Search Movies API** 500 | 501 | #### API: `https://apis.ccbp.in/movies-app/movies-search?search={searchText}` 502 | 503 | #### Example: `https://apis.ccbp.in/movies-app/movies-search?search=Venom` 504 | 505 | #### Method: `GET` 506 | 507 | #### Description: 508 | 509 | Returns a response containing the list of movies and their movie names should includes the given searchText 510 | 511 | #### Sample Response 512 | 513 | ```json 514 | { 515 | "results": [ 516 | { 517 | "backdrop_path": "https://assets.ccbp.in/frontend/react-js/movies-app/venom-let-there-be-carnage-movie-background-v0.png", 518 | "id": "51b4602f-b0f2-4c81-98e0-a2a409b13926", 519 | "overview": "After finding a host body in investigative reporter Eddie Brock, the alien symbiote must face a new enemy, Carnage, the alter ego of serial killer Cletus Kasady.", 520 | "poster_path": "https://assets.ccbp.in/frontend/react-js/movies-app/venom-let-there-be-carnage-movie-poster.png", 521 | "title": "Venom: Let There Be Carnage" 522 | }, 523 | ... 524 | ], 525 | "total": 10 526 | } 527 | ``` 528 | 529 |
530 | 531 | ### User Credentials 532 | 533 |
534 | Click to view user credentials 535 | 536 |
537 | 538 | **You can use any one of the following credentials** 539 | 540 | ```text 541 | username: aakash 542 | password: sky@007 543 | ``` 544 | 545 | ```text 546 | username: agastya 547 | password: myth#789 548 | ``` 549 | 550 | ```text 551 | username: advika 552 | password: world@5 553 | ``` 554 | 555 | ```text 556 | username: binita 557 | password: modest*6 558 | ``` 559 | 560 | ```text 561 | username: chetan 562 | password: vigor$life 563 | ``` 564 | 565 | ```text 566 | username: deepak 567 | password: lightstar@1 568 | ``` 569 | 570 | ```text 571 | username: harshad 572 | password: joy@85 573 | ``` 574 | 575 | ```text 576 | username: kapil 577 | password: moon$008 578 | ``` 579 | 580 | ```text 581 | username: rahul 582 | password: rahul@2021 583 | ``` 584 | 585 | ```text 586 | username: shravya 587 | password: musical#stone 588 | ``` 589 | 590 | ```text 591 | username: saira 592 | password: princess@9 593 | ``` 594 | 595 |
596 |
597 | 598 | ### Stretch Goals 599 | 600 | If you complete the main features of the project you can try out the below features as well. 601 | 602 | **Note:** Just a reminder the additional functionality is just extra practice using the tools we have learned. These are not required. If you do not reach the stretch goals, don't worry. 603 | 604 |
605 | Additional Functionality to be added 606 | 607 | - Home Route 608 | - An HTTP Get request should be made to **Top Rated Movies API URL** as well 609 | - **_Loader_** should be displayed while fetching the data 610 | - After the data is successfully fetched from the API 611 | - Display the list of movies received from the top rated movies response 612 | - If the HTTP GET request made is unsuccessful, then the failure view given in the **Figma** screens should be displayed 613 | - When the **Try Again** button is clicked, then the HTTP GET request should be made to **Top Rated Movies API URL** 614 | - Users can browse popular movies & searched movies using pagination buttons. 615 |
616 | 617 | ### Project Submission Instructions 618 | 619 | - For Mini Projects, you can submit the test cases at your own pace. But we suggest you to submit the code to know the percentage of completion through test cases and that score will be considered for your interviews. 620 | 621 | - Also it's important to publish your code frequently using `Step - 4` in the Instructions tab. 622 | 623 | > ### _Things to Keep in Mind_ 624 | > 625 | > - All components you implement should go in the `src/components` directory. 626 | > - **Do not remove the pre-filled code** 627 | > - Want to quickly review some of the concepts you’ve been learning? Take a look at the Cheat Sheets. 628 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "movies-app", 3 | "private": true, 4 | "version": "1.0.0", 5 | "engines": { 6 | "node": "^10.13 || 12 || 14 || 15", 7 | "npm": ">=6" 8 | }, 9 | "dependencies": { 10 | "@testing-library/jest-dom": "5.11.9", 11 | "@testing-library/react": "11.2.5", 12 | "@testing-library/user-event": "12.6.2", 13 | "@wojtekmaj/enzyme-adapter-react-17": "0.6.5", 14 | "chalk": "4.1.0", 15 | "date-fns": "2.25.0", 16 | "enzyme": "3.11.0", 17 | "history": "5.0.1", 18 | "js-cookie": "3.0.1", 19 | "msw": "0.35.0", 20 | "react": "17.0.1", 21 | "react-dom": "17.0.1", 22 | "react-icons": "4.3.1", 23 | "react-loader-spinner": "4.0.0", 24 | "react-router-dom": "5.3.0", 25 | "react-slick": "0.28.1", 26 | "react-slick-slider": "0.15.10", 27 | "slick-carousel": "1.8.1" 28 | }, 29 | "devDependencies": { 30 | "eslint-config-airbnb": "18.2.1", 31 | "eslint-config-prettier": "8.1.0", 32 | "eslint-plugin-prettier": "3.3.1", 33 | "husky": "4.3.8", 34 | "lint-staged": "10.5.4", 35 | "npm-run-all": "4.1.5", 36 | "prettier": "2.2.1", 37 | "react-scripts": "4.0.3" 38 | }, 39 | "scripts": { 40 | "start": "react-scripts start", 41 | "build": "react-scripts build", 42 | "test": "react-scripts test", 43 | "lint": "eslint .", 44 | "lint:fix": "eslint --fix src/", 45 | "format": "prettier --write \"./src\"", 46 | "run-all": "npm-run-all --parallel test lint:fix" 47 | }, 48 | "lint-staged": { 49 | "*.js": [ 50 | "npm run lint:fix" 51 | ], 52 | "*.{js, jsx, json, html, css}": [ 53 | "npm run format" 54 | ] 55 | }, 56 | "husky": { 57 | "hooks": { 58 | "pre-commit": "lint-staged" 59 | } 60 | }, 61 | "jest": { 62 | "collectCoverageFrom": [ 63 | "src/**/*.js" 64 | ] 65 | }, 66 | "browserslist": { 67 | "development": [ 68 | "last 2 chrome versions", 69 | "last 2 firefox versions", 70 | "last 2 edge versions" 71 | ], 72 | "production": [ 73 | ">1%", 74 | "last 4 versions", 75 | "Firefox ESR", 76 | "not ie < 11" 77 | ] 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /public/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prasanya-web-developer/Netflix-Clone-Mini-Project/0edcf191b995df5fd9802e9cd3d6a15983c84a2e/public/img/favicon.ico -------------------------------------------------------------------------------- /public/img/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prasanya-web-developer/Netflix-Clone-Mini-Project/0edcf191b995df5fd9802e9cd3d6a15983c84a2e/public/img/logo192.png -------------------------------------------------------------------------------- /public/img/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prasanya-web-developer/Netflix-Clone-Mini-Project/0edcf191b995df5fd9802e9cd3d6a15983c84a2e/public/img/logo512.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 16 | 17 | 21 | 22 | 31 | React App 32 | 40 | 41 | 42 |
43 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "app_short_name", 3 | "name": "App_name", 4 | "icons": [ 5 | { 6 | "src": "img/favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "img/logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "img/logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 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/App.js: -------------------------------------------------------------------------------- 1 | import {Switch, Route, Redirect} from 'react-router-dom' 2 | 3 | import LoginPage from './components/LoginPage' 4 | import HomePage from './components/HomePage' 5 | import AccountSection from './components/AccountSection' 6 | import PopularSection from './components/PopularSection' 7 | import SearchRoute from './components/SearchRoute' 8 | import MovieDetails from './components/MovieDetails' 9 | import NotFound from './components/NotFound' 10 | import FailurePage from './components/FailurePage' 11 | 12 | import ProtectedRout from './components/ProtectedRoute' 13 | 14 | import './App.css' 15 | 16 | const App = () => ( 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | ) 29 | 30 | export default App 31 | -------------------------------------------------------------------------------- /src/components/AccountSection/index.css: -------------------------------------------------------------------------------- 1 | .account-section-container { 2 | display: flex; 3 | flex-direction: column; 4 | padding-left: 165px; 5 | padding-top: 67px; 6 | padding-right: 165px; 7 | } 8 | 9 | @media screen and (max-width: 576px) { 10 | .account-section-container { 11 | padding-left: 32px; 12 | padding-right: 32px; 13 | padding-top: 40px; 14 | } 15 | } 16 | 17 | .account-heading { 18 | font-family: 'Roboto'; 19 | font-size: 36px; 20 | font-weight: 700; 21 | line-height: 46.91px; 22 | } 23 | 24 | @media screen and (max-width: 576px) { 25 | .account-heading { 26 | font-size: 24px; 27 | font-weight: 500; 28 | } 29 | } 30 | 31 | .horizontal-line { 32 | width: 100%; 33 | border: 2px solid #cbd5e1; 34 | margin-top: 18px; 35 | margin-bottom: 18px; 36 | } 37 | 38 | @media screen and (max-width: 576px) { 39 | .horizontal-line { 40 | margin-top: 14px; 41 | margin-bottom: 14px; 42 | } 43 | } 44 | 45 | .membership-container { 46 | display: flex; 47 | flex-direction: row; 48 | } 49 | 50 | .name-password-container { 51 | display: flex; 52 | flex-direction: column; 53 | } 54 | 55 | .text { 56 | font-family: 'Roboto'; 57 | font-size: 24px; 58 | font-weight: 600; 59 | line-height: 31px; 60 | color: #94a3b8; 61 | margin-right: 28px; 62 | } 63 | 64 | @media screen and (max-width: 576px) { 65 | .text { 66 | font-size: 18px; 67 | margin-right: 16px; 68 | line-height: 23px; 69 | } 70 | } 71 | 72 | .user-name-text { 73 | font-family: 'Roboto'; 74 | font-size: 20px; 75 | font-weight: 400; 76 | line-height: 31px; 77 | color: #1e293b; 78 | } 79 | 80 | @media screen and (max-width: 576px) { 81 | .user-name-text { 82 | font-size: 16px; 83 | font-weight: 500; 84 | line-height: 20px; 85 | } 86 | } 87 | 88 | .plan-container { 89 | display: flex; 90 | flex-direction: row; 91 | } 92 | 93 | .password-text { 94 | font-family: 'Roboto'; 95 | font-size: 20px; 96 | line-height: 31px; 97 | font-weight: 400; 98 | color: #64748b; 99 | } 100 | 101 | @media screen and (max-width: 576px) { 102 | .password-text { 103 | font-size: 16px; 104 | } 105 | } 106 | 107 | .user-premium { 108 | font-family: 'Roboto'; 109 | font-size: 20px; 110 | font-weight: 400; 111 | line-height: 31px; 112 | color: #1e293b; 113 | margin-left: 18px; 114 | } 115 | 116 | @media screen and (max-width: 576px) { 117 | .user-premium { 118 | font-size: 16px; 119 | font-weight: 500; 120 | } 121 | } 122 | 123 | .hd-text { 124 | border: 1px solid #1e293b; 125 | border-radius: 2px; 126 | width: 70px; 127 | height: 27px; 128 | font-family: 'Roboto'; 129 | font-size: 14px; 130 | color: #1e293b; 131 | text-align: center; 132 | margin-top: 5px; 133 | font-weight: 400; 134 | padding-top: 4px; 135 | margin-left: 16px; 136 | } 137 | 138 | .logout-button { 139 | font-family: 'Roboto'; 140 | font-size: 14px; 141 | border: none; 142 | outline: none; 143 | cursor: pointer; 144 | background-color: #e50914; 145 | padding: 8px, 20px, 8px, 20px; 146 | border-radius: 4px; 147 | align-self: center; 148 | height: 40px; 149 | width: 89px; 150 | margin-top: 50px; 151 | color: #ffffff; 152 | margin-bottom: 90px; 153 | } 154 | 155 | @media screen and (max-width: 567px) { 156 | .logout-button { 157 | margin-bottom: 90px; 158 | margin-top: 70px; 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/components/AccountSection/index.js: -------------------------------------------------------------------------------- 1 | import Cookies from 'js-cookie' 2 | import NavBar from '../NavBar' 3 | import Footer from '../Footer' 4 | 5 | import './index.css' 6 | 7 | const isAccount = true 8 | 9 | const AccountSection = props => { 10 | const onClickLogout = () => { 11 | Cookies.remove('jwt_token') 12 | const {history} = props 13 | history.replace('/login') 14 | } 15 | 16 | return ( 17 | <> 18 | 19 |
20 |

Account

21 |
22 |
23 |

Member ship

24 |
25 |

saira@gmail.com

26 |

27 | Password : ********** 28 |

29 |
30 |
31 |
32 |
33 |

Plan details

34 |

Premium

35 |

Ultra HD

36 |
37 |
38 | 41 |
42 |