Skip to content
52 changes: 26 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,58 +16,58 @@ CRUD applications are the foundation of most web applications. Being able to man

## Instructions
### Task 1: Project Set Up
* [ ] Create a forked copy of this project.
* [ ] Clone your OWN version of the repository in your terminal
* [ ] cd into the project base directory `cd web-module-project-HTTP`
* [ ] Download server dependencies by running `npm install`
* [ ] Run the local web server by running `node server.js`
* [ ] Open a new terminal window and cd into the client code `cd client`
* [ ] Download project dependencies by running `npm install`
* [ ] Start up the app using `npm start`
* [x] Create a forked copy of this project.
* [x] Clone your OWN version of the repository in your terminal
* [x] cd into the project base directory `cd web-module-project-HTTP`
* [x] Download server dependencies by running `npm install`
* [x] Run the local web server by running `node server.js`
* [x] Open a new terminal window and cd into the client code `cd client`
* [x] Download project dependencies by running `npm install`
* [x] Start up the app using `npm start`

### Task 2: Project Requirements
#### Editing a Movie
> *Let's start by walking through the process of adding the routing, component and service calls need for resource updating*

* [x] First, we need to be able to navigate to the edit movie component. In App.js, add in the `<EditMovieForm> `component to the supplied edit route.

* [ ] First, we need to be able to navigate to the edit movie component. In App.js, add in the `<EditMovieForm> `component to the supplied edit route.
* [x] Next, we need to grab the id being passed into the component through the url. Use the `useParams` hook to get the id value.

* [ ] Next, we need to grab the id being passed into the component through the url. Use the `useParams` hook to get the id value.
* [x] We need to be able to load in the current movie's attributes into our local form state. When `EditMovieForm` mount, retrieve our current id's movie from the api and save the data returned to local state.

* [ ] We need to be able to load in the current movie's attributes into our local form state. When `EditMovieForm` mount, retrieve our current id's movie from the api and save the data returned to local state.
* [x] At this point, nothing happens when the edit form is submitted. Add in the api call needed to update the server with our updated movie data.

* [ ] At this point, nothing happens when the edit form is submitted. Add in the api call needed to update the server with our updated movie data.
* [x] Don't forget to make sure that your server data and your local state are in sync! Make any changes the edit route needed to give the edit form access to App's `setMovies` method.

* [ ] Don't forget to make sure that your server data and your local state are in sync! Make any changes the edit route needed to give the edit form access to App's `setMovies` method.
* [ x Now that we have access to `setMovies`, made sure the updated list of movies is saved to our global state.

* [ ] Now that we have access to `setMovies`, made sure the updated list of movies is saved to our global state.

* [ ] Redirect the user to the currently edited movie's individual info page.
* [x] Redirect the user to the currently edited movie's individual info page.

#### Deleting a Movie
> *You added in a CRUD feature! Good job! Now let's get deleted squared away...*

* [ ] Identify the component that holds the "button" needed for deletion. Add an event handler to that button.
* [x] Identify the component that holds the "button" needed for deletion. Add an event handler to that button.

* [ ] Build an event handler that makes a request to delete the currently viewed movie. Observe what is returned from the request.
* [x] Build an event handler that makes a request to delete the currently viewed movie. Observe what is returned from the request.

* [ ] You will once again need to keep the server and state data in sync. In `App.js`, complete the `deleteMovie` method so that it receives an id, filters out any movie with that id and sets state to that resultant movie list.
* [x] You will once again need to keep the server and state data in sync. In `App.js`, complete the `deleteMovie` method so that it receives an id, filters out any movie with that id and sets state to that resultant movie list.

* [ ] Pass `deleteMovie` into the approprate component.
* [x] Pass `deleteMovie` into the approprate component.

* [ ] Run `deleteMovie` on the currently selected movie when your delete request is complete and redirect the user to the `/movies` route.
* [x] Run `deleteMovie` on the currently selected movie when your delete request is complete and redirect the user to the `/movies` route.

#### Adding a Movie
> *Alright! You ready! Let's see you use the skills of the previous steps to build a crud function from start to finish.*

* [ ] Use `EditMovieForm.js` as a model to build an `AddMovieForm` component from scratch. The component should hold all the attributes of a new movie in local state.
* [x] Use `EditMovieForm.js` as a model to build an `AddMovieForm` component from scratch. The component should hold all the attributes of a new movie in local state.

* [ ] Add in a route that allows access to `AddMovieForm`.
* [x] Add in a route that allows access to `AddMovieForm`.

* [ ] Locate the part of the ui that should redirect to your new `AddMovieForm`. Make that button works as expected.
* [x] Locate the part of the ui that should redirect to your new `AddMovieForm`. Make that button works as expected.

* [ ] In `AddMovieForm,` add an event handler for form submission. When the form is submitted, run the approprate request for adding a movie with the component's state values.
* [x] In `AddMovieForm,` add an event handler for form submission. When the form is submitted, run the approprate request for adding a movie with the component's state values.

* [ ] Make sure your component has access to and runs and modifications needed to global state and redirects to `/movies` after creation.
* [x] Make sure your component has access to and runs and modifications needed to global state and redirects to `/movies` after creation.

### Stretch goals
- Make the added DeleteMovieModal appear and be reacted to before deletion occurs.
Expand Down
7 changes: 6 additions & 1 deletion client/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import MovieHeader from './components/MovieHeader';

import EditMovieForm from './components/EditMovieForm';
import FavoriteMovieList from './components/FavoriteMovieList';
import AddMovieForm from "./components/AddMovieForm";

import axios from 'axios';

Expand All @@ -26,6 +27,7 @@ const App = (props) => {
}, []);

