├── .gitignore ├── README.md ├── api.js ├── design-files ├── design-1-starter.png ├── design-2-routeA.png └── design-3-routeB.png ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt └── src ├── App.js ├── Movies ├── Movie.js ├── MovieCard.js ├── MovieList.js └── SavedList.js ├── index.css ├── index.js └── setupTests.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /node_modules 3 | .vscode# Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | lerna-debug.log* 10 | .pnpm-debug.log* 11 | 12 | # Diagnostic reports (https://nodejs.org/api/report.html) 13 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 14 | 15 | # Runtime data 16 | pids 17 | *.pid 18 | *.seed 19 | *.pid.lock 20 | 21 | # Directory for instrumented libs generated by jscoverage/JSCover 22 | lib-cov 23 | 24 | # Coverage directory used by tools like istanbul 25 | coverage 26 | *.lcov 27 | 28 | # nyc test coverage 29 | .nyc_output 30 | 31 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 32 | .grunt 33 | 34 | # Bower dependency directory (https://bower.io/) 35 | bower_components 36 | 37 | # node-waf configuration 38 | .lock-wscript 39 | 40 | # Compiled binary addons (https://nodejs.org/api/addons.html) 41 | build/Release 42 | 43 | # Dependency directories 44 | node_modules/ 45 | jspm_packages/ 46 | 47 | # Snowpack dependency directory (https://snowpack.dev/) 48 | web_modules/ 49 | 50 | # TypeScript cache 51 | *.tsbuildinfo 52 | 53 | # Optional npm cache directory 54 | .npm 55 | 56 | # Optional eslint cache 57 | .eslintcache 58 | 59 | # Optional stylelint cache 60 | .stylelintcache 61 | 62 | # Microbundle cache 63 | .rpt2_cache/ 64 | .rts2_cache_cjs/ 65 | .rts2_cache_es/ 66 | .rts2_cache_umd/ 67 | 68 | # Optional REPL history 69 | .node_repl_history 70 | 71 | # Output of 'npm pack' 72 | *.tgz 73 | 74 | # Yarn Integrity file 75 | .yarn-integrity 76 | 77 | # dotenv environment variable files 78 | .env 79 | .env.development.local 80 | .env.test.local 81 | .env.production.local 82 | .env.local 83 | 84 | # parcel-bundler cache (https://parceljs.org/) 85 | .cache 86 | .parcel-cache 87 | 88 | # Next.js build output 89 | .next 90 | out 91 | 92 | # Nuxt.js build / generate output 93 | .nuxt 94 | dist 95 | 96 | # Gatsby files 97 | .cache/ 98 | # Comment in the public line in if your project uses Gatsby and not Next.js 99 | # https://nextjs.org/blog/next-9-1#public-directory-support 100 | # public 101 | 102 | # vuepress build output 103 | .vuepress/dist 104 | 105 | # vuepress v2.x temp and cache directory 106 | .temp 107 | .cache 108 | 109 | # Docusaurus cache and generated files 110 | .docusaurus 111 | 112 | # Serverless directories 113 | .serverless/ 114 | 115 | # FuseBox cache 116 | .fusebox/ 117 | 118 | # DynamoDB Local files 119 | .dynamodb/ 120 | 121 | # TernJS port file 122 | .tern-port 123 | 124 | # Stores VSCode versions used for testing VSCode extensions 125 | .vscode-test 126 | 127 | # yarn v2 128 | .yarn/cache 129 | .yarn/unplugged 130 | .yarn/build-state.yml 131 | .yarn/install-state.gz 132 | .pnp.* 133 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 134 | 135 | # dependencies 136 | /node_modules 137 | /.pnp 138 | .pnp.js 139 | 140 | # testing 141 | /coverage 142 | 143 | # production 144 | /build 145 | 146 | # misc 147 | .DS_Store 148 | .env.local 149 | .env.development.local 150 | .env.test.local 151 | .env.production.local 152 | 153 | npm-debug.log* 154 | yarn-debug.log* 155 | yarn-error.log* 156 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Client Side Routing w/ React Router 2 | 3 | ## Topics 4 | 5 | * React Router 6 | * Navigating to specific routes 7 | * Consuming URL Parameters 8 | * Passing props to components rendered by the Router 9 | 10 | ## Instructions 11 | 12 | ### Task 1: Project Set-up 13 | 14 | * [ ] **Fork** this repository, then clone your fork. 15 | * [ ] Execute `npm install` to download dependencies. The `react-router-dom` library is already installed! 16 | * [ ] Execute `npm run start` to launch your Movies application in Chrome. 17 | 18 | **Once your application is up and running**, you should see a browser window that looks like [this](./design-files/design-1-starter.png) at `http://localhost:3000`. 19 | 20 | ### Task 2: MVP 21 | 22 | #### Design Files 23 | 24 | Once you are done your application will have two routes: 25 | 26 | * [ ] [Screenshot of route '/'](./design-files/design-2-routeA.png) 27 | * [ ] [Screenshot of route '/movies/:id'](./design-files/design-3-routeB.png) 28 | 29 | #### Set up Routes 30 | 31 | * [ ] Wrap the `App` component with `BrowserRouter` in `src/index.js`. 32 | * [ ] Inside your App file add two routes. 33 | * [ ] one route for `/` that loads the `MovieList` component. This component will need the movies injected into it via props. 34 | * [ ] one route that will take an `id` parameter after`/movies/` (EG: `/movies/2`, `/movies/3` where the id is dynamic). This route should load the `Movie` component. 35 | 36 | #### Add Functionality 37 | 38 | * [ ] When a user clicks on the movie card inside `MovieList` they should be taken to `/movies/{id of clicked movie here}` to see the details of the selected movie. 39 | * [ ] You will need to modify line 7 of `Movie.js` to get the id of the selected movie from the URL. 40 | * [ ] Add functionality so the `Home` button on the `SavedList` component navigates back to home. 41 | * [ ] You should now be able to navigate back and forth between the list of movies and the detailed view of a single movie. 42 | 43 | ### Task 3: Stretch Goals 44 | 45 | If you have completed Parts 1 & 2 feel free to move on to these stretch goals. 46 | 47 | #### Refactor so that our code is DRY 48 | 49 | * [ ] You may notice that we are using very similar JSX in the `Movie` component and in the `MovieDetails` component in `MovieList.js`. The main difference is the list of stars, which only exists in the "detailed" view of the `Movie` component. 50 | * [ ] Create a new component in `MovieCard.js` that returns a Movie Card. Then remove the old code from `Movie` and `MovieDetails` and instead return the new `MovieCard` component. 51 | * [ ] The Movie Card should be flexible enough to handle displaying a movie with or without the list of stars. 52 | 53 | #### Add `Save Movie` functionality 54 | 55 | * [ ] You will notice there is a 'Saved Movies' component that we are not currently using. In this step you will add the functionality to save a movie. You will need to pass the `addToSavedList` function to the `Movie` component. Once you have done that you will need to add a click handler to the save button. You will need to uncomment lines 24-27 in `Movie.js` to complete this. 56 | 57 | #### Turn your Saved Movie list into `Link`s 58 | 59 | * [ ] Your list of saved movies should be links to the movie itself. Study and understand what the `saveMovie` function is doing. 60 | -------------------------------------------------------------------------------- /api.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const CORS = require('cors'); 3 | 4 | const app = express(); 5 | 6 | app.use(express.json()); 7 | app.use(CORS()); 8 | 9 | const movies = [ 10 | { 11 | id: 1, 12 | title: 'The Godfather', 13 | director: 'Francis Ford Coppola', 14 | metascore: 100, 15 | stars: ['Marlon Brando', 'Al Pacino', 'Robert Duvall'], 16 | }, 17 | { 18 | id: 2, 19 | title: 'Star Wars', 20 | director: 'George Lucas', 21 | metascore: 92, 22 | stars: ['Mark Hamill', 'Harrison Ford', 'Carrie Fisher'], 23 | }, 24 | { 25 | id: 3, 26 | title: 'The Lord of the Rings: The Fellowship of the Ring', 27 | director: 'Peter Jackson', 28 | metascore: 92, 29 | stars: ['Elijah Wood', 'Ian McKellen', 'Orlando Bloom'], 30 | }, 31 | { 32 | id: 4, 33 | title: 'Terminator 2: Judgement Day', 34 | director: 'James Cameron', 35 | metascore: 94, 36 | stars: ['Arnold Schwarzenegger', 'Edward Furlong', 'Linda Hamilton'], 37 | }, 38 | { 39 | id: 5, 40 | title: 'Dumb and Dumber', 41 | director: 'The Farely Brothers', 42 | metascore: 76, 43 | stars: ['Jim Carrey', 'Jeff Daniels', 'Lauren Holly'], 44 | }, 45 | { 46 | id: 6, 47 | title: 'Tombstone', 48 | director: 'George P. Cosmatos', 49 | metascore: 89, 50 | stars: ['Kurt Russell', 'Bill Paxton', 'Sam Elliot'], 51 | }, 52 | ]; 53 | 54 | app.get('/api/movies', (req, res) => { 55 | res.status(200).json(movies.map(({ id, title, director, metascore }) => ({ id, title, director, metascore }))); 56 | }); 57 | 58 | app.get('/api/movies/:id', (req, res) => { 59 | const movie = movies.find(movie => movie.id.toString() === req.params.id); 60 | res.status(200).json(movie); 61 | }); 62 | 63 | app.post('/api/movies', (req, res) => { 64 | if (req.body.id !== undefined) movies.push(req.body); 65 | res.status(201).json(movies); 66 | }); 67 | 68 | app.listen(5001, () => { 69 | console.log('Server listening on port 5001'); 70 | }); 71 | -------------------------------------------------------------------------------- /design-files/design-1-starter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bloominstituteoftechnology/React-Router-Movies/70b106a873061147d5e10de5decb85fa2a44e8af/design-files/design-1-starter.png -------------------------------------------------------------------------------- /design-files/design-2-routeA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bloominstituteoftechnology/React-Router-Movies/70b106a873061147d5e10de5decb85fa2a44e8af/design-files/design-2-routeA.png -------------------------------------------------------------------------------- /design-files/design-3-routeB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bloominstituteoftechnology/React-Router-Movies/70b106a873061147d5e10de5decb85fa2a44e8af/design-files/design-3-routeB.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-router-movies", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.5", 7 | "@testing-library/react": "^13.4.0", 8 | "@testing-library/user-event": "^13.5.0", 9 | "axios": "^1.3.3", 10 | "concurrently": "^7.6.0", 11 | "cors": "^2.8.5", 12 | "express": "^4.18.2", 13 | "fkill-cli": "^7.1.0", 14 | "react": "^18.2.0", 15 | "react-dom": "^18.2.0", 16 | "react-router-dom": "^6.8.1", 17 | "react-scripts": "5.0.1", 18 | "web-vitals": "^2.1.4" 19 | }, 20 | "scripts": { 21 | "start": "fkill :3000 :5001 -f -s && concurrently --handle-input \"npm:api\" \"npm:cra\"", 22 | "build": "react-scripts build", 23 | "test": "react-scripts test", 24 | "eject": "react-scripts eject", 25 | "cra": "react-scripts start", 26 | "api": "node api.js" 27 | }, 28 | "eslintConfig": { 29 | "extends": [ 30 | "react-app", 31 | "react-app/jest" 32 | ] 33 | }, 34 | "browserslist": { 35 | "production": [ 36 | ">0.2%", 37 | "not dead", 38 | "not op_mini all" 39 | ], 40 | "development": [ 41 | "last 1 chrome version", 42 | "last 1 firefox version", 43 | "last 1 safari version" 44 | ] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bloominstituteoftechnology/React-Router-Movies/70b106a873061147d5e10de5decb85fa2a44e8af/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 |