- Read Tutorial
- Watch Guide Video
I removed it from my MONGO DB
because I was getting that error every 10 seconds and it was kind of confusing, so I made sure to get rid of that. Now, there are no errors. You won't be seeing any errors anyway. I just wanted to get that out of the way so you don't see those errors in my console as you're watching this. I didn't like seeing them myself.
Anyway, what we want to do is basically move these items. Now, I've created a function or a route
on the back-end that will make it really easy. All we have to do is call it, pass the _id
of the item, and the current status, and it'll switch it based on that _id
.
Really simple logic on the back-end there. Feel free to look at it. You can go see the code it's in there somewhere. It's this right here. That app.post('/request/update-status'
. You can check that out. You're not doing anything in here, but if you want to, you can look at it. You don't need to do anything in here.
What we need to do is we need to hit this route, update-status
. It has requireAuth
, so we need to pass in the header, and it uses useBodyParser
. Now, this is node.js
. It's not Python
, it's Javascript
. That's why I'm not showing you how to build this.
What we want to do is provide a token
and some JSON
. I'm going to get out of there and let's go create this action. OK. Let's go into our actions folder and then requests.js, and let's go down to the bottom here.
Feel free to copy and paste this one and modify it. I'll type it out so you can get it all right. As your messing around with it, it will be quicker just to copy and paste it. Let's say:
requests.js
export function changeStatus() { const token = localStorage.getItem('token'); return function() { axios.post(`${ROOT_URL}/requests/update-status`, { headers: { authorization: token } }) .then(response => { console.log(response.data); }) .catch(err => { console.log(err); }) } }
That's all set and we should be good to go. We don't need to dispatch anything because we're simply posting this. We'll see if we need to, but as far as I'm aware or can think of right now, we don't need to. So we can get rid of the dispatch
parameter in our function here, and we're good to go.
Now, let's go export in our index.js. Let's go to index.js in our actions. Let's import it in, and export it out of this file.
Now, we could write all our actions in here, and that would avoid having to import them all. We'd still have to export them, but we wouldn't have to import them. It's cleaner to do this because then you can see where all of your auth
actions are, or newsletter
actions, or request
actions.
It can get really nasty if you don't do this. I mean technically, you could write your entire program in one javascript file, but that would be disgusting and confusing. You'd be on line 1000
and wondering where you were at. Anyway, we want to hit this endpoint now.
The thing is if we do this right now, it's not going to work because we're not really passing on an _id
or a status
. Our back-end has no idea what's going on, it's just saying you didn't provide it with an _id
so we don't even know what item to change, and he didn't get a status.
Even if we did have an _id
we wouldn't know what status to switch it. So let's pass in the _id
. Let's pass it in an object. So lets say:
requests.js
export function changeStatus({_id, status}) { const token = localStorage.getItem('token'); return function() { axios.post(`${ROOT_URL}/requests/update-status`, { headers: { authorization: token } }) .then(response => { console.log(response.data); }) .catch(err => { console.log(err); }) } }
The reason we do stuff like the entire formData
in other functions is because its pretty clear that its formData
. We know that we're creating a request, so it's going to have a title, a body, and an image, or something else. It doesn't matter.
With here, we have nothing to call it. It's not formData
. We want to be kind of clear on what we're doing here. We don't want to just call it object
, and it's not a form so you can't call formData
. This is the best approach to be clear and concise.
Let's pass it now. The same way we do with this post up here. We just need to pass them in before the headers
. Now, there's a slight chance that it might not work this way, but let's try it. Let's pass in the object
with _id
and status
.
requests.js
export function changeStatus({_id, status}) { const token = localStorage.getItem('token'); return function() { axios.post(`${ROOT_URL}/requests/update-status`, {_id, status}, { headers: { authorization: token } }) .then(response => { console.log(response.data); }) .catch(err => { console.log(err); }) } }
This has a lot of logic and code, so don't be surprised if something breaks. You can always make an accidental typo, like I did earlier with .then
. Let's go test it out and see if it works. If it does, then thank you to the most high, but we'll see.
Let's go now to requestsItem.js. Now, what we want to do here is handle this button. We have the move button right here. Right now, we're just console.logging
. What we need to do is hook up this component to Redux, and then actually make a call to that deal.
Then what we need to do is pass an item _id
and the item status
, which you see are both right here, but we're not using them yet. Let's just do that right now. Let's first import connect from 'react-redux'
and then let's import our actions
. Let's say:
requestsItem.js
import React, { Component } from 'react'; import { connect } from 'react-redux'; import * as actions from '../../actions';
Let's scroll to the bottom now and let's use these imports so that we can access our actions. Lets say:
requestsItem.js
RequestsItem = connect(null, actions)(RequestsItem); export default RequestsItem;
It's basically just an extended functionality of our RequestsItem
. Now, we have access to our actions, so we can just say, instead of console.log
we can say:
requestsItem.js
<Button className='requests-item__move' icon='fas fa-wrench' callback={() => this.props.changeRequest({_id, status})}/> <div className='requests-item__description'> <AnimateHeight duration={300} height={this.state.height} >
All I've done in this file, in this video, is import these two imports up here on line 3
and 4
on my screen, and I have gone down here and I typed out this one line on 77
: RequestsItem = connect(null, actions)(RequestsItem)
.
connect
is equal to null
since we're not using mapStateToProps
, and I bound it to RequestsItem
. Then I went up here and I implemented this function call in place of the console.log('trying to handle change')
.
What's going to happen is it's going to call this, it's going ahead into our index.js in actions, and then it's going to hit changeStatus
, which is in her requests.js, which is basically going to get our token.
It's going to use Redux-Thunk
as middleware to perform a post
request to our server using the ROOT_URL
. It's going to hit the requests
endpoint, then it's going to hit update status
, and pass in an _id
and a status
and our authorization header
to authenticate us.
It's then going to come back and give us a response on whether or not we completed it, and tell us which status we changed it to. If it all goes wrong then you will just console.log
an error. Now, just to kind of give you an overview what's going on in the back-end, I'll switch over to the server, which I wrote and that you are not going to write any code in.
Right now, don't do anything. Don't worry about not having this code. I just want to be abundantly clear with that. We are saying requests/update-status
. What's happening in here is it's authenticating us. It's getting our _id
from our body and then it's finding one in our database.
Once it finds it associated with that _id
, it's going to take the status and store it, and that's purely so we can say we request status changed from
. Don't worry about that. Then it's saying newStatus
is in progress by default.
I actually want that to be pending
. Your status is going to be pending by default. Here's what I'll do. This is kind of cool live-coding, so don't worry about this. I'm going to update this to say case: pending
. If it's pending, I'm going to switch it to in-progress
.
This is not programming that you will be doing. I'm purely doing this on the back-end, so you don't have to. Don't worry about this coding that I'm doing right here. Excellent. So what's happening is it's coming in here it's taking the _id
and putting it into this function.
It's filtering out of the database, getting the request, and then it's storing old one. Then it's saying, according to the one that's on the back-end or the one that was sent through req.body.status
, if it's pending
let's switch to in-progress
and then let's break out of this switch.
If it's in-progress
, then let's change it to complete
and break out of the switch. If it's complete
let's change it to pending
, and break out of the switch. Then what's happening is it's saving that new status to the object in the database, and it's sending back true
, request status changed from oldStatus to newStatus
.
That's all good. I'm going to get out of this. Now, you didn't do any coding on the back and don't worry about that. All we did was this, and a few other things in this video. Let's go ahead and try it. We're calling it now in our requestsItem.js
. Let's go try it.
I'm really glad I went over that back-end, because there are a lot of little catches there that I had to fix. They're obviously going to be OK for you, but for me on this video, I needed to change those. Let's go to requests. Let's hit move, and nothing happened. Let's inspect it, let's go to a console, and we got 3 errors. It says changeRequest is not a function
.
I'm going to go into here, and I have this.props.changeRequest
. That's because it's called changeStatus
. Now it should work.
requestsItem.js
<Button className='requests-item__move' icon='fas fa-wrench' callback={() => this.props.changeStatus({_id, status})}/> <div className='requests-item__description'> <AnimateHeight duration={300} height={this.state.height} >
I typed in changeRequest
in this callback on the wrench icon button. Now it should work. Let's go to requests, now it says success
, true
, request status has changed from pending to in-progress
. Why isn't it displaying in-progress? That's just because we haven't rerendered our views.
What we need to do is find out how we can reload our our DOM
after we have performed our request. If we go to newsletter and back to requests, it should display it as in progress, but it won't because of how we programmed it to filter this. Let's go to newsletters, then go to requests.
You now see it says to
and this says 0
, but it's displaying it in here. The reason it's displaying it in here is because when we're filtering our items we're checking for in-progress
, but when we're counting these up we're checking for progress
.
Let's go back to our boxes real quick, before this video is over and fix that. Let's go to requestsBoxes.js. Let's fix it. We need to say:
requestsBoxes.js
requests.map(request => { if(request.status == 'pending') { pendingCount += 1; } else if(request.status == 'in-progress') { progressCount += 1; } else if(request.status == 'complete') { completeCount += 1; } })
Cool. Log in, go to requests, and you'll see it's now in here. That's great. Let's try moving this one over to our in-progress
. You go to newsletter and back to requests and it's there.
Let's try moving one of these to complete. You'll see it's now in complete. Sweet. Now we just need to fix this problem with rendering. We want it to render immediately. We don't want to have to click this and wonder why it's not moving it right. If you click this can to be weird because it's not rerendered.
That's how you do that. What we want to do in this next video is fix this rendering problem, so let's commit our code. Let's say git status
, git add .
, and let's say git commit -m "created change status action with post request changing the status of the item"
.