const deleteMovie = (id)=> {
setMovies(movies.filter(item => (item.id !== Number(id))));
}

const addToFavorites = (movie) => {
Expand All @@ -43,12 +45,15 @@ const App = (props) => {
<div className="row ">
<FavoriteMovieList favoriteMovies={favoriteMovies}/>

{/* Edit Movie Component */}
<Switch>
<Route path="/movies/edit/:id">
<EditMovieForm setMovies = { setMovies } />
</Route>

{/* Delete movie */}
<Route path="/movies/:id">
<Movie/>
<Movie deleteMovie = { deleteMovie } />
</Route>

<Route path="/movies">
Expand Down
79 changes: 79 additions & 0 deletions client/src/components/AddMovieForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React, { useState } from 'react';
import { useParams, useHistory } from 'react-router-dom';
import { Link } from 'react-router-dom';
import axios from 'axios';

const AddMovieForm = (props) => {
const { push } = useHistory();

const [movie, setMovie] = useState({
title:"",
director: "",
genre: "",
metascore: 0,
description: ""
});

const handleChange = event => {
setMovie({
...movie,
[event.target.name]: event.target.value
});
}

// handling submission for editing movies
const handleSubmit = event => {
event.preventDefault();

axios.put(`http://localhost:5000/api/movies/`, movie)
.then(response => {
props.setMovies(response.data);
push(`/movies`);

}).catch(error => {
console.error(error);
})
}

const { title, director, genre, metascore, description } = movie;

return (
<div className="col">
<div className="modal-content">
<form onSubmit={handleSubmit}>
<div className="modal-header">
<h4 className="modal-title">Editing <strong>{movie.title}</strong></h4>
</div>
<div className="modal-body">
<div className="form-group">
<label>Title</label>
<input value={title} onChange={handleChange} name="title" type="text" className="form-control"/>
</div>
<div className="form-group">
<label>Director</label>
<input value={director} onChange={handleChange} name="director" type="text" className="form-control"/>
</div>
<div className="form-group">
<label>Genre</label>
<input value={genre} onChange={handleChange} name="genre" type="text" className="form-control"/>
</div>
<div className="form-group">
<label>Metascore</label>
<input value={metascore} onChange={handleChange} name="metascore" type="number" className="form-control"/>
</div>
<div className="form-group">
<label>Description</label>
<textarea value={description} onChange={handleChange} name="description" className="form-control"></textarea>
</div>

</div>
<div className="modal-footer">
<input type="submit" className="btn btn-info" value="Save"/>
<Link to={`/movies`}><input type="button" className="btn btn-default" value="Cancel"/></Link>
</div>
</form>
</div>
</div>);
}

export default AddMovieForm;
27 changes: 26 additions & 1 deletion client/src/components/EditMovieForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,32 @@ import { useParams, useHistory } from 'react-router-dom';
import { Link } from 'react-router-dom';

import axios from 'axios';
import { response } from 'express';

const EditMovieForm = (props) => {
const { push } = useHistory();

// grabbing the ID being passed to the component using useParams
const { id } = useParams();

const [movie, setMovie] = useState({
title:"",
director: "",
genre: "",
metascore: 0,
description: ""
});

// retrieving movie's current ID from the api
useEffect(() => {
axios.get(`http://localhost:5000/api/movies/${id}`)
.then(response => {
setMovie(response.data);

}).catch(error => {
console.error(error)
})
}, [id])

const handleChange = (e) => {
setMovie({
Expand All @@ -22,8 +37,18 @@ const EditMovieForm = (props) => {
});
}

// handling submission for editing movies
const handleSubmit = (e) => {
e.preventDefault();

axios.put(`http://localhost:5000/api/movies/${id}`, movie)
.then(response => {
props.setMovies(response.data);
push(`/movies/${id}`);

}).catch(error => {
console.error(error);
})
}

const { title, director, genre, metascore, description } = movie;
Expand Down Expand Up @@ -60,7 +85,7 @@ const EditMovieForm = (props) => {
</div>
<div className="modal-footer">
<input type="submit" className="btn btn-info" value="Save"/>
<Link to={`/movies/1`}><input type="button" className="btn btn-default" value="Cancel"/></Link>
<Link to={`/movies/${id}`}><input type="button" className="btn btn-default" value="Cancel"/></Link>
</div>
</form>
</div>
Expand Down
14 changes: 13 additions & 1 deletion client/src/components/Movie.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@ const Movie = (props) => {
})
}, [id]);

// Event handler for deleting a movie
const handleDelete = () => {
axios.delete(`http://localhost:5000/api/movies/${id}`)
.then(response => {
props.deleteMovies(id);
push("/movies");

}).catch(error => {
console.error(error);
})
}

return(<div className="modal-page col">
<div className="modal-dialog">
<div className="modal-content">
Expand Down Expand Up @@ -52,7 +64,7 @@ const Movie = (props) => {
<section>
<span className="m-2 btn btn-dark">Favorite</span>
<Link to={`/movies/edit/${movie.id}`} className="m-2 btn btn-success">Edit</Link>
<span className="delete"><input type="button" className="m-2 btn btn-danger" value="Delete"/></span>
<span className="delete" onClick = { handleDelete }><input type="button" className="m-2 btn btn-danger" value="Delete"/></span>
</section>
</div>
</div>
Expand Down