├── .gitignore ├── README.md ├── cypress.json ├── cypress ├── integration │ ├── browse-home.spec.js │ ├── browse-navbar.spec.js │ ├── landing-section.spec.js │ ├── login-form.spec.js │ └── sign-in-flow.spec.js ├── plugins │ └── index.js └── support │ ├── commands.js │ └── index.js ├── flixdemo.gif ├── jsconfig.json ├── package-lock.json ├── package.json ├── public ├── 404.html ├── index.html └── manifest.json └── src ├── App.js ├── assets └── images │ ├── howl.png │ ├── index.js │ ├── landingPage.jpg │ ├── netflix.png │ ├── normal.jpg │ ├── profile.jpg │ ├── smile.png │ └── weird.png ├── baseAxios.js ├── components ├── Modals │ ├── ProfileModal │ │ ├── ProfileModal.css │ │ └── ProfileModal.js │ └── VideoModal │ │ ├── VideoModal.css │ │ └── VideoModal.js ├── Navigation │ └── Dropdown │ │ ├── Dropdown.css │ │ └── Dropdown.js ├── StaticPages │ ├── ErrorPage │ │ ├── ErrorPage.css │ │ └── ErrorPage.js │ ├── LoadingScreen │ │ ├── LoadingScreen.css │ │ └── LoadingScreen.js │ └── NotFoundPage │ │ ├── NotFoundPage.css │ │ └── NotFoundPage.js ├── UI │ ├── Button │ │ ├── Button.css │ │ └── Button.js │ ├── CircularSoundButton │ │ ├── CircularSoundButton.css │ │ └── CircularSoundButton.js │ ├── DarkComponent │ │ └── DarkComponent.js │ ├── FAQComponent │ │ ├── FAQComponent.css │ │ └── FAQComponent.js │ └── ProfileCard │ │ ├── ProfileCard.css │ │ └── ProfileCard.js └── Video │ ├── TopTrailerComponent │ ├── TopTrailerComponent.css │ └── TopTrailerComponent.js │ ├── VideoCard │ ├── VideoCard.css │ └── VideoCard.js │ └── VideoCarousel │ ├── VideoCarousel.css │ └── VideoCarousel.js ├── containers ├── Browse │ ├── Browse.js │ ├── BrowseContent │ │ ├── BrowseContent.css │ │ └── BrowseContent.js │ ├── SearchContent │ │ ├── SearchContent.css │ │ └── SearchContent.js │ └── routes │ │ ├── Home.js │ │ ├── LatestVideo.js │ │ ├── List.js │ │ ├── Movies.js │ │ ├── Tv.js │ │ └── index.js ├── LandingSection │ ├── LandingSection.css │ ├── LandingSection.js │ └── LandingSectionTexts.js ├── Login │ ├── Login.css │ └── Login.js ├── NavBar │ ├── NavBar.css │ └── NavBar.js └── Search │ ├── Search.css │ └── Search.js ├── context └── Authentication.js ├── hoc ├── Layout.js └── ScrollToTop │ └── ScrollToTop.js ├── hooks ├── useDropdown.js ├── useHoverStyleButton.js ├── useNavbar.js └── useVideoInfoHandlers.js ├── index.js ├── store └── reducers │ ├── slices │ ├── latestVideoSlice.js │ ├── moviesByGenreSlice.js │ ├── netflixOriginalsSlice.js │ ├── topratedSlice.js │ ├── trendingSlice.js │ └── tvByGenreSlice.js │ └── store.js ├── styles.css └── utils ├── animations.js ├── sorting.js ├── time.js ├── transformations.js └── validation.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | node_modules/ 4 | build 5 | .DS_Store 6 | *.tgz 7 | my-app* 8 | template/src/__tests__/__snapshots__/ 9 | lerna-debug.log 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | /.changelog 14 | .npm/ 15 | yarn.lock 16 | .env -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Netflix-Clone 2 | 3 | ![DemoGif](flixdemo.gif) 4 | 5 | A Netflix clone I created for the sake of practicing React and Redux. It features design 6 | patterns recommended by the documentation. Some of the tools used include:
7 | 8 | * Hooks (and custom hooks) 9 | * React Router 10 | * Redux Toolkit 11 | * Context API 12 | * Responsive web design 13 | * Cypress end-to-end testing 14 | 15 |
16 | 17 | It is a work in progress, and my first real project with React. Any tips on how to better write the 18 | code, manage the folder structure, etc would be really appreciated.
19 | 20 | The future of this project:
21 | 22 | * Integrate it with a Django backend 23 | * Create an authentication flow 24 | * Add REST API endpoints for every user-related event, such as adding Netflix profiles 25 | 26 | ## Architecture Diagram 27 | 28 | ![CloneFlow](https://user-images.githubusercontent.com/36729591/90905326-08c9c400-e39e-11ea-977c-76212f63b2b6.png) 29 | -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:3000" 3 | } -------------------------------------------------------------------------------- /cypress/integration/browse-home.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | describe(' -> ', () => { 4 | beforeEach(() => { 5 | localStorage.setItem('profileSelected', true) 6 | cy.visit('/browse') 7 | cy.window() 8 | .its('store') 9 | .invoke('getState') 10 | .as('reduxState') 11 | 12 | }) 13 | 14 | it('fetches trending, top-rated, and netflix originals successfully', () => { 15 | cy.get('@reduxState') 16 | .its('trending') 17 | .its('ids') 18 | .should('have.length', 20) 19 | 20 | cy.get('@reduxState') 21 | .its('toprated') 22 | .its('ids') 23 | .should('have.length', 20) 24 | 25 | cy.get('@reduxState') 26 | .its('netflixOriginals') 27 | .its('ids') 28 | .should('have.length', 20) 29 | }) 30 | 31 | it('Ensure that the first video of trending section is placed on the