MERN Stack Full Tutorial & Project | Complete All-in-One Course | 8 Hours

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hello and welcome to nearly eight hours of myrn Stack tutorials and instruction this video is made up of 13 tutorials that build upon each other much like the chapters of a book throughout the lessons in this video I will mention links being available in the description below I've compiled all of these links into one GitHub resource that you will find in the description hi I'm Dave gray and I'm the creator of these mernstack project tutorials you can subscribe to my YouTube channel for more tutorials like this one you can also follow me on Twitter and if you're feeling generous you can even buy me a cup of coffee let's get started learning the myrn stack with chapter one what is the myrn stack myrn is an acronym that uses the first letter of four complementary Technologies M is for mongodb e is for expressjs R is for react and n is for node.js so if the myrn stack is full stack that leads us to ask what is full stack and why is the myrn stack considered to be full stack a full stack application means it requires code that runs on the server and code that runs in the browser the code that runs on the server is referred to as the back end and the code that runs in the browser is referred to as the front end the front end and the back end are typically two completely separate code repositories in a large Enterprise full stack project there may be a team of developers that work on the front end and another separate team of developers that work on the back end as a full stack developer you should be able to work on both the front end and the back end if needed the back end for the myrn stack is a rest API a rest API also known as a restful API is an interface that two computer systems use to exchange information securely over the Internet the back end will receive requests from the front end those requests can be classified as crud operations crud is another four-letter acronym like myrn the letters of crud stand for create read update and delete these terms also indicate which type of HTTP request methods will be used in the application for example post relates to create git relates to read patch and put requests relate to update and delete has an exact match hopefully all of that information was not only an intro but also somewhat of a review because this is not a beginner's tutorial series I already have many beginners courses available and I recommend those courses as prerequisites to this series if you have not already completed them specifically I suggest my node.js course before the first lessons of this mern series where we're going to build the back end rest API I also suggest completing my react course my Redux course and my react login series playlist before the lessons in this course where we build the front end react app I'll put links to all of these suggested prerequisites in the description along with any links to resources and source code for this mern series we're going to build a tech Notes app for a small computer repair shop specifically Dan D's repair shop so our stakeholder is Dan D or full name Dan Davidson but he goes by Dan D and this isn't the type of project where I'm going to give you a tour of the full project before we begin we're more taking a real world approach here for this project and to do that we start by gathering some user stories from our stakeholder Dan D I've got vs code open and I've already done a preliminary interview with Dan D our stakeholder for the tech notes project and I've come up with 20 user stories that Dan wants now if you've never done an interview for user stories you need to think that the person you're interviewing with will probably describe what they want as a user but they're not that technical so it can be difficult to get those technical requirements out of that interview and of course that does take practice so I definitely wanted to start the project with this just so you can see the highlights that I've organized for this and we can derive our technical requirements from the descriptions that I have received from DND so the main goal for this application the first thing Dan told me is he wants to replace his current sticky note system he has a small computer repair shop and right now they use yellow sticky notes to write the problem and they slap it on the side of the computer or whatever other technology an iPhone whatever somebody brings in and it goes on their shelf and that's their whole system and he knows they need to get a better system than that so that's what this Tech notes program's main goal is is to have a local database something they can refer to and everybody knows what everybody else was working on and Dan can manage the whole thing the second thing he wants is just a public-facing web page with basic contact info again he's from a small town small computer shop he doesn't need anything extra for his website he just basically wants it to be a business card and we're okay with that because we want to focus on building this back end application for Dan okay he wants to add an employee login to the notes app because he doesn't want just anybody to be able to access it he just wants his employees to access it and then he wants to provide a welcome page after the login thinks that would just be nice to of course show the username maybe the current day time and of course what they have to work on or what's available to them maybe their current level of the administration whether they're an employee a manager Dan has at least one manager and then he's the admin of course he wants easy navigation he wants to display the current user and assign role at any time throughout the application and then he wants to provide a log out option of course he wants to require users to log out or log in at least once per week so that is a big requirement that we need to think about when it comes to authorization again it's not a public-facing site it's not a financial site it doesn't need Ultimate Security but he wants some security but he doesn't want his employees to have to log in all the time either so we need to think about that with the authorization he wants to provide a way to remove employee access as soon as possible possibly he fires someone and needs to remove that access so they do not disrupt the Notes application notes are assigned to specific employees so everybody has their own responsibility notes have a ticket number title note body created and updated dates notes are either open or completed notes can be employees managers or admins notes can be deleted by managers and admins only so that's a consideration when we're applying the roles and permissions of the application anyone can create a note because a customer may come in to check in and Dan doesn't know who may be at the counter but they all need to be able to check in and create a note for a customer employees can only View and edit their assigned notes however managers and admins can view edit and delete all notes so that's another thing with the roles and permissions only managers and admins can access the user settings and only managers and admins can create new users and then desktop mode is the most important because that's where they'll be using it but it should also be available in mobile now notice this is a markdown file that I created a checklist in if you're not that familiar with markdown files they end with a DOT MD and that's also what the readme files for GitHub are usually created with now in Visual Studio code I can preview this file by pressing Ctrl shift in the letter V and we can see this markdown file as it would appear possibly on GitHub or somewhere else and the nice thing is we can also use it as a check well it's not checking right now let me go back and if we put an X in here it would check but then also we can preview this a different way with control K and then just press the letter V and now let's look at this and we have this on the right and the edit on the left and now if I check this yes it does check and we see the X over here so you can work with these markdown files within Visual Studio code and they're sometimes very useful for checklists so I just wanted to highlight that fact as well but those are user stories and we'll create our technical requirements from these descriptions go ahead and create an empty folder for your backend code for this mernstack project act four Tech notes and then if you do not already have it I sure hope you do but if you don't install node.js from nodejs.org and you can download that right on the home page and they have currently as of the making of this video 16.16 LTS is recommended for most users of course get whatever the most current is that should give you npm and node I already said I hope you do because again this is not for beginners you might get through today's lesson but I don't feel like you will be comfortable and get that far if you're an absolute beginner go back to that node.js course if you are now after you've installed node and npm or maybe you already have them you can control backtick inside of Visual Studio code and it should open up a terminal window you can check your versions as well by typing node Dash V it says I have 1616 I can type npm-v as well because that also installs and we need that and it's currently 8.15.1 So today we're going to build the back end or at least start building the back end rest API for this myrn Tech notes project and that will use node Express and so three of the four Technologies in the stack so what can we take away from these user stories already just the basic General thing that we would need for our server is we need to be able to create notes and as we mentioned in here view which would be read as related to crud edit and that would be update delete and then there's also the ability to create notes as well so we need to perform all crud operations four notes and also for users as we read through that so we know our basic rest API is going to need to complete the crud operations for both notes and for users and it's eventually going to need to support authentication although we'll do that last we want to get the application working first and then apply the authentication as the last step so we're now ready to get our server up and running in node.js and to do that I'm going to once again open up the terminal window with control and backtick then I'm going to type npm init and dash Y which will help it avoid all of the questions it usually wants to ask and we can see some of that being completed here and after we did that we get a package Json file now this is where our dependencies will be listed and I need to install two dependencies today so I just opened up the terminal window again I had it full screen but inside of the terminal window to install these dependencies I'm going to use npm and then type I for install and then I want to install Express which is one of our myrnstack Technologies and then I'll just press enter and I will let that install and we should see it listed here as a dependency inside of our package Json after that there's a Dev dependence C which is different from a normal dependency because we'll only use it during development so I'll type npmi for install again and then I want node mon at the end Dash capital D and that makes this a development dependency only node mon will let us run our code and as soon as we save the changes it will continue to run our server with those updated changes so it's very useful okay after we've applied both of those we should be able to close out the terminal once again I'm going to scroll to the top of the package Json and you can see it probably named your project whatever you named your folder mine's in lesson one it's version 1.0.0 that's fine let's go ahead and put a description in here and say Tech notes myrn project after that we're going to use a server.js file this is really just kind of preference index.js is what it defaults to and then for scripts I'm going to go ahead and remove this test script and instead I'm going to put in a start script and there I'll have node space server a comma after that because this is an object I'm going to type Dev and then I'm going to have node mon space server so we'll use node mon during development and that's the script that will go ahead and let us start nodemon one other thing I like to do right at the beginning so I don't forget is create a git ignore file we haven't initialized git for our repository yet but we could at any point and this is dot get ignore and inside of the git ignore we list the node modules because we do not want to send those to GitHub or wherever we might keep our code Repository that is this huge folder here that installed when we added some dependencies and there's no reason to send that up to the code repository so we create this git ignore file so it's ignored and not sent along with the other code okay now that we've completed those things let's create our server.js file at the top of our server file we'll Define Express and we'll set this equal to require and we'll just require Express right inside of there underneath that we need to define the app so we'll say const app set that equal to Express and we'll call Express and then I'm going to define a constant called port and this will help set what port we are running our server on in development but also when we deploy it somewhere so here we'll get a DOT EnV Port if the place we would deploy it would have a port number saved in the environment variables then it would grab that otherwise we're going to run it here locally at Port 3500. okay that's the initial Imports now let's just tell our app to start listening so we'll say app Dot listen and then we'll pass in the port and then we have a function and in this function we'll say console.log and we'll go ahead and make a template literal here we'll say server running on Port and inside of this we can pass in our value for Port let's go ahead and save our server file let's press Ctrl back tick to open up the terminal window again and now we can type NP let me get lowercase npm run Dev and after I press enter notice our server has started running this is the console for node.js and it says server running on Port 3500 it's not really doing anything if we send a request there we wouldn't have any luck but the server is up and running with just those few lines of code let's not stop there though let's go ahead and make our servers serve a few bits of information to us and the first thing we need to do for that is import path from the node.js system so there we'll say require path and after we have path now we can go ahead and use it here in the body of our server file and we're going to say app dot use and we're going to listen for the route just the slash which would normally be the root or the index of a web page and here we'll say Express dot static and then we'll use path dot join which is a method of path and then we have two underscores and dur name which is a global variable that node.js understands and it says look inside of the folder that we're in after that we'll put a comma and then say look inside of the slash public folder we're telling Express where to find static files like a CSS file or other resources like an image that we would use on the server now if we save this it won't be able to find that if something was looking for it because we haven't created it but notice nodemon went ahead and restarted and we're still running on Port 3500 so now let's go ahead and come over here to the file tree and create that public folder and inside the public folder I'm going to create a CSS folder now normally with our rest API we're just going to be receiving requests and sending back Json data that would be requested and will be receiving Json data however a rest API can still have a splash page it could still also return information about requests that cannot be fulfilled and so we can at least set that much up as we start now inside the CSS folder you might guess we'll go ahead and create a style.css file not being a CSS tutorial I'm just going to paste in some basic Styles here I'll close the terminal quickly so you can see everything on one screen we're importing in a Google font we've got a basic reset and just some styles on the HTML embody nothing big but just a few Styles there so we could have something on the splash page for the rest API or possibly a 404 page when a resource is not found let's go back to the server over JS now and let's put in another line of code that says app dot use and we'll once again look at that root route and now we'll say require and we're going to look for a routes folder and then a root file and now we crash the app and you can see nodemon said that because we do not have a routes folder and we required it in the file so let's go ahead and create that routes folder and then inside of routes we're going to need to create a file named root dot JS inside of root we need to require Express again so we'll say const Express set this equal to require fix press now after that we need to define a router so we'll say const router and we'll set this equal to Express dot router with a capital R to start the word router and then we need the path once again so we'll say const path and we'll require path from node.js and then after we have required those three things we're ready to say router dot get so this would be a get request that relates directly back to our HTTP methods and the nice thing about Express and these routes is they recognize reg X so we can use a reg X here and the first thing I'm going to type is the carrot and that says at the beginning of the string only and then we'll put a slash and then the dollar sign which says at the end of the string only so that means this will only match if the requested route is only a slash and that would be for the root but then I'm going to put in a pipe which is an or for regex then I'll have slash index because maybe they would request more than just the slash as they put that in and after that I'm going to have oh I put in a quote that's the reason we're seeing red right now I want to remove that quote because all of this is going to be inside this string so the quote comes at the end but then after the index here I'm going to make the HTML optional so they could request just the slash or maybe just the slash index without the dot HTML or the user could request the full index.html which would also work I got an extra parenthesis in there let's put the comma there then we'll have a request and a response for our function and then inside the function we will send the file back so it'll be response dot send file then we'll say path.join and we'll use that dur name directory name variable that nodejs recognizes and now we need to tell it where to find the file and the file is going to be up out of the routes folder so that's what the two dots indicate and then we're going to tell it to look into a views folder and then we're going to have it look for the index.html file and that's quite a bit there but that should wrap it up and I need that parentheses there at the end so there I've got the syntax correct and we've got our router.get and it will get the index.html file if it matches any of those three we just now need to create the views folder and the index.html file but before we leave this file we need to say module.exports and set that equal to router and now this file is complete also notice our server is once again running nodemon restarted it as soon as the errors were fixed and it's not crashing even though we're 10 telling them we have a file that we don't because nobody's requesting it right now so we can go ahead and do that this is not a require the require is actually what crashed before when the required thing was not available but now this does not of course crash the application okay now we'll go over here to our file tree Once Again create a new folder we'll call this views and then inside of the views folder we'll create a new file and call it index.html I'm going to type an exclamation mark which is an emit abbreviation in vs code then I can press Tab and we instantly get the foundation of an HTML page here I'm going to replace the title where it says document with Tech notes API and then inside of the body I'm just going to use an H1 element and type Tech notes and then we need to bring in the CSS so that is a link Rel is a style sheet and then the href is going to be set to CSS slash Style dot CSS and then we close out that link tag and actually I think I need the slash close there we go and after we save that now it can find this CSS because that is a static public file that we set up earlier with our route back here in the server so we didn't have to put in the full file path for that it's just one of those things that's available inside of this public route our server is still running let's drag vs code to the left I'll go to my new tab we want to go to localhost colon 3500 and press enter and there we get our Tech notes home page at the root however we could request something that doesn't exist and we might not get the best results if I put in slash Dave we just get the basic Express response cannot get Dave so let's fix that by going ahead and taking care of basically 404 errors and those are for resources that are not found let's start by creating in a 404 page inside of the views since we're already there so another new file I'll type 404.html again with the emit abbreviation to get the foundation here and we'll just say 404 error or we could say 404 not found I think that's a little bit better than error but then inside of an H1 we'll just say sorry and then we can put a paragraph as well and inside the paragraph we'll say the page or let's say the resource you have requested does not exist and of course we once again need to bring in the link and that would be Rel equals style sheet and href equals CSS slash style dot CSS we'll close that out and save let's go back to the server and let's handle anything that's not found we want to put this after all the other routes and of course I'll put it before the app listen for this server but here we'll just say app.all instead of app.use and now we'll listen for this asterisk which essentially means all everything that reaches it to app.all will be put through this instead of being routed to anything that's above so that it's the catch-all that goes at the end so then we'll once again have our request and our response and we'll have our function now and the first thing we know is the status is a 404 so we can set that right away although we're not sending the response yet and now we can look at the headers from the requests that come in and determine what type of response to send so we can say if the request has an accepts header that is HTML then we can base our response on that so here inside of this if we'll say res dot send file and now this will basically be what we did before to send our index.html but we're going to send our 404 and of course we have to route to it correctly so now we're at the server level so we don't need to go up out of a folder we're just going to go down into the views folder and from there we're going to get the 404.html file after that we can put an else if here we could say request dot accepts and let's look for Json which would be very common sent to a rest API so if there's a Json request that wasn't routed properly and didn't get stopped by any of the expected routes this would be the response we'll say response.json and now inside of this we'll have a message and then we'll say 404 not found very basic generic message I guess I was using single quotes before Ctrl D to select both of those switch those to single just to stay consistent and finally we'll have our last else that will be sent no matter what if HTML or Json was not matched in the accepts header and here we'll say response DOT type text is fairly safe just about everything can receive text and we will send once again our 404 not found now we'll test this out in the browser and as you might expect we should get HTML back so if I'll highlight this and just press enter again now we get sorry the resource you have requested does not exist so we got our 404 page when it didn't match any of the other routes we are well on our way to having our rest API up and running for our full stack mernstack application what is middleware middleware is just one or more functions that are placed in the path of requests that are received by our backend API middleware can add additional functionality to our backend rest API middleware can also apply some preliminary process into requests before they get to the controller where the request processing will be completed we'll be adding three types of middleware today built-in middleware custom middleware and third-party middleware let's start today with a couple of quick Corrections I'm on the nodejs.org site in the first tutorial I said the latest version of node to use and really what it stands for LTS stands for long-term support I had latest on the brain from installing the latest packages but I just wanted to highlight that as I've been asked about that a couple of times also in the code from lesson one which is our starter code by the way for lesson two just always go back one previous lesson and that completed code will be the starter for the next I just wanted to highlight that in path join as you see that I'm using right here path dot join you do not have to use a slash and notice I didn't do that when I talked about the views directory here but I did it with public here so I was just a little inconsistent you can remove that if you want to and if you see me using the slash some other time inside of path.join well that just means I'm not really thinking about it it won't hurt either way but you do not have to use it and I will try to stay consistent okay with those Corrections out of the way let's get started by talking about middleware and again we're in that starter code which is the completed code from lesson one already so we already have our server set up and now we're going to add middleware and we've already added one piece of middleware that we really didn't discuss and that was built-in middleware Express dot static is middleware and it's telling our server where to grab static files and I was explicit here when I put this in we put in the app.use and then we said slash and then we have express.static and I use path join to get the directory name which is This Global variable and then I said in the public folder which we created over here you might see this used without quite so much explicit information which you can also do so I'm going to show you that right now you might see it without the slash here and you might see it without the path joined so it might just be like this and then I can remove one of those parentheses I believe and this would still work because it's relative to where your server file is or your index.js if you didn't rename it to server.js like I did but public is relative so it can find the public file right here and this will work if you want to do that I like to leave mine with a little bit more explicit information like you see right here and like I did in the first tutorial so I wanted to highlight that we've already added one piece and the other one that we need is the ability to process Json in our application so we're going to say app dot use then we're going to have Express two s's dot Json and we need to call that and that will let our app receive and parse that Json data and that's what we expect to use now with that complete you can see how easy it is to add built-in middleware to your application but now we need to go ahead and create some custom middleware so I'm going to create another folder and let's first well I'm going to create two folders let's first create the logs folder because a server needs to be able to log some things errors possibly requests and whatever we want to log so we'll have that logs folder we're also going to create not inside the logs folder though so I need to make sure I'm out of that let's create a middleware folder as well and then while I'm thinking of it inside our git ignore file let's add the logs directory because we don't want to send those logs up to GitHub there'll be development logs but even in the future with another repository the logs wouldn't really help our code base so they don't need to be sent to the repository at all so I'll include that in the git ignore that said let's go to the package Json file I'm going to change the name here to lesson two but now we need to add some dependencies that we're going to use as we write some custom middleware so I'm going to press Ctrl and the back tick then I'm going to type npmi and date Dash FNS and also uuid so two separate packages and we can add them on the same line like that and they will install shortly and when they are finished we should see them listed in our dependencies and now we do so we have data F and S we already had Express and now we also have uuid and now inside our middleware directory let's create a new file and I'll name this logger.js at the top of logger we need to destructure so I'm going to de-structure format and I'm getting that from our date FNS dependency that we just required after that I'm going to do one other destructure here and this is going to be V4 and I'm going to rename it uuid and that's going to be coming from uuid but I know that looks a little weird but that is the least the last I looked that is what they were currently recommending so we're getting V4 when we destructure and then we're renaming it uuid after that I need the fs module for the file system so that comes directly from node it's already built in so we'll have require FS now I'm going to do shift alt in the down arrow but I'm not going to leave it the same this needs to be FS promises and at the end of our require we also need to put dot promises and then I need that path module again so const path equals require path now we have everything imported let's start by creating a helper function called log events and this will equal an async function that receives a message and also a log file name now inside this function I'm going to copy and paste a couple of things I typed earlier just because they are template literals that have several different variables in here and it's easy for me to create a typo so I'd rather just go over these with you I'm creating a date time variable and I'm using that format function notice this is a template literal and inside this template literal I've got a new date object and then I'm formatting it and this goes from the docs of the date FNS package that you can find at npmjs.com I believe is where you could search that up and find those docs and it will also link to the GitHub repository but there are different ways you can format the date and I'm going with year month day and then I've got hour minute seconds so anytime I'm creating a log message I'm getting not only the date but also the time and then I have a log item here and for this log item I'm passing in this date time that we just created and notice the slash T's those are tabs which will make the logs easy to import into Excel or something similar if I wanted to I'm calling uuid here which creates a specific ID for each log item which might be handy as well if we were to export that and then we have the actual message that is passed in this last slash in creates a new line so each log item gets its own line in the log file okay let's go ahead and create the rest of this function now so we've got a try and here we're going to check if the directory exists first if not and we try to save there we'll have an error so we say not which is the exclamation mark then FS Dot exists sync and then inside here I'll use path.join and we'll use the Global dur name variable and then we'll go up out of the folder with two dots and then we'll look for a logs folder and we're saying if that doesn't exist then we'll need to create it so we'll say await FS promises and then that's dot mkdir for make directory and then we'll just need that same directory that we are looking for if it doesn't exist that's what we're creating so I'm just going to copy that and paste it right in there so now we have either created the directory or it already existed and now let's say await FS promises and we'll append file because we are appending to our log file or creating that log file as well if it doesn't exist which is what will happen here this is once again that same path so I'm going to paste it in again but we're not finished after that I need a comma after logs and I need to say the log file name and then we can have the parentheses and then we need to specify our log item I'm going to press alt Z because that's a longer line so now we can see it wrapped down so here's the append file we provide the path oh I've got two path joins that's why it got a little longer let's go ahead and remove that so now we provide the path the directory name two dots to go about logs so we're in that logs directory then the file name itself and then the item to log to the file now after this we'll just put the catch here and I'm catching an error and right now I'm just going to say console.log error now I'm going to scroll up and we'll write the actual middleware here so const logger middleware has a request a response and the ability to call next so it can move on to the next piece of middleware and here we'll put in log events and actually I'm going to copy this as well I am just too susceptible to typos when it comes to those template literals with several values so let's look at this log of vents which is what we just created above and we're passing in this template literal here that has the request method a tab the request URL another tab there should be tabs between all and then the origin what the URL where the request originated from and we're writing that all to the request log dot log which is like a text file but that's the convention for writing logs and you can open it like a text file as well so this would log every request that comes in you might want to to put some conditionals in there that would say Okay Only log it if it's not coming from our own URL or something like that or only specific request methods because this would get full very fast if you left it like this for your entire application but I'll leave it there and leave that part up to you now we'll say console.log and here I think I can manage to type in this template literal it'll just have the request method after that a space and the request dot path we'll see that in the log of node.js here as we're running our server and that could help us during development after that we just want to call next so it moves on to the next piece of middleware or eventually the controller where the request would be processed the logger of course would come first before those other things and now let's add the module dot exports set that equal to we want to export both of these because we might use log events inside of an error Handler as well now let's go back to the server.js file and we can import the logger we created so we'll say const we'll get the logger and that comes from our require look in our middleware folder we created and there should be the logger there it is now we really want this logger to come before everything else so we'll say app use logger and we should be able to save that I'm going to press control and back tick to get our terminal open and then I'm going to type npm run Dev to get our server up and running it should start on Port 3500 and you can see we're using node mon so as we make any changes it should go ahead and restart and it will give us this message this is our console for node.js I'll drag this to the left and we'll go to the browser we've got our localhost 3500 where we should at least get our home page when we put in a request and we do and we can now see the requests log here in the console so we had two requests come in both get requests one for that root route and the other for the static file that we specified that was available in the public folder so both of those were logged and now we should have a request log inside of our logs directory as well I'll drag this over and we can see how how this was logged we have the date the time the specific ID of the request and the request and then the origin is undefined as we're here in our local development environment now we're ready to add one more piece of custom middleware so let's create another new file inside of the middleware directory and we'll call this air handler.js I'm going to close the terminal just so we don't have to look at that right now and we'll start out by importing in that helper function that we created called log events so that will equal require and we're in the same directory so it should just come from logger from there we can create our error Handler and this is going to overwrite the default Express error handling and we can do that just by creating this middleware that starts with an error and then it also has the request response and next and now inside of this function this middleware I am going to once again paste in a line that's just a little bit difficult for me to type without typos and we'll go over this but we're calling that log events function and it's a big template literal here I'm including the error name and message and then there's a tab and then it's just like the previous log events that we were logging so it has the request method the URL the origin and this is going to the error log file so error log.log otherwise basically the same I'm also going to put console.log and log the error.stack this will be a pretty large message inside of our console several lines worth but it will give us a lot of details about an error and tell it specifically where it is which is always helpful then I'm going to define a status and this is going to look to see if the response we receive up here as one of the parameters already has a status code set and this is a ternary so if it does have that status code set then we'll just return that status code if not it's going to be a 500 which is a server error and then we'll set the status to whatever our ternary determined and then we'll have a response that is Json data and we'll say message and then we'll have the error Dot message let's not forget to do the module exports at the bottom so we'll say module.exports set that equal to error Handler and now back in the server.js file we can import our error Handler as well so we'll say const error Handler and this will come from that middleware folder also and this is from the error Handler file but now instead of using it at the top like the logger we want to use it at the very end essentially at least right before we tell our app to start listening so here we'll say app use and we'll pass in that error Handler right there now we will test this out in a moment but I also want to get started with our third-party middleware now that we've written custom middleware so let's go to the package Json one more time bring up the terminal I'm going to press Ctrl C to stop the server temporarily type npm I and I need cookie Dash parser our rest API is going to need to be able to parse cookies and that's because we're going to use them in this mirn application we can see we've added the dependency right up here so I am ready to once again type npm run Dev and keep the server running and it will restart with changes that's good let's go back to the server.js I'm going to scroll back to the top for the Imports so once we get up to the top I'm going to import that cookie parser we'll call this cookie parser and camel case we'll set this equal to require cookie Dash parser and once we have that it's just about as easy to apply as our built-in Express Json middleware so we'll say app dot use and then we'll say cookie parser and we call that and now we'll be able to parse cookies that we receive as well so that was very easy third-party middleware to add however I want to cover something a little more complicated that must be added every time or at least a consideration every time you create a rest API so I'm going to drag the code to the left I am going to go over here to the browser and we're at google.com I'll just press enter to pull that up and then open up Dev tools clear out whatever warnings they have and what I'm going to do here is Type in a fetch right in the console and type in our development rest API so localhost 3500 and now when I press enter we get a cores error a Coors policy that stands for cross origin resource sharing and it says no access control allow origin header is there this sends an options request which is another type of HTTP request much like a post a put a patch a delete and so on and that options did not detect that header this is really the first line of security also Google should not be able to request information from our API another resource add another URL essentially unless we say it's okay so we have to enable cores for that to happen and pass this what is called a pre-flight request so let's go ahead and do that and we'll do it as if we were creating a public API first and then we'll secure it afterwards so it's very easy to set it up as if it were a public API so we'll go ahead and control backtick Ctrl C to stop the server again we'll type npmi cores and it should install quickly and we should be able to see that listed in the package Json now as a dependency so that's good we'll control backtick again and npn run Dev to start the dev server back up with nodemon after we've done that let's go back to the server.js and we need to import cores so we'll say const cores equals require cores and after we have that it's just about as easy to apply as these others when we just want everything to be available to the public we'll say app.use cores and we call cores and now if we pull this back over to the left and we go back to Google and we do Ctrl shift I to open up Dev tools we've got our error here from the fetch let's try the fetch again and see what happens we get a promise pending because we're not really processing anything from the Fetch and we expect the promise but there's no error that's because our API is now essentially available to the public so those that are at other Origins can request resources from our API now what we want to do now is secure it so we only allow the origins that we want to access our API and we can do that with cores options so I'm going to control or close the dev tools drag this back to the right Visual Studio Code full screen and we need to create some cores options we're going to do that by creating first a directory over here called config and inside of config we're going to create two files the first one is allowed origins.js here we'll Define our allowed Origins set this equal to an array and now these will just be strings that will say what Origins are allowed and the first one we'll put in just for development will be where our react app will eventually be at and requesting data and that's usually localhost 3000 after that I'm making up a couple of fictitious URLs here I didn't register them I don't think anybody else has either but you never know so I'm just saying https colon slash slash www.dandy [Music] repair shop.com because that is our stakeholder for this project is dandy and his repair shop and then we'll also say https colon slash slash and we'll just do this without the W's these are strings that need to match so you would typically want to do both of these for any URL so you'd have dandyrepairshop.com as well these would be the local hosts that we would accept to access our rest API and now we'll say module dot exports equals allowed Origins and now we can use these when we create the cores options in the next file so we'll create another file coresoptions.js I'll start by importing in the allowed Origins that we just created and it's nice to have those in a separate file unless we if we want to refer to them somewhere else inside of the API as well so that's why they're in a separate file to begin with now we'll say const cores options and this is going to equal an object this is again third-party middleware so we have to follow the rules they have set up for their options this is like a lookup object where we have the origin method here and this is going to receive the origin and a callback function and now inside of this function we're going to check that allowed Origins list and then we'll say dot index of and I said list it's an array then we have origin and then we'll say if it's not equal to -1 now this would limit it to where only those in the array only those Origins would be able to access our backend rest API but then that would screen out other software like Postman that we might test our API with or possibly desktop applications or anything else that didn't provide An Origin so you might also want to say or no origin and this would go ahead and allow Postman and some other things to possibly access our rest API so here this is if it's successful we'll say call back the first argument that is passed into the Callback is an error object so here we'll just say that's null because we don't have an error the second is the allowed Boolean either true or false and yes this is successful so we'll stay true and then here we'll have the else where it fails and now we'll have a callback and we'll use that first argument which is an error so we'll say new error and we'll say not Allowed by cores there's also some other options we can set inside of cores one is credentials and we'll set that to true now this sets the access control allow credentials header and if you did my node.js for beginners course we actually created separate middleware to set that header which is kind of taking the long way around but we learned a little more here you can just set this option to true and it handles that header for you so that's a great option to go ahead and set to true there and then say options success status and we'll set this to 200. I believe the default is 204 but there are some devices that have some problems with that so you might just want to set that to 200. after that we'll say module.exports and we'll set that equal to cores options now I know I might get asked what devices would have a problem with the 204 but I believe in the documentation it says Smart TVs older browsers things like that we probably wouldn't run into it but just setting it to 200 makes so we will not have any problems let's head back to the server.js and go ahead and apply these options now so we need to import our cores options so we'll say const cores options set this equal to require and then we'll have our config folder and then we'll have our cores options file and then for course options we just pass them right into cores here so once we've done that our course options are now set up let's go ahead and make sure the server is running and yes it's on Port 3500 and running as expected I'll drag vs code over I'll drag our browser back over and go ahead and open up Dev tools once again let's go ahead and put in a fetch once again and now we are blocked by cores as expected and the reason is we're not allowing Google to access our resources we're only allowing those URLs that we put in our allowed Origins to access our resources at the rest API so that's as expected I'll close this we'll come back to our server and let's see what happened with that error and we did log the error stack to the console now so let's look at this it's fairly large here but it gives us quite a bit of detail we got the error not allowed by course so we log the full error stack and then it gave all the other details which can be quite a bit but let's look at what else happened we now have an error log because we had our error Handler and let's look at what was logged in our error log and now we had our error not allowed by cores there as well and it came from google.com well that's great everything's working as a expected we have added built-in middleware we have added custom middleware and we have added third-party middleware it's added extra features to our rest API and it will even do a little bit of preliminary processing to those requests that are coming in so we are well on our way to completing the back end for our merinstack project mongodb is a nosql database built with collections of documents my node.js course gives a deeper explanation of mongodb and I highly recommend that course as a prerequisite before you complete this tutorial our starter code today is available in the course resources it's the completed code from lesson two as we now begin lesson three in this mernstack project series we will be integrating mongodb into our rest API today but before we do that there's a dependency that I want to set up in our existing code you can see I've got the package Json file open here I'm going to change the name to lesson three and go ahead and save that but afterwards I'll press control on the back tick and I'll pull this down a little bit so we can still see the dependency list or at least some of it there I'll scroll that up there we go and I'm going to type npmi dot EnV and hit enter this is going to install the dot EnV package it doesn't take long and now you can see it listed in the dependencies this will let us use environment variables inside of our rest API now environment variables are values that we want to use on the server when we deploy as well but we will not want those stored in GitHub so we'll set all of that up let's first start by going to server.js and I like to put this right at the top the very first line and I'm going to put require dot EnV and then after that I need to put dot config and that allows us to use dot EnV throughout our package we won't need it in every file we'll just put that right here and we'll still be able to use environment variables in all of the files where we need them okay after doing that let's create a DOT EnV file now it needs to be at the same level as the server.js here so I'm just going to create that file and it starts with a period instead of the word Dot and then it's EnV now you can see I'm using vs code icons extension and then it gets this little gear symbol here and now we can put variables inside of here that will be able to pull out as environment variables so just as an example of this I'm going to type node underscore EnV and set this equal to development note I don't need any quotes around development or anything else this is just how you set them you typically set these as all caps for these environment variables as well so I'll save this and now back in the server.js somewhere here and I'll just put it right towards the top I'm going to say console.log and now to pull a value out of the environment variables I'll say process.env and then we put the actual name of the variable so I'm going to log that value to the console when we start up our server so let's go ahead and start up the server I'll do control back tick then npm I want lowercase here npm run Dev and I'll pull this up and let's see what we get inside of our console and I had to scroll to see it there so the development was printed before we got the server running on Port 3500 but there is our environment variable printed to the console just like we expected it to be with the console log statement so now to keep this value or any values we store inside of the dot EnV out of GitHub we want to make sure to list that dot EnV file right here inside of the git ignore file as well okay now as we set up our free mongodb.com account we're going to get a database URI string back that will let us connect to mongodb and we'll want to store that in this dot EnV file so I'm going to put database underscore URI equals and this is where we'll put the connection string that we get from mongodb so the next chapter of this video is about five and a half minutes I've got time stamps in the description and it's going to walk you through setting up a mongodb database mongodb.com now this clip is taken directly from my node.js course because the process for setting this up hasn't changed at all so just as you go through realize this about this myrn stack project that we're creating you can name your project whatever you want but please name your database Tech notes DB and I'll type this out just so you can see it so remember to name your database as you set this up as Tech notes DB with a lowercase T at the beginning at least if you want it to match my code so you'll have that and then create your first collection and call it users all lowercase now I'm going to go ahead and share that clip so you can go ahead and create your mongodb account if you already have that if you already know how to do it just skip this chapter in the video and we'll come back and we'll put our database URI right here inside of the dot EnV file okay we're at mongodb.com and I already have an account so I'm going to choose sign in if you don't have an account you'll want to sign up for a free account so you can just click try free I'm going to click sign in and then it will take me to a page that probably uses my Google ID or allows me to log in with an email address yes there it is so you get those options I'm going to log in with my Google email address or my Google account and then we'll meet back up after you have your account or you've signed into your account okay I'm signed into my account and I'm on the projects page where I can create a new project and you see I already have one project here now if you're not on this page once you're signed in Just click the little leaf in the top left and it says view the organization home because that's where this is so once you're there you'll want to create a new project and now you want to name the project I'm just going to name this one tuts short for tutorial and click next and then it asks you to go ahead and set permissions or members and it'll probably assign that to your default account to start out with as you can see I have project owner right here so I'm going to click create project with the project created you can see I now have tuts up here above database deployments we need to build a database and of course it gives you the Big Shiny button right in the middle to do so so please click that and then it gives you choices and we're just going to go with free today if you want to get one that you pay for that's fine I'm going to choose free over here on the right and then it will say create a shared cluster and right now I'm just going to keep all the defaults so free shared it has AWS it has one of the USA regions for me because I'm in the U.S you may want to pick a different one if you're not and maybe it already defaults to something close to you and then it just has these other default settings and I'm going to go with all of that even the default name here cluster 0 and click create cluster at the bottom now it says new clusters take between one to three minutes to provision so I'll come back when this is finished my cluster 0 has now been created and we're given this screen so what we want to do is Click browse collections we don't have any collections yet so we get this and it says load a sample data set or add my own data we're going to choose add my own data with that it asks for a database name and a collection name so let's just call this company DB and then we can call the collection name let's go with employees and I'll just keep that all lowercase company DB is capital company and capital DB at the end and I'll click create and with that has created our company DB database and our empty employees collection right here what we should do now is concern ourselves with database access so let's create a user that can access this new collection and database that we have so create a database user we click the big button that says add new database user and then it gives us password certificate all of that we'll just stick with password and it put in some old information for me let's put in something different here let me go with uh Tut once again and then for a password I'm just going in and we'll go ahead and show whatever the password is I'll go with testing one two three kind of like a mic check Okay so we've got Tut testing one two three I think we'll keep all of the default options here and we want the read and write to any database and of course I'll come back later and delete this user but for now we'll use it for the tutorial and we'll click add user and once we have the user we need to go back to our cluster so let's click tuts and that takes us back to our cluster and it says we are deploying your changes current action configuring mongodb so I'll give this just a second and then we're going to click connect with the configuration now complete let's go ahead and click the connect button it tells us we need to set up some security this part is required and what we're going to do is allow access from anywhere we don't really know where we're going to host our back end yet so this is good for development right now until we actually know what IP address we had so let's just add in the zeros and that means it's good from anywhere we already created a user so now let's click choose a connection method and we're going to connect our application this gives us a connection string and this is what we want notice it's already put in the user I created now I'm going to have to put in the password including getting rid of the less than and greater than around the password and then also I need to replace my first database with the company DB which was the name we gave the database so I'm going to copy this and we're ready to close out of this now and open up visual studio code okay you should now have your connection string from mongodb I'm going to paste mine in here except I'll show you a difference I'm going to press alt Z to get this code to wrap you should have your username right here and then you should have your password right here of course I'm not going to show you mine but here just in a second as we go away from the screen I'll put mine in so mine continues to work as well as we connect to mongodb notice I also have the tech notes database name right here inside of the string as well so you can just match that pattern up to yours to make sure you have a proper connection string from mongodb we're back at the package Json and we're almost ready to create our data models but before we do that we need to go ahead and Import in one other package and that package is called Mongoose it's a library that really helps us communicate more easily with mongodb so I'm typing npmi Mongoose and installing that as a dependency as well it won't take long either I can close out of the terminal and we'll now see manga listed here amongst the dependencies as well so now in the file tree I want to create a new folder and we'll call this folder models this will store our data models and now inside of the models directory I'm going to create a new folder and I'm going to call this use I said new folder a new file and I'm going to call this user.js with a capital u and this will be our user data model the first thing I need to do is require Mongoose so I'll say const Mongoose equals require Mongoose after that we'll start creating a schema that will allow us to have a data model and so we'll say cost user schema and we'll set this equal to a new Mongoose dot schema and now that schema has a capital S when you put it after Mongoose and the dot okay inside of our user schema is where we'll have our data model so we need to think about the different types of data that a user needs to store let's go back to our user stories quickly and we can look at some of these points in here to see or get an idea of what data our user needs now of course we need a username and a password but let's talk about the rest let's look at number 13 for example it says users can be employees managers or admins so we also need user roles and then let's look at number nine and it says provide a way to remove employee access as soon as possible if needed and really we should switch this to user access and then underneath that number 10 says notes are assigned to specific employees that's true but employee refers to a role really so let's also say to specific users now this won't impact our data model for user but it will for notes but we just got the terminology defined a little bit better by switching employees to users there so what we do know is we need roles as we see here in number 13 and also for number nine provide a way to remove user access ASAP if needed let's give an active status and that means users might be assigned to different nodes and we wouldn't want to delete a user if they still had notes assigned to them so what we can do is disable a user by having an active status basically Boolean data if they're active true and if not false and that would allow the admin or manager to remove user access ASAP if needed okay with those changes made to the user story and we've gone over that a little now we're ready to Define our model so we'll say username that's the first thing we need and then this is an object as well and here we'll say type and this will be string type data and then we can say it is required and we set that to true now after that let's put a comma and then I'm just going to highlight this and do shift alt and the down arrow and I'm going to switch this to password and it's also string and also true now let's do that once again shift alt and the down arrow and we can put roles but now we'll make another change here let's wrap this object that we have in an array so we'll put our opening bracket and our closing bracket and now we're saying roles is an array and the data within the array will be string but instead of require shared let's put a default value and we'll have the default be employee so even if a role is not assigned in our front-end application as the request is sent to create a user it will assign the default role of employee now as an array this indicates that a user might have more than one role and more than one value could be stored of course in the array now we could copy this down one more time so let's do this again let's shift alt and the down arrow and here we'll have an active status let's go ahead and remove the array from around this we can remove that final comma because this would be our last one now the type here will be Boolean and then we'll have a default to true as we would create a new employee they should immediately be active without us even needing to send that data to the API this will just allow any new employee or I should say any new user created will automatically be active now before we finish with this file we need to come underneath the definition of our schema and just say module.exports set this equal to Mongoose dot model and then we name it user and then we pass in the user schema that we just created and now we should be finished with our user model and now we need to create a note model I am going to just Ctrl a to select everything in this file and Ctrl C to copy and then create a note JS with a capital N and I'm going to paste everything in from the user model and just make some changes but before we make those changes I guess I could make the first one just so we know we're working with the note model we'll change this user schema and I'll press Ctrl D to select the second instance of that and then I'll move to the front Arrow over four and change this to a note schema other than that let's see if we need to change anything else quickly just the name here of the model we can change to note and now as we come in and make changes to these different types of data we once again want to Refuge refer to the user stories let's look at 10 11 and 12. so notes are assigned to specific users so we know in this note model we need a reference back to the users and then notes have a ticket number title a note body you could say the text of the note and then created an updated dates and then notes are either open or completed so this is another status here we could basically say it's completed or not and if not it would be open so those are things to consider as we look at what data we want to store in the note so let's start out with a user because we know it needs to refer back to the users that we have now this data type is going to be just a little different than string or number or any normal type of day data that you would think of this is related to Mongoose so we'll say Mongoose dot schema so we're referring to the other schema we've created and we say types and we say object ID well we're not specifically referring to that other schema here but we're saying what type of data this is it's an object ID from a schema then required is true but one more comma after that and now we have a ref here now this is where we're referring exactly to which schema so this is referring back to that user schema that we created after that let's change password to title this would be type of string and true after that we could change this one let's call it text because it is the text of the note and this would be string and let's put required true again for that but we also need to remember to remove the array that is wrapped around this one as this was rolls in the one we copied from okay after we get text oh I've got an extra quote there okay after the text now we have the completed and this is a Boolean again but the default will be false because when we create any new note it will be open and not completed so we needed the opposite right there now those are our basic data types but notice it's not all of the data types we needed we also said we needed dates both created at an updated at and we need a ticket number so there's some other things we're going to do for those types of data I'm going to move the curly brace off this Top Line likewise off this bottom line because for the time stamps we need to add that is an option so I'll put that on a separate line and then inside of here we can just say time stamps and set that to true and mongodb will actually give us both created at and updated at timestamps just by setting this option and when I save you'll see it gets formatted just a little differently but this is easier for me to read to know that this is one object and then this option here is another object so now we have everything except our ticket number that we need for the note and really there will be an automatic object ID created with every record and that's what we're referencing here for the user and the note will have one too but as you may see this as we work through the DB object IDs are very long strings and it wouldn't be too practical to use that for a ticket number and in fact what our owner Dan D wants is a sequential ticket number now he doesn't want it to start at zero because that makes it seem like his shop just opened up so he said started at 500 or higher and that's what we'll do but then every note created will be in a sequence of ticket numbers we can do that once again by installing a package that will help us so let's go back to package Json so we can see it installed and control and back tick and then let's say npmi Mongoose Dash sequence and this will install and then it will help us issue those ticket numbers in a sequence okay we know we have the dependency now so now let's go back to the note JS model and at the top of the file we're going to Define Auto increment and we're going to set this equal to require Mongoose Dash sequence and then after that we need to follow it with another set of parentheses and pass Mongoose in I know that looks different than some requires you may have seen but that is what is documented for this package okay now we'll scroll down to where we have created our schema here already so right after the schema we need to say note schema dot plugin and then we pass in Auto increment put a comma curly brace and we set some options for this so now we tell it what the increment field is going to be named and we're going to name it ticket this will create a ticket field inside of our note schema and that will get the sequential number this also gets an ID called ticket Noms we won't see this inside of our notes collection what will happen is a separate collection named counter will be created and we'll see that ID inside of the counter collection and then we need to tell it what number to start the tickets at so we'll say start sequence which is just seq for this option and we'll tell it to start at 500. now that's all we need to do and once we start creating notes this plugin for auto increment that we're using from Mongoose sequence will create a separate collection called counter where it tracks this sequential number and continues to insert it into our nodes we have now created our models and we have our connection string inside the dot EnV file so we are now ready to create our connection to mongodb let's go to the file tree and the config folder and let's create a new file in the config folder and I'm going to call this DB and then a capital c o n n so databaseconnection dot JS we'll start here by requiring Mongoose once again so we'll say const Mongoose require mongoose after we do that we'll just Define a function called connect DB this will be an async function and inside this async function we'll have a try catch inside the try we'll await Mongoose dot connect and then we just pass in that environment variable so process EnV dot database underscore u r i and then we'll have our catch and here we'll just catch the air and then we'll console.log the error that just should be err there we go after that we can do the module.exports set this equal to connect DB now we're ready to go back to the server.js and we'll start here at the top with a few more Imports we need to import connect DB that we just created so this will equal require and then we'll be looking at the config folder and then we should be able to look at dbcon there it is we'll also need to require Mongoose here so we'll say const Mongoose equals require and get Mongoose there it is and then after that I want to go ahead and bring in that log events function that we have inside of our logger file so this will equal require and then it's inside of our middleware folder and then it's inside of logger so now we have our three Imports we're ready to apply these to our server.js we don't have to scroll far let's just go right under this console log where we log the node EnV value and let's call this connect database function and then we can scroll all the way to the bottom where we're listening for the port and saying the server is running on Port and providing the number we're going to wrap this in a listener for the Mongoose connection so here we can say Mongoose dot connection dot once and we'll listen for the open event and then this has a callback function and we'll put our app.listen right inside of here and then we can put another statement as well so first I'll paste this one in but also let's go ahead and console.log connected to mongodb now I'm going to scroll for just a little more room and we can put one other listener here so this will be Mongoose dot connection dot on instead of once and we'll listen for an error so if there's an error with our connection then we'll pass the error into this callback and then we could console.log whatever the error is but let's also use our log events and I'm going to paste this in once again just so I don't have typos it's a template literal and it just always creates some typos as I try to type them out so I'll spare you that but what we can get from this is the error number the error code the error system call and the error host name all of that should be provided through a mongodb error and then we can create a new file called error log dot log and I'll save the file here now one way you could test this is to go ahead and stop your internet connection and then start this server remember you would type npm run Dev and you should get an error here I believe it doesn't provide an error number so it'll only do that if it's available it might say undefined there but I have tested that out and you get everything else written in your error log and the log will appear in your logs folder as expected now we're going to test out all of our user models we created and everything about our mongodb connection as soon as we create controllers to process the rest of the crud events the request will get the create read update and delete so that is coming up next for now let's just open up a terminal once again type npm run Dev and we'll make sure our mongodb connection is working as expected starting the node server we've got development from our environment variables it says connected to mongodb and the server is still running on Port 3500 everything is good to go our starter code today is the completed code for lesson three and that's available in the course resources for download or for cloning in git and what I'm going to do here inside of the package Json now is change lesson three to Lesson Four and save the file and that's all we need to do no new dependencies right now let's go to the server.js file and we'll start by adding some routing for the user model we created a user model and a note model in the previous tutorial and now we need to create routing and controllers for both of those so we're going to start with the user model today I'm going to scroll down where we already have some routing and you can see we are routing to the root file and that is how we display that index page when we go to our local host and then Port 3500 which we've done in previous tutorials so now just underneath this I'm going to have another app use so app dot use and then I'm going to say slash users so this would be the end point and if the request goes to this route we're going to then require and then we're going to look inside of the routes folder as we do with the one above then I'm going to look for user routes which does not exist right now so let's go ahead and go to the routes directory and we can add this user routes JS file so it's user with lowercase and then routes with a capital r dot JS now if we look at the previous file that we had inside of routes which is root.js we can see we required Express and then created a router from Express router we will not need the path but we do need these first two so I'm just going to copy them and then go to the user routes file and paste these in after this we can do some preliminary setup here so I'm going to say router dot route and now this will match the slash users so now we're saying we're already at slash users and now this is just the root of that and we can chain different methods here so what we're going to do is first say dot get so any get request that comes to our rest API at slash users and then we would have a response we would put in here which will direct to a controller but we're not going to provide that yet because we haven't created it so we're also going to look for a post method and we could have a different controller or response for that and then we could say patch this would be related to update so if you're matching these up to crud git would be the read post would be the create patch would be the update and then we'll have a delete method notice how all of these are truly chained together we could put them in one line but then once we started to insert our controller functions here inside the parentheses that would become difficult so I'd rather have them all on individual lines after this we just need to put module.exports and we're going to say equals router at the end of this and we'll save this us for now now currently this won't do anything so we need to create our user controller so now in the file tray let's make sure we're at the top level and let's create another directory and we'll call this directory controllers inside of this directory we'll create a new file and we'll call this users controller.js notice the lowercase and then the capital c on controller we need to require the user model at the top of the file so we'll say user equals require and now we'll come up out of this folder and look in the models folder and then we'll find our user model and then I'm just going to copy this down with shift alt and the down arrow because we need to do the same for the note model even though this is the user controller we may have to refer to the note model at some point inside of this controller so we need both of those and then I'm going to save because now we do need a couple of new dependencies so let's go back to the package Json and I'll scroll so we can see our dependency list here I'm going to open up the terminal window and pull it down so we can once again see our dependency list and now we have two dependencies so I'm going to type npm I express dash async dash Handler and then we also need B Crypt and we can install both of those on the same line just like that and it shouldn't take them long to install and we should see them both in our list of dependencies so here we have Express async Handler and then at the top we have bcrypt because these are listed in alphabetical order so now let's go back to our user's controller file and underneath the models that we have required let's bring in these other dependencies so let's say const async Handler and we'll set that equal to require and this will be the express dash async dash Handler and then we'll say const be Crypt and we'll set this equal to require decrypt and we'll need that to Hash the password before we save it because we don't want to just save a plain text password inside of any database and the async Handler will keep us from using so many try catch blocks as we use async methods with Mongoose to save data or delete data or even find data from mongodb and now we can create our controller functions and it is common to label those with comments so I'm going to paste in the first label and we'll follow this pattern for each controller function but it has a description and the description of this function will be to get all of the users the route will be slash users and the method will begin and the access to this route will eventually be private but we're not setting up any authorization right now we just want to get the rest API up and running so we can create the front end and then we'll come back and lock it all down later so we'll say Advanced get all users and we'll set that equal to a function that is async and we'll have a request and a response notice no next the controller here should be the end of the line essentially where we're processing the final data and we're sending a response back and after we do that we have to consider something else the async Handler that will keep us from using the try catch block and still catch those async errors needs to be wrapped around this function so then we'll say async Handler and we'll put a parenthesis there and a parenthesis at the end notice we haven't created the function yet but I'm just going to leave it like this I'm going to highlight this function even though it's empty and do shift alt in the down arrow to create another one and now we'll create our post so this instead of get all users will be to create a new user or just create new user to keep it brief and this will be the post method at the same endpoint slash users it will also be private so let's call this create and get lowercase here new user and it will also have the async Handler wrapped around it so that's good enough to start out there I'll once again highlight this do shift alt and the down arrow and give another space let me scroll for just a little bit of room and this will be to update a user so we'll say update user or I'll say a user and then this will be the patch method and it will still go to that same user's endpoint and it will still be private so now let's just change this to update user and now one more time I will highlight all of this shift alt and the down arrow give a space and this will be to delete a user this will be the delete method it will still go to the same user's endpoint and now we can change this to delete user and then we have our module exports at the very end so I'll come down a couple of lines and type module.exports we'll set this equal to an object that will contain all of these functions so we'll have get all users and then we'll have create new user then we'll have update user and finally we'll have delete user and now all that is left is to actually create the logic inside of all of these functions but before we do that we can go back and complete our routes so let's go back to the user routes.js inside user routes let's import our user's controller so we'll say const users controller set that equal to require then two dots to come up out of this folder we'll look in the controllers folder and then inside of the controllers folder we have a user's controller and I should have just pressed tab right there so I wouldn't have to type it but there we go user's controller now that we have the user's controller I'm just going to copy that user's controller highlight these parentheses here at the end Ctrl D to select all four of them arrow to the end and then one to the left to be in the middle and paste and I've got the user's controller now inside of each method and now individually here we can use dot notation to pull in these methods the functions that we created inside of the user's controller so this will be dot get all users and we can see that right there and then we'll have dot create new user and then we'll have dot update user and finally we'll have dot delete user and now our routing is complete and it's pointing to the correct method inside the user's controller for each one of these HTTP methods that could come into this user's route so let's go back to the user's controller and make sure we're scrolled to the top and now we'll start putting the logic inside of each one of these methods inside of get all users I'll start by defining users and then we will await and then we'll take our user model and call the find method and after the find method we can chain a select here where we're actually going to say please do not return the password with the rest of the user data there's never a reason to send the password back to the client after that we also want to chain the lean method otherwise would actually give us or mongoose I should say would actually give us a full document that has methods including the save method and others attached to it which is more than we need lean will tell it to basically give us data that's like Json and it won't have all of those extras and especially when we're just getting the data and we're not going to call a save method or need that that's the way to go okay so then we need to check to see if we have users so we'll say if we do not have users then we're going to return a response and that status is going to be 400 and then I'm going to chain Json here and give a message and then say no users found we could use an else here and then not use the return because then we wouldn't have to say that's the end of the function but I'm not using an L so just after this I'll say response dot Json and there I'll send the users if we have the user another thing to note about this is if you have larger functions and several responses I believe adding the return statement here is a little bit more of a safety feature otherwise you could get an error about client headers already being set or something like that and so I like to add the returns then of course at the end the final one you don't really need to and some may prefer not to do that but you could get in a bit of a problem with your logic if you don't literally end the function with a return statement okay moving on to the next function we have create new user this is going to take a little more space so I'm going to scroll it right up to the Top If possible and when we create a new user we'll be receiving some data from the front end so let's destructure that data from the request body we'll get a username a password and a roles array is what we should be receiving so we'll have to confirm all of that we'll have request.body we did set a default value for roles to have an array with an employee but really we want to make sure they're set so let's start out by confirming data I'll say confirm data here and now we'll say if there is no username or there is no password or let's use the array dot is array method and pass in roles so if roles is not an array that's an issue or we could say if roles doesn't have any length so it's an array but it doesn't have anything inside any one of those should cause us to reject what we have received so then we want to say return response status 400 which is a bad request and then we'll say Json and have a message and we'll say all fields are required now these are specific responses we are sending back for specific situations if there are other errors inside of any one of these functions then the error handling will take place and our async error Handler should kick that out and it will go to our error handling middleware that we already have but we don't always want that to be the case sometimes when we know we might get a specific response we want to send that back and we'll be able to show a message like all fields are required inside of our front-end application that will actually help the user and now we need to check for duplicates so we'll say check for duplicate because we don't want to have two users with the same name so here we'll say const duplicate and we'll set this equal to a weight and here's our user model now we'll use find one because we're passing in a username that we have received above as one of the things we received in the request body and now after this we need to use lean again because we're not going to call Save on this duplicate or any of the other methods but then we also need to call exec and Mongoose really says if you're passing something in not like we did with find above let's look in this other one here find we didn't Call Exec but we didn't pass anything in and that's what I see in their documentation but they're saying if you're using async await and want to receive a promise back you really need to call exec here at the end I do think it may work without it but you do not get the error reporting either and we could Google some more on that I have read a couple of stack Overflow reports as well just to see what others were thinking along those lines but I'm following the documentation especially if there is any doubt so that's what I'm looking at there once we have the exec added we can say if we have a duplicate it if that's what we receive if it finds one then we're going to return response status 409 which stands for conflict then we'll have Json and this message will say duplicate username which could also be very useful for our users okay we're already getting close to the bottom of the page I'm going to scroll up so we have some more room and now we need to Hash the password that we have received so let's say const hashed password we're going to set this equal to a weight and then use B Crypt that we have imported say hash and now we'll pass in the password that we received from the request body and we'll add 10 salt rounds to that and you could look at the documentation for bcrypt if you're interested in that but I can just put here as a note salt rounds that's what those are and that's when it hashes the password so I couldn't look at the database and know what your password is if I was the administrator this keeps passwords secure even in the database even when they're seen you won't know what the password is without decrypting it so that's also very useful now let's define our user object before we save it and let's set this equal to an object that has the username now we don't have to say username username since the field in the database and the variable is the same this is just like de-structuring we can just say username but now I do need to say password and I'm going to set this to the hashed password and then we'll pass in roles which is the same name so just like username okay after we've created that user object we're then ready to create and store the new user so let me put that note in here create and store new user and we'll say const user equals await user dot create and we pass in the user object that we just created now we can say if we have a user so we've received that back which means it was created then we can do something here or we could have an else afterwards if not so we'll say response dot status 201 notice I'm not using a return because I know I'm at the end here and I'm going to use an if else instead so message and then I'm going to use a template literal say new user pass in the username value create it and then after this we'll have an else and here we'll say response status 400 dot Json a message and here we'll say invalid user data received so that did not save and we can save that and we should be finished now with our create new user function now let's scroll up and add our Logic for the update user function it's going to have some similar logic to the create new user function that we have but it's not the same and it's not identical to where I wanted to create Little Helper functions along the way so you'll just see some logic that is almost the same first we're going to bring in a little more data with this so we'll be receiving an ID a username rolls an active status and possibly a password all from the request dot body after that let's once again confirm data but we've got just a little more data to confirm as well so we'll have if there is no ID or there is no username or there is no array with our array Dot his array and we pass in the roles or the roles dot length is not there or we have one more type of active which is the active status now we'll say not equal to Boolean I'm going to press alt Z to wrap this code as well so now we've checked all of the data and if it doesn't check out we will return res status and set that to 400 which is bad request then we'll have our message that once again says all fields are required let's hit return a couple of times and Define our user we'll set our user equal to a weight user dot find by ID and now we'll pass in the ID and we need to call exec at the end of this because we are passing in a value here and we do need to receive that promise after that it we're also not calling lean because we need this to be a mongoose document that does have save and the other methods attached to it so now that we are checking the user we can once again say if we do not have a user then we have a return response status 400 Json and our message is going to be user not found okay after the user I'm going to scroll up for some more room we're once again going to check for a duplicate but the logic is a little different so here's our check for duplicate we'll start out by defining our duplicate set this equal to a weight user dot find one and we're passing in the username and then after that we need to go ahead and chain lean as we do not need the methods returned with this and we'll chain exec as well and then let me put another note here because this is where the logic is different we want to allow updates to the original user so if we just look for duplicates and didn't allow an update at that point it would also catch the current user we're working with so we need to avoid that so we'll say if duplicate and duplicate I'll use optional chain in here and use underscore ID which is the ID that's created by mongodb now we'll send that to Strings we'll call the tostring method and if it is not equal to the ID that was received as a variable in the request body then we have a duplicate but if it is equal to that ID that means we're just working on the same current user so we didn't find a duplicate we found the user that we're working with so now let's say return response status 409 Json with our message and here this would be duplicate username so we're trying to change a username to something else that already exists and we do not want that now we're ready to update our user object with some of the information we have received so we can say user.username we'll set this equal to username user.rolls we'll set this equal to roles and user.active should be equal to active note that since this is a mongoose document if we tried to set a property that didn't exist in our model it would reject it so we can only do this with properties that already exist in our model now notice we didn't update a password because we don't want to require someone to always send in a password update when they update something else so here we're just going to say if we have a password then we can go ahead and update that password and we're going to do that by hashing the password again so I'll say hash password and here this will be user dot password is going to equal a weight bcrypt dot hash like we've seen before pass in the password and give it 10 salt rounds again and I'll put that note here once again that those are salt rounds and you can look in the docs for more details if you're curious about bcrypt I need to scroll for just a little more room but we're almost finished we just need to say const updated user equals a weight user dot save and this is where we absolutely needed that document because if we requested the lean data in return we would not receive that save method that we could call right there and then of course if there is a problem with that this will be caught by the async Handler even though we didn't use a try catch now after that we can send a response so response to Json and then our message and inside of our message we'll use a template literal and here we'll say updated user dot username and then we'll say updated and we should be finished with our update user function we are ready for the final function which is delete user and this should seem fairly easy compared to the last two however it's still got a little bit we're only going to destructure the ID from the request body that's all we really need to reference a user and delete that user so we'll say if there is no ID then we'll have that similar response so return response dot status 400 which is bad request Json a message and this message is user ID required instead of all data is required I could spell required to be better off and now we need to use the notes model because we do not want to delete a user if they have notes assigned to the specific user so let's check the notes so we'll say const notes equals await note we've already imported that above and we'll call find one again and now here each note in the note model has a user so we'll pass in the ID which should match that user ID and then we need lean as we won't be calling any methods and we need exec at the end after that we'll say if the notes and I will use optional chain in here have length then we'll go ahead and return response.status 400 for bad request Json and the message that could help our users which would be user I need a capital u there user has assigned notes so we do not want to delete that user if notes are assigned to the user okay after that let's define our user and we'll set that equal to a weight user dot find by ID that we've received and we'll Call Exec after that because we do need those other functions and we're going to actually delete instead of save this time but we'll say if there is no user then we need to send another response so return response status 400 Json and now our message will be user not found but then if there is a user is where we will be after this let's go ahead and Define a result and this result will actually receive the full user object that is deleted and here we'll just say await user dot delete one and when we do that the user will be deleted but the result will hold the deleted users information so now we can define a reply instead of sending all of that deleted user's information which we could do I'll just create this reply and I'll use a template literal for that and I'll say username here we can say result dot username after that let's say with ID and then pass in result dot underscore ID and then we could just say deleted so we have a message to send back and now we'll just say response.json and we'll send our reply and that should finish out our delete function with our controller functions completed we now need to test them and I'm going to do that with Postman so we'll go to thepostman.com website I'm here at postman.com downloads and here you can download the postman app Postman lets us test each endpoint of our rest API and see the results without having a full front end which can be very handy so if you do not have it go ahead and download and install Postman and we'll come back and I will walk you through testing the endpoints that we just created okay back in Visual Studio code I need to go ahead and start the development server so I'm going to type npm run Dev and we should see everything start up and it should say it's running on Port 3500 and we're connected to mongodb with our Dev server running I now have Postman open and we can click the plus symbol at the top to create a new workspace I'm also going to press Ctrl and the plus symbol a couple of times to get a larger font on the screen as Postman defaults to a smaller font and what we need to do is put in our Dev URL at the top so I'm going to put in localhost and you can see it actually remembers what I've had in here before so we want localhost Port 3500 and then the user's endpoint now our user's endpoint has several possibilities because we get different responses from each HTTP method that we send so we have git post we're also going to send patch and delete and we need to check out every possibility and if we get a response that we don't expect then we know we need to fix something in our code and I'll give you an example of that right now we're at the get users endpoint so we're going to send a request to users and it's a get request and it should return all of the users but we don't currently have any users but I'm going to go ahead and send this request and we get an empty array that was not what I expected so let's fix that we need to look in our code and let's look at the get all users function that we have inside of our users controller now I'm going to close the terminal because it will continue to run even if we have closed the terminal and now what we expected was this response here no users found but we had this happen it sent the users anyway and it was just an empty array so what we really need to check here is if the users have any length and by using optional chaining we can first make sure that the users exist before we check the length property so now let's save these changes and let's check that request again with Postman so I'll send that request and now we get the response we expected so now we'd like to also make sure this can return users but before we can do that we need to create a user so let's check our post for the same endpoint and now we'll need to send some data and create a user so to do that we need to go to the headers first and let's add a header here in Postman that is content Dash type and this will tell the server that we are sending application slash Json type data so after we've added that let's go to the body Tab and let's choose raw so we can just send some raw Json here so we'll have curly braces then we need to put quotes around the properties here and we have a username I'm just going to say Hank after that we have a password and remember this will be a plain text password here but after the server gets it it will encrypt it so I'll put in a basic password and we should also have roles and roles is expected to be an array and then there are string data inside the array so with these three pieces of data we should be able to create a user for Hank at the user's endpoint with a post request let's go ahead and send that and it says new user Hank created great so now we can go back and check our get request for all the users and let's see if we get Hank's information back and we do so you can see what was sent back notice the password is not here as we told our code not to send the password back so that also is working correctly let's see what else we need to check inside of Visual Studio code so for our get all users we've already checked when no users are found and now we've checked a response that sends any users that exist so that's good let's move on to our create new user endpoint and we made sure that it actually created a user but now let's check if some of these other things happen so we need to try it out without some of this data to see if we get the all Fields a required message we also need to try it out with duplicate data which means we need to create another user and try to or at least try to create one with the same name so those are two possible responses and then what else might happen Okay we might just create a user as we have or if there was invalid data and we could also just check to see if our async handlers working by sending some malformed Json as well so I think we'll be able to check everything except maybe the invalid user data because we're already checking some of that before so let's pull Postman up once again and let's first check the duplicate so we've already got a username Hank let's just try to create another one at the post method or at the user's endpoint with the post method so I'll send this and we've got the duplicate username response so that's good so if we change this to Dave we won't have that problem but let's go ahead and remove the username from the request and now send the request and now it says all fields are required we could also verify that by removing a different one such as the password if we put it back and maybe we remove roles and let's try sending that now we have an unexpected token so this checked our async Handler because we had an extra comma here that it didn't expect since it was the last one so let's delete that comma we know our async Handler is working and our error handler was past this and sent it back to us now let's send this request it still says all fields are required let's put the comma back and we'll put our roles back but we'll change the type of data let's say it's an empty array and let's see if we catch that issue as well and there we go let me send this all fields are required is what it still says so now what if it was just string data and not an empty array so it didn't have the right data type all fields are still required so I'm going to minimize Postman again and we'll once again look at our code we checked the all fields are required we check the duplicate username we definitely know we can create a user and I couldn't think of any invalid user data to send that would get past the other checks but if you think of something go ahead and try that and of course we also made sure our async handler was catching errors and it sent it on to the error Handler for the entire server so now we're ready to check the update user method again we have all fields are required so we need to check all of our data to make sure our confirmed data logic is correct and then we also need to check the possibility of a user not being found when we're trying to update the user and then we'll need to check for a duplicate but we can't check for the same user that we're already working on because we want to be able to update that and that's what we set our logic to so we'll actually want to create another user and then try to change their name to Hank's name and as I scroll down let's see if there's anything else to check nope now we should just be successful and send the response back so we're checking for duplicates eventually but also user not found and all Fields required I'll pull Postman back up we'll now go to the get because I want to get all of the data that we have for Hank first so we can just put that up above and if we provide extra data it won't hurt anything because we're only destructuring the data that we need when we send the request and that's what the server is doing actually those different controller methods we're destructuring the data so now I'm providing the ID so we can update Hank but let's change one of the numbers here instead of this number nine let's change it to a 1 and then we'll try to send the patch request which would be the update and let's see what happens user not found well that's what we expected great so now let's remove the active that should be required and let's see what happens all fields are required so that worked out as expected as well now this other logic was what we already had in there previously as well so we had checked that with the other endpoints so that should be good but let's see if we don't Supply an ID because we didn't have that before nope it still says all fields are required so just to confirm I'll go back to the get and send and I'll get Hank's number again which I think I just changed the 9 to a one but I wanted to make sure I had that same one now let's make sure the update actually works and I'll just change active to false for Hank so I'll come back to patch and we'll send this and now Hank was updated so when we go back to git and send our request we can now see that Hank's active status is set to false and so now I need to create another user before I can try to rename and test the duplicate reactions so what we're going to do now is go to the Post request and I'm going to change Hank's name to my name first and we'll create a new user so this should work and it says all fields are required what are we missing oh yeah we didn't have a password because we didn't send a password along for the update so let's just go ahead and add a password here as well and I'll make it the same as Hanks too as that won't hurt anything and now I'll send the information for our new user and new user Dave is created so now if we look at the users we should see that we have both Hank and Dave available here in our response so I'm going to copy Dave's information and then pull the response back down put Dave's information up here remember we'll need to change this underscore ID to an ID and now we're going to do a patch and I'm going to try to change Dave's name to Hank now remember we already have another user named Hank so let's see what we get duplicate username so that worked out just great now let's minimize Postman one more time and look at the logic for our delete method our delete user here and so we just have to send an ID and if there's no ID we should get a user ID required likewise we're going to look for notes now this is something we can't check and as I'm looking at this a second time I think this needs to be changed lowercase we're really only looking for one note first of all so this is lowercase and our model is uppercase so they're not the same thing even if they both say note the second thing is this probably won't return an array we're using find one here so I don't think that's what we want if it doesn't find anything it will be null so we'll be checking that otherwise it will have a note so a nice little code review there now we also might get a user not found if we send an ID that doesn't exist but we can't check this user has assigned notes now we'll have to wait until we create the notes controller so we're really just going to check to see if the user ID is required or the user is not found and then we're going to make sure it can delete a user as well it looks like I need to save that change and node mon will restart our server and now I'll pull Postman back up and let's go to the delete method for the same user's endpoint and now we're going to send some information and remember this is actually user Dave we tried to change the name so let's not send the actual ID first I'll change this 5 to a 1 and let's see if it can find a user user not found great so now let's try it without a user ID at all user ID is required that's what was expected as well now let's put in the accurate user ID I'll change that back to a 5 and when I send username Dave with that ID was deleted so now let's go to the get request get all of our users and we still have Hank here so let's go ahead and delete Hank as well and our database will be empty once again we'll pull this back send oh that's the get request we'll pull this back and go to delete send the delete request and now Hank is also deleted so when we check the get request we have no users found and before you move forward with your controllers and the logic you have created for each function inside there they would be the methods of the controller you want to make sure you test every possible response that you expect to get and then also check your error handling and that's what we have done for the user's controller and now I'll minimize Postman one more time and we're back at Visual Studio code now we still have a notes controller to create and you have followed me for this process starting in the server.js where we created the route for the users and then we went to the routes directory and we created user routes JS and then we created the controllers directory and we added the user's controller JS that has all of these different methods inside of it so now I think it's a good time to issue a student challenge because we need to do all of this for the note model as well so we'll have our notes endpoint and we'll have all of the associated controller methods with it and of course the routing needs to be put in place I will leave that to you I will provide my code inside of the course resources for this lesson so if you want to check back but I think it will be a great logic exercise and don't expect to be perfect there's no pressure just do the best you can and then of course you can check your code with mine in the course resources a quick look at today's starter code we have a new git repository and that's because we're building the front end now so lessons one through four the repository for those lessons has the back end code that has node.js Express and mongodb that's the rest API now we're talking full stack so not only do we have the back end but we also have the front end and that is built with react and what you see in the package Json is that I have named this lesson zero five with a dash front end now today we'll only have front-end code but if we ever have a lesson that has back end and front end I will make sure to note on each directory which is the front end and which is the back end now you can see I've already started a react app with npx create react app and I've removed all of the things we don't usually use so the extra dependencies are gone you'll also see in the source folder the extra files are removed and I'm back with an index.js and an app.js and I have an index.css now I have supplied some CSS already this is not a tutorial on CSS you can apply what you want to or you can use mine but I'm really focused on the structure of the myrn stack and building the logic throughout and today we'll be focused on react other than that I've also supplied an image folder we only have one image and it's a background image you can see that right here somebody's working on some technology and that's just what we'll use for Dandy's repair shop as the background I've also supplied this same folder inside of the public directory so there's no issue with you linking to it from the CSS which is where I do that and I only apply that background to the body element which is not something we access through react normally anyway so that should handle that now let's take a look at the user stories that we have previously looked at a few times and these are the notes that I took from DND our stakeholder the owner of the repair shop that we're building this project for now we haven't completed any yet because we've only completed the back end so we cannot fully say that any of these goals are met however today we should be able to complete a couple of these goals just some basic ones like add a public facing page with basic contact info we should also be able to provide a welcome page after the login now we could say that is complete or we could wait until we complete the login portion we're first building this burn stack with full access and just making sure everything works the way we want it to before we apply the user roles and that authentication and authorization we'll do that after we get everything else working let's head back to the package Json and we have several decisions to make today I'm going to open up a terminal window and we'll get ready to install a package but first let me discuss these decisions we need to talk about the state management of the app the file structure and the routing structure as we begin to create this application those are things you need to decide early on even though we won't apply the State Management today we're going to use Redux and rtk query for this application I've had many requests for that it's not a huge application but it is one that will be used for business purposes and I think it will allow this application to grow if Dandy comes back to us and wants us to keep adding features to it the other thing we'll do is apply the Redux file structure that you have seen in my previous Redux tutorials and that's also what's in their documentation with their examples and so it will be based on features and now the routing structure we're going to use react router so let's go ahead and install that dependency we'll just write npm I and then react Dash router Dash Dom and press enter it should add fairly quickly I'll drag this down so we can see it in our dependencies and there it is let's close the terminal window and go to index.js here we need to go ahead and remove this report web vitals that I forgot to remove before but other than that we can go ahead and import what we need from react router Doms so we will import and we need browser router we also need routes and we also need route now that we have those let's go ahead and delete this web vitals part down here as well and then inside of the root.render we can start to apply what we have imported so I'm going to delete the app component for now and just start with browser router and after we add that you can see I automatically get the closing part of that tag then inside of the browser router I'm going to press tab to come over and then I need to use routes and then inside of the routes I'm going to put a specific out I'm going to assign the path to a slash and an asterisk which will allow us to have nested routes then I'm going to set the element and here is where we bring our app component back close out the app there and then we need to go ahead and close out the route tag itself so you can see we have browser router nested within that we have routes and then we apply a specific route that will allow nested routes as we move on to the app.js so we can save here as we are now finished with the index.js and we go to the app.js in the app.js we can remove these Imports as they were the default from create react app and we can really remove everything here inside of the return as well so just inside of the div with the class name app will remove all of that let's start at the top of the file now and we will import routes and Route once again and both of those will come from react router Dom now let's leave this as is for a moment and let's create inside of the source directory a new directory called components and inside of this components directory let's create a new file and I'll name this layout.js now I'm going to import outlet from react router Dom [Music] and after we get that imported we can go ahead and just type rafce at least if you have react es7 Snippets extension like I do and press tab if not you'll need to type that out but once you have the basic layout here we can remove everything after the return and then we can just provide Outlet so all this does is render the children of the outlet component and we're going to make this our parent component the nice thing about having the layout component here is if we decide to add a banner that would go across the entire application throughout or a footer or anything like that that we would want to show on both the public and the private pages I mean on everything that shows in the application we could do it here so this gives us kind of one parent where we can add extra things if we need to so let's go ahead and save our layout JS now let's go back to the app.js and we'll start by importing the layout that we created so layout and that comes from the components layout after that inside of the return let's go ahead and put in a route and then inside of that we'll put in a specific route and this will be the parent of everything else essentially that we have underneath it so here we'll just have the root and then we'll say element equals and then we'll put in our layout but we will not close this out like you saw in the index we will make this a route with a closing route tag and now we can put everything else inside of this and the layout will be the parent now let's go back to the components directory and we'll create another file there and I'm just going to name this public this will be our public facing page for Dandy's repair shop and inside of this we're going to need a link from react router so we'll import that from react router Dom and after that let's once again use our rafce shortcut and create a public function I'm just going to highlight everything here inside of the component and I'm going to paste in a basic web page essentially here you can see I'm creating a Content variable and then I'm returning that content with the functional component and you can see it's inside of a section with the class name public you'll want that to match up to my CSS if you're using my CSS and then inside of this section we have a full structure a header a main element and a footer you can see the footer is going to link to a login page after that the main section here the main element has all of the information about Dandy's repairs and the header has a welcome now of course you'll want these class names to match my CSS I'm using a bem naming convention for some some of these or if it's a utility class like no rap just has its own name there so just note that if you're using mine but feel free to create your own as well I have no problem with that as this does not really apply to the logic of the rest of the stack but it does meet one of our user stories so that's important we can come back to the app.js now and we can import this so import public and that's going to come from the components and then the public and once we have that we can put it inside of this route so this is going to be another route and then we can assign it a value as well and this value is going to be index and that means when you come to this root path it's not showing a layout layout just renders the children so this will be the default component that it shows so here we'll say element equals and we'll provide the public component that we created now let's go ahead and close this route out now after this we also noticed public links to a login component so let's save the app.js go back and create a quick login component we're not going to handle all of the login logic today and all of those roles and authorization and things like that but in this hierarchy this will at least let us create this page and import it into the app.js so I'll use my es7 shortcut again to create that functional component once we have the login here I'm only going going to change the div to an H1 just my preference again and save that now let's go back to the app.js make that import as well so import login it comes from components login and then we can use it right under our public here so we'll have route this will not be the index though so we'll just say path equals login and then we have to provide the element so that's going to equal that login component here and let's close this one out as well now let's create another component and I'm going to call this one dash layout so this will be part of the dash after a user has logged in so one of Dan's employees or Dan himself will have logged in and then we'll have our Dash layout so I'll use rafce once again to create a quick functional component and now we can make some changes let's start with an import at the top and we're going to import Outlet once again from react router Dom and once we have that imported then inside of the dash layout we're going to set some things a little differently I'm going to use a fragment because I know I'm going to need it to Nest some things inside and once I've done that I'm going to start with a div and this div is going to have a class name so I'll come back and add class name and set this equal to dash dash container and then inside of this Dash container we can provide the outlet so now we have wrapped this in a div so we can apply different styles to our area that will be required to have a log into I guess our protected area you could say we could apply different styles as we now have that in a container and all of the children will be within that we're also going to use a dash header and a Dash footer but we haven't created those yet so let's start with the dash header and I'll create that component over here as well Dash header.js and now I'll use rafce to quickly get that functional component again and at the top we're going to need to import in a link here so let's import link and that once comes from react router Dom after we have the link let's go ahead and add the body here to the component I'll once again highlight this return and replace it and we can go over this it's fairly simple content here we have a header as the container inside of this we have a div with the class name Dash header two underscores container and then we have a link to dash notes this is linking the H1 that we see here that says Tech notes which is the name of the application and then we have a nav element that we know we will fill later with navigation buttons but we're not adding those right now that is the basic structure of our Dash header so we can save that file and now let's once again go back not to the app.js I guess but back to the dash layout and here we'll import the dash header there it is in my list and once we have that we can put it right here inside of the jsx so we say Dash header and just close it out there now this is an example as I mentioned with the previous layout this has the children here so now the dash header will be above every page on the protected part of our site so this is the layout component for that protected part of the site and now we'll be able to add a dash footer down here too that we won't see on the public page but once we make it to the dash part of the page which is the protected part we'll begin to see that header and the footer after we create it before we create the dash footer let's go back to the package Json as we need to add a few dependencies for font awesome so I'm just going to press Ctrl back tick to open up the terminal window and then I'm going to type npm I and I'm going to paste in the first part which is at Fort awesome not font awesome but Fort awesome and then it is font awesome Dash SVG Dash core is the first dependency but we have two others that I'll just put all on this same line it will once again start with at Ford awesome then it is free Dash solid Dash SVG Dash icons and then finally one more that starts with at Fort awesome and it will be react Dash font awesome with those three all on the same line I'll press enter and they should install into our dependencies and then we'll be able to use Font awesome components inside of our project and now you can see all three of these listed up here if you didn't catch that when I listed them out on the line below pause and install those if you need to and then come back to the video I'm going to close the terminal window and back in the components directory I am going to create the dash footer component so we'll start with Dash footer.js press enter rafce for a functional component but we've got some more work to do inside of this component so let's start out with the basics inside of the component I'm going to Define my content I'm going to set that equal to a footer element and then inside of the footer element I guess I should apply the class name while I'm here so class name is going to equal dash dash footer and then inside of this element our user stories said they wanted to see the current user in status and I think the footer would be a good place to have this available throughout the entire application so I'll just put a paragraph here that has current user and when we start working with State we'll be able to bring in that user and then I'm also going to put another paragraph here that has status and the same we'll be able to bring in the current status once we start working with the state as well now there's some other things we want to add to this footer though so now let's go to the top oh we're not returning it yet I need to put the return of the content here so we'll just get rid of that and say content now let's go to the top and we'll say import and we're going to bring in font awesome icon there you can see that full import after that we're going to import fa house from well it's Fort awesome slash free solid SVG icons and once we've imported that we need a couple of things from react router too we'll say import use navigate and we'll also say use location those will come from react router Dom with those Imports all in place we can now start adding some to our component I'm going to start with const navigate set that equal to use navigate from react router and then I'm also going to de-structure path name from our use location hook that we imported now that I have those values I'm going to create a simple function here called ongo home clicked let's set this equal to an anonymous function and then it will be navigate slash and then we'll have our Dash after this function let's create the button that's going to use it I'm going to start with let and I'll say go home button and it's just going to equal null but now we can have an if statement and we'll say if path name that we've destructured above from the location is not equal 2 slash Dash then we'll do something else with the button instead of having the value be null so we'll say go home button let's set this equal to a button notice the parentheses since I'm breaking this out onto separate lines and now with this button on separate lines I'll put the class name and I'm going to set this equal to a couple of classes so I've got a dash dash flutter two underscores whoops two underscores button and I've also got another class that is icon dash button after that we'll give it a title and this is just going to equal home of course the title value always shows up when you Mouse over a button and then on click will be equal to that function we created on go home clicked and after that we can close out our button here now we can give a value that's going to be on the button and here instead of a word we're going to use our font awesome icon and then we can set the icon equal to the fa house that we imported and then we can go ahead and close out our button and I'm getting all the red lines because I closed out the button early out of habit I put the slash there so there we're good now that I removed that slash and we've created our button and now the only thing that remains is just to put the button inside of the footer so we'll put it inside of curly braces and have our go home button now this will only appear if we're not at the root page of Dash so we don't want the home button to appear there because we will already essentially be home if we're a logged in user but we want it to appear on all other Pages we'll have a little home icon in the footer let's take a quick look at app.js and it doesn't look like we have imported in our Dash layout component yet so let's do that we'll have our Dash layout and that comes from components and then we'll find our Dash layout there it is now remember with the dash layout it Imports the header and the footer so we still need to import the dash footer over here and once we've imported that we can use it inside of the dash layout so all that the app.js needs is the dash layout component because it pulls in the header and the footer here so now back at the app.js we see we've imported Dash layout but we still need to use it now this will be really where the protected routes begin but we haven't applied that protection yet and that's okay so here we actually need route first we'll say route path is going to equal Dash and then we'll set the element equal to [Music] Dash layout and now we won't close this it will actually wrap around the other components that are protected inside of this route I had previously mentioned folder and file structure and said we're going to use what we've seen in my Redux course and that we also see in the Redux toolkit docs we're going to base this on features so let's go ahead and create a features directory that's going to be inside of the source directory as well so we'll have features and now inside of this features directory let's create another one named auth and now that I'm thinking about it inside of this components directory we could have brought the login inside of auth because it's related to that feature so once we do that and we moved it over you can see it was instantly changed in my app.js file and I will save that change if it's not in yours you'll need to change where you have imported the login component from but so we've put that at inside of the auth directory now let's go ahead and create our welcome page because we'll already need to be logged in there as well and it will use some of that information so I'm relating that back to a protected directory or a protected route so I'm going to put it inside of auth now my way isn't the only way of doing this so if you want to create a different directory if it makes sense to you in another way there's nothing wrong with that you're just trying to use some logical hierarchy here so now with this welcome component I'm once again going to create oh and I don't have a DOT there between the welcome JS so this would not be a good thing right now let's rename this it didn't recognize what type of file it was welcome.js now we're ready type rafce and we get that functional component at the top of this component we once again need our link from react router Dom so I will return come down one and Import in link for from react router Dom [Music] and after I get that imported we're ready to put something inside of the component I'm going to highlight and paste and review with you press alt Z to get this code to wrap so we're importing link from react router Dom we get to our component and I'm creating a new date first of all and then I am formatting that date where it says today so I'm creating a today variable and I'm using this new international dot date time format now you may be in another location we know DND is in the U.S he's our stakeholder so that's what we're setting here but if you want to set something for your location you can do that as well and then we're putting in the object with the formatting that this date time format requires so it says date style is full time style is long and then we're formatting the date right here so you can see all of that and we'll get this nice format for the date that we want to display that's actually in one of our user stories where it talks about the login page and we're giving the date we're also supposed to give some user information that we will do in the future but we're able to pull in this today variable down here inside of our content where we create this section so here is the today variable pulled in with that format right now we'll just have a nice welcome message and then we'll have links to dash slash notes which will be our Tech notes and to the user settings now the user settings will not be available to all users in the future we'll apply some roles to whether that is visible or not but right now we just want to make sure it works so we've created that section and then we return the content and that is our welcome page over our our welcome component so we can save that and now import it into the JS or our app.js we'll say import welcome and that comes from features auth welcome I'm going to delete this semicolon as I'm trying not to use as many of those as I have in the past as they're not really required and now inside of our Dash layout this will be a route that's nested within so I'll just give a little space and then we'll have a route and this will be the index route for the dash path so when we go to Dash and it renders the children it will look for this index if you just go to the dash right here so then we'll say element we'll set this equal to welcome and we'll close that out and then we can go ahead and close out this route so you can see as I mentioned before we do have a nested hierarchy here we start out with the index essentially the index for the full page or the full site and that goes to the public but then after a login we essentially have an index for the protected routes as well well and that is our Dash layout you go to the dash path though and it renders the children and the actual index value that will show is our welcome component so now as you noted inside of the welcome component there was a link to the notes and a link to the user settings those are our other main features of this application so let's create directories for both of those we'll have a notes directory and then inside of features we will also have a user's directory okay I'm going to select the notes directory first and inside of that I'm going to create a new component called notes list dot JS and then rafce to create that functional component and the only thing I'm going to change here right now is the div to an H1 and press save now I'll do the same thing for users so we're creating these components we're not putting the logic in them yet but they are placeholders for the future we'll have users list.jsrafc e for that functional component and we'll once again change the div to an H1 and save and now if we go back to app.js we can finish out the hierarchy of our application so here we're going to have another route but I guess we need to import these first as well so let's go ahead and Import in our notes list from features notes notes list and then we'll do the same for users list and that's from features users users list and then we can set up the routing here now it's inside of the dash layout our protected parent here and then we'll put in our route we'll set this path equal to notes and then let's just close the route and get that closing tag right there because we don't have to put the element right there we're going to have several things inside of this notes route and remember we're already inside of the dash route so if we went to this it would be whatever our domain is slash Dash slash notes to get to our notes list and we'll make this the index of this path so we will then say route index and set the element equal to our notes list component and then we can close that out right here as we won't Nest other things inside of the notes list but we may eventually put other things in the notes path such as the edit note component or the new note component now we can essentially highlight this press shift alt in the down arrow and then I'm going to select notes and Ctrl D to select the other notes and switch this to users so now I have path users and we're rendering as the index of this path the users list and if the nested routes start to get confusing you can leave yourself a note inside of curly braces such as a comment here and we can say end Dash which was our Dash layout and now that might help you see things a little clearly when you get to the bottom and you're just seeing these closing routes here so overall the repair Notes application that we've created can see the routing structure inside of the app.js component we've got two public routes one is just the root itself that goes to the public component the other goes to the login page after that we are going to protect these following routes in the future we have not yet and that's okay but if we go to slash Dash we should see the welcome component if we go to slash Dash slash notes we should see the notes list component and then slash Dash slash users we should see the users list components we've also created our basic file structure here where we have some components for the overall the dash area and the public inside of components if you want want to create a separate directory for just those Dash components you could I did not but then we also have a features directory and we're going to have three primary features for this we're going to have the auth directory the notes directory and the user so we're organizing these logically by which they apply to so in the future of course the notes directory would hold the note edit component it would hold the new note component and it has the notes list similar for users and then other things associated with the auth the authorization the roles that we have and things like that will be inside of this auth directory here so it should make it fairly easy to find but again this is not the only way to do it but it's the way that I'm doing it and the examples you see in my Redux course will follow that pattern as well right now we should be able to open up a terminal window type npm start and at least see what we've got so far make sure everything is working correctly so here we've got our full page for welcome to Dandy repairs we've got the basic information that Dan wanted for his basic web page at the beginning now our link should work to the employee login and when we click it it does we just have our login heading we're not ready for the rest so let's change this path to Dash and see what we get here we've got our Tech notes page it's got our full date format and the welcome it's got a link to the notes and a link to the user settings now we also see our header and we see our footer that will have the current user and Status notice there is no home icon but if we go to the tech notes which is the notes list now we see a home icon that's available here our Tech notes should also link the word Tech notes should link back to the home page as well and our footer Still Remains at the bottom so let's click Tech notes here to check that out and looks like maybe I linked Tech notes back to notes we'll check that in a second the home does link back to the home page let's check the users list everything looks the same here so we go back and that's working so now let's just check that code for the one component that I said the header and that would be here inside of the components directory we have our Dash header and let's see where we're linking to and yes it is at slash Dash slash notes let's just delete the notes off of there as we have made the welcome the home page that change went ahead and registered and we can bring this back and actually you can see this now in a smaller screen that it still looks just fine let's go back to the tech notes and now if we click Tech notes at the top it links back just like our home icon does at the bottom on both Pages we have the basic layout and structure for our react application and in the next tutorial we'll be managing state with Redux and applying the API layer with rtk query let's look at our starter code for today I'm at the package Json and I'm going to change the lesson 5 front end from the previous lesson to lesson six and that's the code we're starting with is from lesson five that we completed in the last tutorial now moving forward we need to add some more dependencies to our package to use Redux inside of our project so I'm going to press Ctrl and the backdick and now inside of this terminal window I'm going to type npm I for install and then we're going to add the at symbol and have Redux JS slash toolkit and then give a space and we're also going to add react Dash Redux press enter and it shouldn't take too long to add those dependencies to our package Json and then we'll see them listed in the dependencies above looks like they're already there I'll close the terminal window we can see react Redux we can also see reduxjs Slash toolkit now available I should note the other starter code that I have added today is in the CSS file once again in the previous tutorial we stopped at line 179 I did not go over the CSS I just said you could use mine if you want to or you can apply your own and the same goes here now I added the rest of my CSS starting at line 180 and it's everything else you'll see including a couple of media queries that will make the font a little bigger on those larger screens I believe in the last tutorial I thought the font looked a little small so I've gone ahead and increased that size but this is not a CSS tutorial you can go over my Styles if you want to or you can apply your own now let's move on to highlighting that Source directory and let's create a new directory inside and let's call this directory app now inside the app directory we need to create an API directory so now I'll create that directory and inside the API directory I'm going to create a new file and I'm going to call it API and then with a capital S slice.js I'm going to move just a little quicker today so I'll paste some code in instead of having you watch me type it out but then I will go over anything that I paste in and so this is our starting API slice you can see I'm importing the create API and fetch base query from Redux here and what we're using this fetch base query for is essentially what we would use axios for in another project or something similar so that's how you can think about fetchbase query you can see we are creating the API right here so we've got export const API slice and it equals create API then we have to set some things inside of it and you can see our base query is going to use fetchbase Query and here's where we provide the base URL which in development is our local host at Port 3500 we would want to change this of course when we deploy this project we we provide a couple of tag types because these will be used for cached data so when we invalidate different caches or types we'll be referring to the note and the user data both and then we provide endpoints here with an empty Builder now we are going to provide extended slices that we will attach to this API slice essentially for notes and for users and that's where we'll provide the details that would really be the actual endpoints but this just gets us started with the API slice we need now let's highlight that app folder and let's make sure we're not inside the API folder and create another file and we'll call this file store.js and we can confirm we're not inside the API folder if we close that and you still see the store.js in your file tree so what we're going to do inside of the store just to begin is very simple we import configure store and then we use configure store to create store we just give the reducer an empty object and we go ahead and set Dev tools to true because we may want to use the Redux Dev tools but now that we've created an API slice let's go ahead and pull that API slice into our store as well and now instead of an empty reducer we will refer to that API slice and will also provide middleware so inside of the reducer you can see we're dynamically referring to this API slice with the reducer path and then we have apislice dot reducer here likewise we have middleware here that now must be added to the default middleware so we can call this function get default middleware and then well here's the actual function it's passed in here and then we add with concat we add the API slice middleware there now again this was all covered inside of my Redux full course so if this looks confusing it's a great time to go back and review that as well and now now that we've set up our Redux store and we have our beginning API slice let's go to the index.js and bring it into our project so we need to import a couple of things now we need the store from our store file that we created inside of the app folder and then we also need to import a provider from react Redux and then we can use that here in our projects so just underneath where we have react strict mode we want to create a provider and we want to pass in the store that was created and then we close that and get the closing provider tag and of course we'll put that after browser router and before the closing reacts trick mode tag so now we have provided the store to our application now we're ready to move on to the features directory and if you remember inside of the features directory we have auth notes and users let's go to users first and inside the user's directory let's create a new file and we'll call this users and then capital A for API and then capital S for slice so it's users API slice dot JS I'll paste in just a little and go over this before we add any more so we're importing in create selector which we'll use later and then we're also importing in create entity adapter from reduxjs toolkit and then we're importing in the API slice that we created as well which we will use but first we create a user's adapter specific to our user slice here that we are using Create entity adapter with now if you've gone through my Redux tutorial you'll remember using a entity adapter we can get some normalized State here so we should start then working with data that has an IDs array and then also has entities now the entities cannot be iterated over but the IDS can so we'll use the IDS to get data from the entities essentially when we need to do that again if that sounds strange please refer back to my course but we will be using that as we move forward then if initial State exists in the user's adapter here we're calling that get initial state so we get that now I'm going to scroll up for some extra room and once we get up here to the top I'm going to paste in quite a bit as we get started with our users API slice but I'll go over this it only has the one endpoint right now but see we're using the API slice that we import right here and then as we Define our users API slice variable right here that we can export we use that API slice to inject the endpoints into that original API slice and that's where we Define our endpoints and we're only going to have one as we start out here so we're passing in the Builder and it's our get users query so there we have Builder dot query and here you can see the query it's just going to the user's endpoint and remember we already provided the base query URL inside of our API slice which was our local host at Port 3500 so here we just have to provide that endpoint following the documentation we can validate the status now you may not have seen this before and it's a little strange because even as they note in their documentation currently their tricky API as they refer to it always gives this 200 status even if his error might be true but this is how they say to check or validate the status so this is exactly what I'm doing I'm making sure there is not an error and I'm also making sure that we do have a 200 status here now this keep unused data for and I've got it set very short to five seconds I'm only going to do this in development but you could remove this later on the default is 60 seconds which would be more like what you would want when an app is deployed and that's just talking about whether the data will be referred to in the cache or if it needs to request new data so we're just not keeping it that long here during develop development transform response this is very important especially as we're working with mongodb and getting data from our back end so here we get the response from the query and then you can see I'm defining load loaded users inside of this function that we can call inside of the transform response what I'm doing is mapping over the data and I'm setting the user ID property to the value of the user dot underscore ID and the reason is especially with that data I talked about the normalized data using an ID array it's looking for an ID property not an underscore ID property so if we didn't do that it wouldn't work out right and then of course we just return the user there and then we use that user's adapter and it says set all and we're providing these loaded users which is the response data that has that new value at the ID property so so now we have returned that data and put it in our user's adapter and it's stored as normal ID normalized data with IDs and entities now here this last part just provides the tags that can be invalidated now you could possibly get a result here that doesn't have IDs now that's probably when an error has occurred or you've got something you didn't expect how I'm handling that is I'm just checking to see if there is an IDs property with optional chaining and essentially if there isn't I'm just returning the user and the ID list instead of the user type and ID list along with mapping over those IDs so any one ID could invalidate it essentially if we don't get IDs we probably didn't get the data we wanted anyway so that's just kind of a fail safe and now if you remember or know from rtk query it is going to create a hook based on this endpoint for us automatically so now let's scroll down to the bottom and we can export that hook so we'll have export const and it automatically generates a hook that starts with use and ends with query if it's a query and then it's whatever we named it which above was get users so this is use git users query and before we're finished with this slice let's go ahead and create some selectors and I'm going to paste this in and go over it it is exactly what I did in my Redux course as well but what we've got first is Select users result and now we're using the users API slice referring to the endpoints calling git users and then chaining the select method to it so this gets the query result after that we're creating a memoise selector notice we're using Create selector here that we imported above and we pass in that result select users result and then we have a function that has users result and it comes in and grabs the data now I'm going to press alt Z so this wrap so you can see my full note here which is normalize State object with IDs and entities that are referred to notice this doesn't have an export so we're not exporting this at all we're just creating that memoized selector here to use in the next part and this is with Git selectors so it says git selectors creates these selectors and we rename them with aliases during the destructuring here so it creates these automatically we have select all select by ID and select IDs and we're renaming them to apply them to users so select all users select user by ID and select user IDs now how we're creating that it says pass in a selector that Returns the user slice of the state so we're using git selectors on the user's adapter we have state coming in here's that select users data where we created the memoise selector so we're using that here with State and then you can see the null coleskine operator so if that's null then it just goes to initial state but otherwise these are memoized selectors and they can come in handy when we want to optimize our application so now that I've saved this file I'm actually going to press Ctrl a to copy everything we've put in here and then control I said control a to copy it's Ctrl a to select Ctrl C to copy and then we're going to go to the notes directory and inside of it we'll create a notes API slice.js and I'm going to paste in what we had in our users API slice I'll once again press alt Z so that wraps but now what I'm going to do is highlight the word user and now that I have that highlighted I'm going to press Ctrl shift and the letter L and then I'm just going to type note and so you can see it changed every instance of user in this file to note and by doing so I just took a shortcut to creating my notes adapter because it's basically identical to the user's adapter at least as we get started here but we're just referring to a note instead of a user and as I scroll down I don't see any problem and we'll have a use get notes query that is created and everything will be created here including those memoized selectors that we might use including select note IDs select note by ID and select all notes now to quickly review how I did that so you don't have to highlight every instance of note there's two things to take into account one is the selection and so I selected all occurrences with Ctrl shift and the letter L select all occurrences which you can also do from the selection menu that does not take into account wherever note or user was capitalized or wherever it was lower case as we see here and notice all of mine changed automatically I'm doing that with an extension I'll save this file just so I don't lose any changes let's click the extension over here in vs code and I'll search for multiple and there it is multiple cursor case preserve I use this extension so when I select multiple cases essentially when the word user was lowercase or uppercase and I replaced it with the word note I just had to type the word note and it applied the uppercase in the same areas that user had uppercase and of course lowercase the same so this is a very useful extension multiple cursor case preserve if you want to apply that to your instance of vs code as well but that helped us quickly and easily create our notes API slice to get started now in the previous tutorial we already created a user's list component and a notes list component let's go to the users list component you can see this was just a placeholder so far now I want to come to the top of the file and I'm going to import that hook that rtk query automatically created for us that we exported the use git users query and now inside of our functional component the very first thing I'm going to do is actually use that query and you can see we're going to get several things from it we're going to get data back that I'm going to rename as users we're also going to have several states that we monitor here we can check and is loading and is success and it is error and if we have an error we can find out what the error is and all of this will help us conditionally render some content so underneath I'm going to Define some content with let content variable defined here and then we'll check is loading and if that is true we're just going to set the content to loading or if you have a spinner component you like you could use that there as well next is air we're going to have content set equal to a paragraph with an error now let me press alt Z once again to wrap this so you can see everything and I'm checking to see if there is an error here in the class name so you can see I'm applying two different class names based on that if there is no error if that is false this is off screen and if there is an error I'm applying the error message class and then we're displaying the message itself now notice the error doesn't just have Dot message it has data first so we're going to error.data Dot message and I'm using optional chain in there just to be safe and now let's replace the return here inside of our component and instead I'm going to paste in what happens if we have success I'll delete that extra line and let's look at this so if success then we're destructuring the IDS from that user's data remember we renamed the data that we received from our hook users this would also have an entities that we could destructure here as well so the IDS is just an array of the user IDs now we're creating our table content and we're making sure there are IDs that there have length on that array and if so then we're mapping over those IDs and you can see we're passing the user ID in here from map and then we're providing a user component that we haven't created yet and all this user component receives is the user ID now it has to have a key as well as we map over but we're providing the user ID for both of those and if there is no link to our IDs array then this is just null and then we have content here that's on multiple lines so that's why we have our parentheses and you can see I'm creating a table now this table has several classes applied that apply to the CSS that I have provided you can see usernames roles and edit and this is all inside the table head and then we have the table body that just gets our table content which was our mapped data from above now something to note about the tables in this project is I am setting them to display contents which lets me flatten the table to actually apply CSS grid to that now if you have not done that before you might be interested in the CSS you might also be interested in the final project of my CSS course on my channel where I do that exact same thing so grid needs a flattened structure tables are not usually a flattened structure but you can provide a flattened structure to grid if you set some of these elements that are the parents to that display contents and you can see at the bottom we are exporting the user list component and that should finish the user list.js now we still need to create the user component that we're using here inside of map or we will have an error and this just won't work out right so now let's create a user.js file I'm going to paste in some imports that we can talk about and then we'll create the component underneath so we are using font awesome icons as we previously set that up in the last tutorial so here at the top I'm importing the font awesome icon component and then the icon that I want to use I've also got use navigate from react router and then we're bringing in use selector from Redux this is where the IDS will come in handy because we're also bringing in that memoise selector we created which is Select user by ID so underneath using react es7 Snippets I can type rafce press Tab and we get our functional component named user and we know we're bringing in a user ID so now let's start just inside of the component and we're going to bring bringing in that use selector and we're going to use that select user by ID selector pass the state and we pass the state and that user ID here and we get our user back also we're going to pull the navigate function from use navigate and now instead of the return that we have here let's start out with an if statement we can say if we have a user so if that user does exist we're going to do something here but then let's also have an else return null just in case we don't have a user and now I'm going to scroll to give ourselves a little more room to put some things inside of the successful part of the if statement and we'll start out by defining a few things one is a handle edit and this is going to call navigate and it's going to go to dash users and then whatever the user ID is is going to finish out that URL and we can set that up in our app.js with react router the next thing I'm doing is pulling all of the roles from the user roles array setting them to a string and I'm also replacing the commas with a comma and a space so really what we're doing here is making it just look a little bit better with formatting so instead of all scrunched together we get a comma and a space instead of just a comma the then I'm defining a cell status and this is helping me set an inactive class or not essentially on the active user and now let's go ahead and put in the return data that will use those and so here we see a table row being created that will go into the previous table that we started in the users list and now this row has several classes let me see if I can press alt Z and get a little more to display there there wasn't much wrapping but what we've got are some table cells here and we're setting that cell status in each one if they are active or not likewise we're using that icon that we imported here the PIN to square that we would see which kind of indicates edit and we're calling handle edit if that is clicked so let's go ahead and save this file and let's not forget to import it into our users list as well so we need to import user from dot slash user and after we save that we're ready to check this out in our application but we can't just start up the front end without the back end and the last version we have of our backend code is the code repository from Lesson Four so open up another instance of Visual Studio code and in that instance you want Lesson Four I'll drag mine over right now as you can see it now on the screen and I've got Lesson Four here in the package Json I could make this full screen as here as well so now that I've got the lesson 4 code up in another instance of Visual Studio code I can press control on the back tick type npm run Dev and we'll make sure our backend code is running and it's ready to respond now to the front end code that we're creating so now that I have that running I'll minimize that and we've saved our changes here so I am ready to to press control on the backtick as well in this instance of Visual Studio code and type npm start to start up our react app now I'm going to drag it to the left as I have a browser here on the right and then we should see our app startup and we do the font might be a little bit larger than you saw from the previous lesson as we've applied that extra CSS but now we're going to need to enter in the URL to navigate to the dash so it would be at slash Dash and from there we can see what the employees or the staff of Dandy's repair shop we'll see when they log in except for maybe some auth details that we haven't added yet and we should be able to navigate to the user's list by clicking this view user settings so if we do that now we see our grid table here and once again I'm taking that HTML that is a table and I'm turning it into a grid and you might be interested in the CSS for that but overall we've got three employees that I added you could add your own using Postman as we had seen previously in tutorials as we were building the back end and you can see it displays their username their roles and the edit area now this edit area won't currently take you to any page it would probably give you an error because we haven't created that page yet to edit that information but our users list is working as we expect it to so now I'm going to drag Visual Studio code back to a full screen and close the terminal I'll just leave it running because we'll eventually check that again and now we're ready to update our notes list so at the top we need to use that same query that was created in the notes API slice just like we did with the query that was created for the user's API slice so now we have use get notes query and now inside of the functional component you should notice this will be much like we did for the users list so what we have here is that you use get notes query we're bringing in data but we're renaming the data notes instead of users we're going to check is loading is success is error and if there's an error we'll look at that error so I'll scroll down once again press alt Z so any code going off the screen wraps to the next line and we're checking is loading and once again providing a loading status if that is the case for Content likewise we're checking is error and we're applying those same classes for an error message if it needs to display and remember the error has dot data.message instead of just error.message as you might be used to and now I'll scroll up because we're going to replace this return and we'll replace it with what happens if we have success and herefore is success we're once again destructuring the IDS from the notes data so this could have IDs and entities and in the future we'll actually come back and use the entities here as well but we're keeping it simple for now and then we have the table content that we're creating in the same way we created table content for that users table and we're passing the note ID into a note component that we have yet to create you can see this table is a little larger here and it has some extra classes applied which is why you see this wrapping down so we have more columns that we'll be able to see on a larger screen but I have applied a media query that hides some of the columns for a smaller screen and then we have that table content going into the table here as well and then we export the notes list and that wraps up everything inside of this notes list and of course if I went over that too fast you'll see all of this code available in the course resources and now let's create our note component so note dot JS and we'll start with the Imports much like our user JS component we're bringing in font awesome we have the PIN to square icon and use navigate from react router Dom we also have use selector and now a memoized select note by ID from our notes API slice I'll type rafce using react es7 Snippets extension we quickly get our functional component and then inside this functional component we'll start by using our use selector hook and then we'll select note by ID pass in the note ID here then we're also pulling the navigate function from use navigate and now we'll put a conditional here instead of just the return so we'll say if we have a note we're going to do something and then we'll say else return and we'll just return null now inside the successful If part let's go ahead and Define a few things here we have a little more data we're handling inside of note than we do with users I'm going to press alt Z once again and I'll even press Ctrl B to hide that file tree temporarily but it still wraps down just because it's taking a little longer here with the dates so we've got to create a date and an updated date that we get from mongodb about each record and here we're applying this to Locale string and here I'm providing the US area for this now you can provide your area if you want to as far as our stakeholder Dandy's repair shop I'm considering them to be in the US as well now we're providing the day value as numeric and the month as long for both of these and then we have a handle edit function that is going to navigate us to dash notes and then the note ID and that's where we would be editing the information for the note and we'll eventually need to add that routing to our app JS as well now underneath this we'll put in the successful return and this once again is creating a table row you'll want to apply these classes if you want to use my CSS notice here I've got a ternary based on whether the note is completed or not so it gets a different class based on that completion other than that we're displaying these others inside of table cells but then they also have classes based on what each piece of information is and eventually we have a table cell that has that font awesome icon that indicates an edit once again and it calls handle edit now with those changes saved I'll press Ctrl B to show the file tree again back in the notes list we need to come back to the top and import notes so it can be used and it comes from dot slash note after we've saved that we should be able to see our notes list now remember if you're creating users and notes with Postman you want to create the users first because you have to have those users to create notes so far and that's what I've done so I'll drag this to the left and I can see an error because inside of note I forgot that we were bringing in the note ID so I didn't put it at the top and it needs to be coming in as a prop so here we've got note ID as well let's save that easy to forget when you're moving quickly move it back over and here's our users page once again so this is working let's go back to the home and let's see if we can view the tech notes yes we can notice the completed here is at the top that's something we'll talk about in a second right now they're just in the order they were created so we've got Mrs Smith's computer we've got food city schools which is the city where Dandy's repair shop is and we've got Bob Jones's iPhone now we just see three columns here so let me drag this to the full screen and you can see the media query is actually hiding some of the other columns based on the screen width so now we can see the created updated and the owner of the note who the note was assigned to essentially and then we've still got the edit icons over here now that we've looked at this a little bit let me drag it back to the smaller view we can still see the status here either completed or open it would be nice probably a good feature to think about and include even if our stakeholder didn't ask for it directly would be once a node is completed to not leave it at the top anymore just because it was created first let's put the open notes on the top and any that are completed down at the bottom instead so I'll drag the code back over and we can do that inside of our notes API slice where we have our entity adapter here where we create the entity adapter we can provide a sort compare function so I'll paste this in and we can see what it is due doing so this is much like your traditional JavaScript sort we take A and B and then we're looking to see if the a completed value is equal to the B completed if it is it gets a zero otherwise then it's checking this once again looking at a completed and it either gives it a 1 or a minus one so it may be just a little more complicated than that traditional sort that you're used to but what we're doing essentially is putting the completed at the bottom so if it is true otherwise the open status is at the top so if we just put this in and then we drag this back over and check our page we'll need to refresh to query that data once again now Mrs Smith's computer is at the bottom of our list any any others we would switch to completed would instantly come below as well we have covered a lot in a short amount of time as far as Redux and rtk query goes now in the next next lesson will cover mutations which also covers the editing and posting and deleting so the crud operations but those are the mutations not the queries as they're referred to in rtk query our starter code is the completed code from lesson six there are no new dependencies today but we've got a lot to cover and I'll need to keep things moving feel free to pause the video as we go and remember all of the source code will be available under lesson 7 in the course resources here we're starting in the package Json and the only thing we need to do here is increment this to lesson seven today no new dependencies to add from there let's move on to the user stories while we've made progress on many of the user Stories We list here and really this is that informal list we talked about in previous lessons we've only completed a couple that we can really say that are completed one of those is to add a public facing page with a basic contact info we did that in the last tutorial and then we also had provide a welcome page after login and I said in the last tutorial actually we did this two tutorials ago as we created the react app and just provided those basic things and some routing to those but today I think we'll complete a few more let's look at number 10 here notes are assigned to specific employees we'll be able to create notes and create that assignment today number 11 notes have a ticket number titled note body created and updated dates now we previously set that up on the back end with our data models but now we'll complete that for the front end as well as well as number 12 notes are either open or completed so when we create a note we'll assign that and number 13 users can be employees managers or admins so when we are able to create create users with a form will also be able to complete that so number 10 through 13 should be completed today some of these others we are very close to completing but maybe we can't say it's completed yet because it also deals with roles and protections and things we haven't applied through authentication and authorization yet or there are things just like provide easy navigation which we have done somewhat with our users list and notes list but we're not finished yet we need to provide some more navigation throughout the application so now with these two boxes checked in our Target set on lines 10 through 13 here or I should say Goals or stories 10 through 13. let's go ahead and save our user stories.md file and let's move back into the application so we're inside of the source directory and then inside of that we want to open up the features directory and let's go to the users directory and the users API slice we have already added our endpoint forget getting the users but that's the only one we added so far so let's go ahead and add the create update and delete endpoints as well so let's find where we started this we have get users this is all inside of the endpoints definition of the slice that we have created here this is the users API slice that's injecting endpoints into the main API slice for Redux and rtk query so underneath this get users endpoint that we defined we can put in the other endpoints and I need some room to do this and I just put in all three they're not nearly as big as the get users so we'll just go over these the first one is add a new user now notice this is a builder dot mutation previously we had Builder dot query but now this is a builder dot mutation and that's what these other methods will be so we're passing in some initial user data and we're going to the user's endpoint we're using the post method and then we're just passing in that data in the body after that we're saying we're invalidating tags now so this will force the cache that we're using with rtk query and Redux to update and what we're doing is saying the user list will be invalidated so that will need to be updated after that let's look at the update user endpoint here so another Builder dot mutation we're passing in that user data again so it looks very much like the post as far as this endpoint is concerned we're using the patch method and here's the user data inside of the body we're invalidating tags here but now it's not the list now we can specify the ID of the user that we're passing in and we get that with the ARG parameter that we have right here inside of this Anonymous function for invalidates tags so we specify that right there and it invalidates that one one user ID so we know that needs updated again and remember we specified the IDS as well as the list here inside of the provides tags for our get users query so we had the list and then we also mapped over the IDS so we can invalidate those as well after that we have the delete user again very similar all it needs to be passed in is the ID here so instead of spreading in full initial user data we're just spreading in the ID actually we're destruction we're not even spreading and then we have the user's endpoint the delete method and all the body needs is that ID and then once again we're invalidating the specific ID of the user and now as we scroll down remember rtk query automatically creates hooks for us so we had our get users endpoint and it created use get users query that was a query now remember these others are mutations so as I put these in here you'll see now we have use add new user mutation so it's named after what we created as far as an endpoint which was add new user and then they always append use at the beginning for the hook and mutation at the end just like query was appended at the end of our git users query so we have use add new user mutation use update user mutation and use delete user mutation and we'll be able to use all of those today as we create our forms and now that you understand the additional endpoints we added to our users API slice let's do the same thing very quickly for our notes API slice so once again we're inside of the endpoints Builder and then we have the get notes Builder query so we'll come down right underneath it and we'll paste in the other three which you could create as well or grab from my source code but we've got add new note Update note and then finally delete note and this has the similar logic that we just went over for the user's endpoints as well so nothing new there now let's come down to the export and we're going to export these three new mutations that we have here as well now before we create our forms let's go ahead and add some placeholder components I'll go back to the users directory and create a new file and this first file will just be named edituser.js and I'll use my es7 react Snippets extension to quickly create a component and this is just a placeholder component so I will save the file and now I'm going to create another new file and this is going to be called new user form dot JS and once again I'll use rafce to create a new user form just a placeholder component for now so we have edit user and new user form files as placeholders now let's do the same thing in the notes directory and I'm going to create edit note if I could spell edit correctly.js and rafce with es7 react Snippets and I quickly get that functional component placeholder and then I want one more and this is going to be new note.js notice I did not name that new note form it's just new note dot JS and there's a reason for this I'll do rafce we'll come back to that reason soon but let's save that and now we have four placeholders for our form data so we have two for notes and two for users I wanted to do this so we could go ahead and add the routing inside of our app.js file now to do that we first need to import these new components so at the top I'm going to import first edit user and after we get that I'm going to import new user form and then after that well I don't I'm not quite at the end there we go I'm just getting rid of that semicolon that I'm trying not to use as often anymore then I'm going to import edit note and then finally we need to add import new note and remember it is not new note form it is just new note for now okay with those four Imports we can now add our routing below we've already created our notes route and our users route and at this point I think I want to put notes below the user's route so I'm just going to switch those around it won't make any difference which is above the other here so we have the distinct routes of both users and notes just because I'm going to do users first here so let's go ahead and add a route and now inside of this route we need to have a path this path is going to be equal to the ID parameter so we're sending the ID parameter and that will be part of the path so we'll go to the dash will be at the root of the website or web app and then we'll have slash Dash slash users and finally the user ID all inside of the URL now besides that we need to specify the element so we'll say element equals and inside of this we will put edit user and then we'll have our edit user component and instead of this closing route I think we can just close it out inside of the same so we have the slash greater than instead of the closing route symbol there at the end or the closing route tag now once we've done this let's copy this down and we'll have one more path inside of our users path and this will just be to new so we could have slash Dash slash users Slash new and this should be the new user form and now I'm going to copy both of these and put them underneath our notes list as well because it will have the same path pattern for notes so it will either go to the ID parameter in the URL or new so we just need to change what we have here as far as the components so we'll have edit note or we will have new note once again it is not new note form before we begin building our forms there's one more thing we need to do I'm going to go ahead and collapse the features directory we need to be just inside of this top Source directory and create a new directory tree named config now inside of the config directory I'm going to create one file named roles dot JS and I will paste this in it's very simple we are exporting an object name roles and this would be a lookup object and notice the key and actually the string value are the same so roles dot employee equals employee we're going to use this in more than one file so I wanted to just create this object one time and put it inside of a Rolls JS that we can export and then we can use it in the other files we need let's go back to the features directory and back inside of the notes directory and we're ready to go ahead and update this new user form component I'm going to start at the top with the Imports again I'm going to move faster and paste things today and then go over what I am pasting in and of course feel free to pause slow down or look at the source code that I'm supplying for this lesson but we're importing use State and use effect for this new user form we're also bringing in the use add new user mutation that we created inside of the user slice I'm bringing in use navigate from react router and I've also got a font awesome icon because we're going to use a save icon from that and then the roles that we just created are going to be used in this form as well being a new user form that means we're going to have some new input for the user so I've got a couple of reg X constants that I am creating as well again this won't be a public facing form this will be something Dandy or his manager will use to create for new staff members to create a new user so we just need to put some guidance here as far as what can be entered for a user or a password but we're not being as strict as we might be for a public facing new user creation okay once we have those reg X's we're ready to start working with our our use add new user mutation inside of the component so now inside of this new user form component I'll paste that in and we'll take a quick look at what it does and what it brings into the component so this unlike the query gives us an add new user function that we can now call when we need it inside of the component so it is not activated immediately and then there is an object that of course delivers the status after we call this function so we have is loading is success is error and error much like a query but the query was called immediately when we use that inside of our list components this is not called until we're ready to call it underneath this hook let's go ahead and paste in the other hook that we get from react router which is just pulling the navigate function that we will also call whenever we're ready to call it from use navigate and now we've got some individual pieces of state that I'm using used 8-4 we've got the username but then we're also going to have a valid username that is only going to be true of course when it meets our regex standards same for password and valid password and then we've got the roles and set roles so we can set those and we're defaulting to employee right away for that value but notice it is an array so there could be more than one role assigned to an employee or a staff member and we did bring in use effect and that's going to help us validate our username and password so we're just going to check both of those so we have username and password as dependencies in each one of these and as they're changed we're just testing those reg X's that we defined and in one more use of use effect we're going to go ahead and check that is success status that we get after we call our mutation so if it is successful we're going to empty out all of that individual state that we're keeping here really and we're going to navigate back to our users list that has that is at the dash slash users URL now is Success does change and when it does change that's what will trigger this you will get a warning or a complaint if you do not include navigate in here although we know bringing in the navigate function from react router will not change so I just put the navigate in here as a dependency to remove that warning now let's go ahead and scroll up to have some more room and I'll put in the handlers that we're going to use instead of starting them with handle I started them with on and then we have on username changed which just sets the username on password change which sets the password but the roles are a little different and that's because it's a select and then we're doing something specific with them so let's break this down we have on rolls change that also receives the event but then the values we get we need to build an array from those values because we when it comes in with the event.target.selected options it is an HTML collection and that won't give us the same thing we need so we're using array from and then array from not only takes that value but it also has a function and then we can just get the option dot value from that and create an array stored in values and that's what we need so then we set the roles to those values after that let's go ahead and put in our save and we Define a can save before we actually allow the on Save users clicked to really kick in and do what we need it to because here we check if can save so let's look at this can save I'm going to press Ctrl B to hide the file tree just so we can see that full line here but we've got can save defined and notice we've created an array and inside that array we put the roles dot length because that's an array okay we've got valid username and valid password then we're calling the every method on the array and passing in Boolean so we're essentially saying if all of these are true you could say if roles dot length and valid username and valid password but I kind of like this method for doing it sticking them all in an array and then having dot every with Boolean and then we do have the Ampersand and we're also checking the is loading status so we're saying and if we're not loading then can save will be true and then we check that can save value inside of our on Save user clicked and this is where we call our add new user mutation and once we call that we're passing in the username password and the roles now before we create our jsx for the form we've got just a few more things to Define so I'll put those in here and we'll quickly look we are going to have a select so it needs options now previously we discussed how to get the value out of that and that's what we had up here inside of our on rolls changed well what we're looking at here is object.values and then we pass in that roles object that we defined inside of our config directory and import it so now when we pass that in we're just getting the values which was Employee and manager and admin and for each one of those we're creating an option that can be inside of that drop down menu that we should have and we're actually going to display all of those so we should be able to select more than one and we'll get to that in a second but first we have some other things we're defining here and these are classes that we may or may not want to apply to some elements in the form one of those is an error class so we're just checking to see if we have error and which class will be applied here either error message or off screen another is the valid user class the same for valid pass word class and valid roles class so we're just checking to see if those are valid and if they are then we're not really applying anything but if they aren't we're giving the form input incomplete class which will just outline those in red and highlight the fact that something needs to be completed with those inputs I'm going to replace our return right here and just return content so now I want to define the content variable it's going to take up some space and we're actually going to need to scroll through that so I'll put it right here and give one extra line before the return and now let's look at each part of this form that is held inside of the content variable notice I have got a fragment here as the parent for valid.jsx and the first thing we're putting in is a paragraph with the error class and that error class is defined above so it's either off screen or if we have an error it's going to display that error message at the top of the form and remember we gave some detailed error messages from our back end that it can provide to the front end so these will be displayed at the top of the form if any of those errors do occur then we have our form so here is a class name form remember the class names that you see here are going to relate back to the CSS that I've created you can use my CSS or you can create your own as well so my class names are relating back to my CSS here on submit for the form calls the on Save user clicked so that should work for the entire form and then we have the top the title which is new user and then we have a button and this is where we're using that font awesome icon with the save icon and notice this button has a class name a title and then we set the disabled and so if can save is false or use using the exclamation mark here to flip that value disabled would be true so if we are not meeting the requirements for saving the new user then this button will be disabled so we're getting double use out of that can save variable after that we have a label and you should have a label for each input and what we're doing here is providing the username and some details here we're saying it must be 3 to 20 letters and then inside of this we have a class name and here's that valid user class value that might be applied if there is an issue with the username or if it's just blank it's highlighting that it needs to be filled out we've got your basic attributes here including autocomplete set to off because we don't want other previous names popping up and this is a controlled input so we have the username State here and we're calling on username changed during the on change if that happens very similar for password we give some details here 4 to 12 characters including these characters right here and after that it's a controlled input and the same for the valid password class now we get to the roles what I want to highlight here with the roles is that multiple is set to true so you can select more than one value and the size is set to 3 so it will display three values without being a drop down all three values will be visible and then it is a controlled input so we have roles and on rolls changed and then we're bringing in those options that we defined above and with that we have completed our new user form let's go back to the file tree now and highlight that edit user component let's go to the top of the file and we'll bring in our Imports first and not nearly as many for this particular component we'll have use params from react router because we're going to get that user ID parameter out of the UI RL and then we're going to bring in use selector from react Redux and select user by ID so notice we are not bringing in a query we're actually going to pull the data the user data from the state and we're going to get that by selecting the user ID so now I'm just going to highlight the return and I'm going to replace the content of this particular component and there's not a lot because we're going to use another form that we haven't created yet and that is the edit user form so what we've got here I'll go ahead and save is pulling that ID from the use params from react router that will give us the ID value that is inside of the URL and then we're passing that ID value in where we're using the use selector hook and select user by ID remember that is a memoized query there that we created ins or a memoized selector that we created inside of our users API slice so we pass in that ID and we get the user in return that has that ID now what we're checking here for content is do we have a user if we do we're going to pull in the edit user form that we haven't created yet but if not we're just going to provide loading if you had a loading spinner that you wanted to use here instead that's fine this is just a small paragraph that says loading and then we're returning that content so this is ensuring we have the user Data before we need it inside of the edit user form and the reason that is helpful is because we want to pre-populate that form we need the existing data to show up in the form and this will confirm we have it as we render that edit user form so now let's create the component we need so we'll come over here and create a new component and call it edit user form dot JS as you might expect this will be very much like the new user Forum we're essentially editing in that same information so I'm going to go fast but highlight the changes we're pulling in basically the same things with a few changes here for the Imports We've Got U State and use effect again but now we're pulling in the use update user mutation and the use delete music mutation instead of the add new user mutation and then we've got use navigate again we've got font awesome but then we're pulling in not only the save icon but also the trash can icon if we want to delete then we're once again pulling in the roles from our config directory after that we're going to have this same regex at the top because we're going to need to check those same fields for the same things once again underneath this I'm just going to type rafce to go ahead and get a start on this edit user form component and we're going to destructure the user as we bring that user in as we were doing that inside of edit user we see here the edit user form and we're passing in the user as a prop I almost well I need to control Z to undo that I didn't mean to drag that over but the user gets passed in as a prop for the edit user form okay back in the edit user form we're using the two hooks now use update user mutation and use delete user mutation they might be called at different times but we need some different identification for each so as I paste these hooks in I want to highlight that the first one update user just has is loading is success is error and error that we might expect here and I can put this on a separate line but after that the second one use delete user mutation notice I am renaming the is success to is Dell success and the same for is error and the error itself as we might need all of those now we've got our separate functions that we can call to delete user and update user and now I'm going to scroll up for more room and underneath those I'll paste in the navigate that we're pulling from use navigate as we did with the new user form and then we've got some State and it's essentially the same state that we had in the new user form with one addition and that is active and set active this has a default value of active inside of our data model when we create a new user but now we want to be able to change that to quickly disable an employee as our stakeholder Dandy has requested so if he were to let somebody go he might want to remove their access immediately they may still be assigned to notes and he may not want to have to make all those changes before he deactivates the user so this is the state here that will help us do that inside of the form and then we will have the same use effect underneath that checks for the valid username and valid password oh I had it before already too I had grabbed it before so I'll just remove that once again sometimes I get a little ahead of myself when I'm copying and pasting after that we've got use effect now this use effect checks the is success status but remember we have two mutations now so we have to consider both of those and so we're still just using one use effect and it's checking the is success status or is delete success remember there is success is for the update once again passing in that navigate function to avoid any complaints inside of our console about that but we're checking here is success for the update or is delete success for the delete and now as I look at each one of these they're essentially doing the same thing and sometimes we can get caught up in that when we're writing code we write one and then we look at the other so just a quick refactor here we could say if is success or if is delete success and then we should be able to remove one of these blocks because the rest of it the consequences of those being successful it they're both identical so we remove that and now this is a little smaller but it does the same thing I'm going to scroll for a little more room and underneath this we will put in our handlers and they are very much like what we saw in the new user form as well so we've got on username changed and on password changed no difference there on roles changed where we're doing the same thing with the rolls as before with array Dot from but then we do have on active changed which is new but it just sets the previous active status to the opposite because it's a check box so it's either active true or false essentially and then we've got on Save user clicked here we have to check to see if we have a password because we do not want to require the password to be updated every time we edit the user so it's just optional and that means we must call update user two different ways one with and one without the password then we also have on delete user click that call calls that delete user mutation and just passes in the ID scrolling up a little bit now just underneath that delete user let's go ahead and put in some more where we Define can save this can save variable is once again needing to check to see if we have a password and if we do can save is going to be using that valid password inside of the array that calls dot every with the Boolean notice over here there is the is loading status as well I'm going to press Ctrl B just so we can see everything on the screen and then can save has the array without the valid password in it if password is not being created as well so we're checking either way there and then we have the same classes that we did before as far as error class valid user class valid password class valid roles class then we're creating some error content and notice there is a difference here it's whether we have an error.data.message or a delete error so this this is based on the update or this is based on the delete mutation and then instead of a ternary this is a null coleskine operator so if the error or delete error are essentially undefined or null then we'll just have this empty string here that would be in the class and it won't change the presentation or I said class this is actually the error content itself so the content would be empty if that was null or undefined and now speaking of content that's what we need to return next so I'll just modify this return right here and change it to content and let's define our jsx with the content variable and this of course takes up more room than the screen has so I'll scroll back up this is very similar to our new user form except in the edit user we've got a couple of additions so here's that error content with the error class provided if it exists otherwise that off-screen class hides it off the screen and then we've got our form this form not only has our save button as the previous new user form did it also has our delete button and this is where we use that trash can icon and this will call cause that delete user mutation to be called just like the save user here will cause the update mutation to be called then inside of the form we've got the same inputs except for the addition of this active check box so here's the check box it is still controlled with checked either active or of course not whatever is there and then we've got the on active changed Handler being called other than that we still have the assigned roles it is still set to multiple trues so we can assign more than one role we're displaying all three roles at the same time so it's not a drop down as much as it is a list where more than one can be selected with those changes in place I'm going to save the file and now I want to bring over another instance of Visual Studio code that has our backend code in it so I'll bring this over to this screen this is from Lesson Four the last time we touched the back end code I'm going to press Ctrl in the back tick and go ahead and start our backend development server here this is the rest API that's a big part of our mernstack application it's now connected to mongodb it's running on Port 3500 remember this is the code we finished up in Lesson Four and I've opened a separate instance of Visual Studio code to run that so now if I want to I'm just going to minimize that and look at our existing code here I'll go ahead and press control and the back tick and I'll type npm start for our react app and we'll see if we can view the forms we just created or if we have any errors now I'm going to drag this over to the left and we've got our application running here on the right we should be able to go to the dash that we've previously created and now we should be able to go to the users list so let's check that out and we've got imp employees in here that I previously created that you should have seen in the last tutorial we've got Dandy the stakeholder he's the owner so he's an admin as well as a manager and an employee so you can see different roles are applied to the same user we've got Mark who's an employee and a manager and then we've got Joe who has the role of employee now I'm going to drag this over to the left because there's some things we need to highlight as far as using Redux before we get into each individual form and how we maintain that state so I'm going to press Ctrl shift I to open up Dev tools notice I really shrank the application because I want to use Redux Dev tools if you don't have those of course you want to install those and I can put a link to those in the course resources as well but here I'm highlighting the state in Redux Dev tools and I can open up this API and notice there is a subscriptions right here and if I open this up we've got get users that we needed our get users query to populate this users list and inside of get users we have a subscription set right here and it gets this long string now let me go ahead and go to Dandy's page and here we've got the edit user screen that we created notice there is no subscription and now it went back to loading after just five seconds why is all of that happening well let's take a look at why that is happening so to do that I'm going to close this out drag our application back to the right and drag Visual Studio code back to full screen close the terminal and let's look at our users API slice once again and if you remember I set the kip keep unused data 4 to 5 seconds and I wanted to highlight this in development because after five seconds we went back to that loading screen it only kept that data for five seconds and that's because there was no active subscription into the data so after the all of the subscriptions are gone that's when this countdown kicks in Now the default value is 60 seconds so if there still wasn't a subscription to our users list after 60 seconds we would use the state of our editor's form and it would go back or our edit user form and it would go back to loading we don't want that either so there's a couple of solutions here first of all I'm going to just remove this as we no longer want it inside of here and the default keep unused data for 60 seconds will be fine but we'll see how we can keep an active subscription and that won't be an issue either so while I'm thinking of it let's go to the notes API slice as well so we don't have that same issue because I believe I kept that in there too so also remove this keep unused data for five seconds and just leave it out of the slice altogether now what we need to do is create an active subscription that remains active even though are you user or edit user form I believe we're here in edit users where we got the data it is just using the use selector so it's not querying that data again and that's why we don't have a subscription but we've already queried the data we don't want to send another query when we already have it so we're not using rtk query although rtk query would know we already had that data and create that subscription we're using a use selector so somewhat of a preference but also just to demonstrate what is going on here so we're pulling this out of the cache and out of the Redux State and using select user by ID rather than creating a new subscription and we want the notes and users throughout the application so it's really no problem to create a subscription that lasts for the duration of our protected pages so to do that let's close out the users directory let's close out the notes directory let's go to the auth directory and let's create a new component in here and we're going to call this pre-fetch dot JS now rtk query and Redux toolkit does have a use prefetch hook but that's not what we're going to use let me start out with a few Imports here inside of this file we will import the store from our app directory and the store this is the Redux store we're going to import the notes API slice the users API slice we're going to use a use effect hook and we're going to import outlet from react router Dom and now let's go ahead and use rafce to get that functional component started with our es7 react Snippets and inside of this prefetch component I'll just paste in the details and we will go over that I'll highlight the existing return and put in our details here I'm going to press Ctrl B so this doesn't go off the screen so let's look at this and we can see how it works as well here's our use effect and it's an imp 50 dependency array so we only want this to run when this component mounts when it mounts we're going to log subscribing and I really want to highlight that or leave it in the code for you because of react 18 and we're using strict mode so it's going to mount unmount and remount and we'll see that with a subscribing unsubscribing and then once again subscribing and that's only in that strict mode when you're in development mode but we're going to create a manual subscription to notes and another manual subscription to users that will remain active so that way we have access to that state and it will not expire in five seconds or in 60 seconds which is the default and then we'll unsubscribe if we ever leave the protected Pages we're going to do that of course this returns an outlet so all of the children we're going to wrap our protected pages in this pre-fetch component this will also help us when we refresh the page and we still want to have that state including pre-filling our forms so now that we've created this prefetch component let's go to the file tree and let's go to the app.js and inside the app.js I want to import prefetch [Music] I've got it from features auth prefetch and once it's imported all we really need to do is wrap it around everything that starts with our Dash which are the protected pages so here we'll have route and then we'll have an element we do not need a path for this and inside of that we will put our prefetch component and once we have that we can go ahead and close this because we will want a closing route and we do not want this to close out until after the end of the dash and once we've done that we have now pre-fetched that data for notes and users for this whole area of our application now let's once again go back and look at that prefetch because I was thinking the one thing I didn't explain really is what this is this is the manual subscription right here so we use the slice then we call the endpoints then we call the actual query that we want and then the initiate method creates that manual subscription notice in the cleanup method we are unsubscribing so if we ever go to any of the unprotected Pages it will unsubscribe as well okay with that saved now let's see we're still running our application let's drag this back over to the left and now we've got Dandy's information on our edit user form and it's not going away let's see if we can change Dandy's name to a lowercase D at the end just for an example we'll click our save icon now we're back at the users list and we have added that addition to Dandy's username let's go ahead and change that back and now we can also see in the roles we can hold down the control button and just select one or none but then it's outlined in red saying hey we need something here notice also when this is outlined in red the save button went away so our can save variable is working as expected too active or not active and of course Dan needs all of these roles and we're not changing his password right now so we'll just leave this empty but that's okay because we do not have to have it although we did it looks like we applied the red around this even though we're not actually requiring the password when we edit the user so we may want to change that also while we're here let's go ahead and go back to the edit it and notice if I refresh the page we reload all of that data because we're already subscribed and that hits the prefetch component first before it comes here so that really helps our consistency if someone hits the refresh or reloads the application in any way now what else do we need to check well let's go back to our Tech notes and we could view the user notes again but after the users we also created that new user form so let's put slash new to check that out and let's create a new user I'm just going to call this new user test and our password is test123 and we'll make him an employee or her and a manager and then let's hit save and now in our list now we don't need that or any help from chrome but in now in our list we have test with an employee manager role and here is that user let's go back and let's delete that user and now that user is gone now what might happen with our list of data here or with our notes data is say this was open on more than one employee's screen or more than one staff member and we might get some stale data after it's open for a while so we also want this to refresh the data sporadically or at some type of interval that we can control and we can do that with rtk query and Redux as well so now let's go ahead and apply that I'm going to pull this back over to full screen we'll close the terminal for now let's open up the file tree and go to the app directory and our store.js inside of our store we need to import set up listeners and notice this comes from reduxjs toolkit query and I'm going to get rid of those semicolons just because I'm trying to be consistent now after we bring in setup listeners we just need to add it at the end of our file and we call setup listeners and pass in the store.dispatch once we've done that we've enabled some things that we can use now with our queries in the users list and in the notes list let's go back to the users directory we have inside of the features directory and back to our users list notice we're just calling use get users query here inside of this component but we can pass some things in including options so I'm going to paste this in we just put null or you could put undefined here as well this would also work if we did that after that we have options and what we're using here for options are a polling interval refetch on focus and refetch on Mount or ARG change really if we remount the component we're going to refetch the data that's set to true if we put the focus on another window and come back to our browser window then we'll also refetch that data so we'll be looking at fresh data and then we're setting the polling interval to 60 seconds this is sixty thousand milliseconds essentially so every minute it will re-query that data and if we have the Page open to a users list then we will get new data again now we can also do this inside of our notes list so let's go to the notes directory and inside of the notes list we'll do something similar but I would expect the notes list to be more active I'll once again change this to undefined it should work either way but I believe the documentation shows undefined when you do that afterwards we're just going to change that polling interval to every 15 seconds because the notes could be more active more than one person could be working on them so we'll show the most recent data in the list at least every 15 seconds after that refetch on focus and refetch on Mount or ARG change will both be true as well so after setting this pulling interval you should see a new request for notes every 15 seconds inside of your network tab of devtools of course you could adjust that if you didn't think it was necessary that frequently or you needed it more frequently either way but those are nice features to add when you have more than one person working with a list of data and they're needing to reference that data for any changes and now let's go to the welcome component that's inside of our auth directory and we have links to the lists for Tech notes and for the users list but let's go ahead and highlight those and I'll just put in two more links with it so we go directly to the add a new tech note or add a new user link as well now that said we haven't created the forms yet for the notes so let's get started on that as we have a new note and an edit note component now just like our edit user component that had an edit user form component that was pulled in our new note component will have that and you would think okay but why didn't the new user have that well the new user has all new data but the new note actually needs some existing data so we're going to pull in this use selector and select all users and then there needs to be a new note form component that we will also use inside the body of the functional component I'll just replace this return and we're going to use that selector with select all users which is a memoized selector that was created inside of the user's API slice and get all of the users once we have that we're going to check what kind of content do we want to render if we have the users then we're ready to render the new note note form that will be populated with users data to choose from as well so we can assign that note to a user if not we'll just have a loading message and then we return that content so let's go ahead and save that file and let's go into our directory and create that new note form dot JS component we could rafce for a place holder and just get that new note form component there so we don't currently have an error we should go back to the new note and import that and we did so that's good we already have that so no error there when we try to check it out now we're at the edit note the edit note has a little bit more to import at the beginning so let's go to the top here and go over the Imports oh I got rid of the name there there we go return that and I'll go down and paste in those Imports now we're bringing in use params because we're going to need the ID of the note we've got use selector select note by ID which is that memoize selector that's now created in the notes API slice since we're dealing with notes we also need the users though so we're going to select all users here as well because this form will be very similar to creating a new note and then we're bringing in the edit note form that will also need to be created so we're bringing in data once again and then rendering a pre-populated form to edit that information so let's go ahead and replace the functional component information here we're going to get the ID from use params which should look very familiar to you after we did the same for the users now we're getting the Note data for the specific note that has that ID with the selector we're also getting all of the users that we need again now our content is going to check to make sure we have the Note data and the user's data and if we do it's going to render the edit note form and after that of course we're passing in the note and the users both as props there if not we have the loading message and after that we return the content so now let's go ahead and create an edit note form placeholder as well so edit note form.js for the component rafce to quickly create a functional component and we have placeholders for edit note form and new note form now this is very similar to to what we have already done with the users where we had the edit user form and you can use that pattern what I'm going to do now is give you a viewer challenge much like I did with the controllers we've already spent a lot of time going over these patterns so now apply what you have learned and try to create your own forms here needed for these two placeholders and of course I'm going to put my code in the source code for the lesson so you can go back and check as well but I think this is a nice place to stop and give you that challenge and we've got everything else in place in lessons one through four we built a functioning back-end rest API for our myrn stack project and in lessons five through seven we created the front end react app for our myrn stack project it should currently complete all crud operations for both notes and users at the end of lesson 7 I left you with a viewer challenge to complete the new note form and the edit note form for the app I hope you did well and remember you can view my source code for lesson 7 in the course resources to compare your code to mine let's start today by quickly reviewing the difference between authentication and authorization while many use the terms interchangeably or simply refer to the abbreviation auth they are not the same things authentication refers to the process of verifying who someone is authorization is the process of verifying what resources a user has access to when we log in with the username and password we are verifying who we are and that is authentication after logging in our app user will be issued Json web tokens also known as jwts while it's true that possessing a JWT confirms the user authentication has already taken place users send jwts back in a request authorization header to prove they are authorized to access the rest API endpoints and data resources today's starter code is the completed code from lesson 4 where we left off working with the back end rest API we are back to add authentication and authorization to the API now so the only change we're going to make in the package Json right now is to go from Lesson Four to now save this as lesson 8 in the name now let's move on to the server.js file not much to do here but we do need to add our auth route so it's going to look a lot like the users and notes route so I'm just going to click on line 29 press shift alt in the down arrow to copy down the user's drought and above the user's route I'll put in the auth route and it's going to go to routes and then auth routes so we'll just save that line and we're finished with the server.js now let's go to the routes folder and when we highlight that we can create a new file and we'll name this auth routes dot JS and I'll start with the Imports I'll just quickly paste those in and we can look at this it starts with Express being required and then we're creating a router from express.router this is exactly what we did in our previous routes files and then we're bringing in the auth controller but we haven't created that yet so that will be coming up very soon after that we simply have a few routes to handle so we'll have router dot route and this will be the root route so it just has slash now of course this would be at slash auth already as we're directed to the auth routes but then after that there wouldn't be anything I guess to follow low off as far as in the URL then we'll have dot post and we'll just put this here as a placeholder now because we haven't created that auth controller yet now let's move down to the next route and we'll say router.rout and this will be slash refresh so the full URL would be the root URL then slash auth then slash refresh after that we need the refresh route to be a git method so we'll just put an empty git here for now as we wait on that auth controller and then we have one more route so router.rout once again and this will be slash logout and now this one will be a post request so we'll put in an empty post method there to handle what we get from the auth controller after we create it then we'll have module.exports and we'll set this equal to router and we can save the file for now but we have some methods to create in the auth controller before we move on to that auth controller we need to create a rate limiter for our login route the root route here in our auth routes so to do that we have one more dependency to add I'll go back to the package Json and we'll scroll up where we can see all of our dependencies press control and the back tick to open up the terminal window I'll pull it down just a little bit then I'm going to type npm I and then Express Dash rate Dash limit this shouldn't take long to install and now we see it in our dependencies right here inside of our package Json now that we have that let's go to our middleware directory that we have here and create a new file and let's call this login limiter.js I'll start by defining rate limit and we'll set this equal to require and then we'll have Express Dash rate limit that we see from our Visual Studio code intellisense after that I also want to bring in the log events middleware that we previously created so it's right here in this directory already so we'll just say require dot slash and it comes from the logger file after that I'm just going to paste in some code that we can go over I'll press Ctrl B to hide the file tree and also Ctrl Z because we had a long line there that wraps so now we can look at the details of this code I'll get rid of that extra line but we're creating a login limiter with rate limit and pretty much everything you see in here then are options for rate limit that we're setting inside of an object let's just go over these first we're setting the time and we're setting this to one minute so 60 times 1000 milliseconds then we're setting the max rate limit so notice I put a note here this limits each IP to five login requests per window per minute and then we have a message if that is exceeded so too many login attempts from this IP please try again after a 60 second pause and then we have a Handler and this Handler is going to handle what happens if this limit is achieved and so we're going to log events here this Middle where we created where we can see a log that there were too many requests and where it's coming from this gets written to our error log if we need to refer to that then we're also going to send this status with the status code and the message back and then these are settings standard headers and Legacy headers that are simply recommended in the documentation for this middleware so I set those as recommended and now we have our login limiter that we will be able to use specifically in our login path so if we go back to auth routes now we should be able to include this by saying cons log in limiter and then we will require wire this and it's going to come from our middleware directory and then be in the log in limiter file then we can use this specifically in a route so this is our login route the root route so we'll just say login limiter goes right here and then we'll put a comma and then this will be awaiting what method we call from our auth controller so now it's time to go back to the file tree so I'll show that again go to the controllers directory and we need to create auth controller.js now I'm just going to paste in the simple code for now and we will review this code but quickly we just bring in the user data model we also bring in the B Crypt dependency that we were previously using to encrypt the passwords as we stored them now we'll need to decrypt those with bcrypt so we can read them and compare to what the user is providing to authenticate with we've also got a Json web token dependency that we're going to call JWT so we're going to need to add that dependency and then we've got our async Handler that we have used in the other controllers as well to catch any unexpected errors and pass those on to our custom error Handler so I'll save this right now and we will come back and describe these empty Handler methods that we have as far as login refresh and log out in our controller but right now before we forget let's add that Json web token dependency so I'm back back at the package Json control and backtick once again type npmi and Json web token and add this to our dependencies as well once I close the terminal window we now see it added to our list of dependencies here we're good to go I'll scroll back up to that auth controller and let's quickly look at these we've got the description route and access for each one the login route is publicly accessed and it's at slash auth which comes of course after whatever the root URL is and then we also have a public route for refresh which is slash auth slash refresh and this needs to be public because our access token our JWT that will give us access will have expired so the only way to get a new access token will be to have a valid refresh token that we send to this endpoint and then we have the log out method and this is going to be at slash auth slash logout and it can be public as well and we're going to clear a cookie at this log out route or with this log out method if we do have a cookie so we're exporting these three methods from this controller so before we put this logic in at least since we have the placeholders in place let's go back to the auth routes and put the rest of the information that we need from the auth controller into our routes so we're going to start out with auth controller and I'm going to copy this because I'm going to need it a couple of more times then we can say dot and we want login First we can use intellisense to help complete these after that in the refresh route we're going to have auth controller.refresh and in the log out route we're going to have auth controller DOT log out which is also in my list and we can save and we're now finished with the auth routes and we have the middleware that we're using our login limiter as well so now everything we need to complete is going to be inside of the auth controller for these three methods we just need to add the logic but before we do so I think it's a good time to review a little bit of information about Json web tokens jwts jwts are referenced as a form of user identification which is issued after the initial user authentication takes place when a user completes their login and they are authenticated our rest API will issue the client application and access token and a refresh token an access token is given a short time before it expires for example 5 to 15 minutes a refresh token is given a longer duration before it expires possibly several hours a day or even days our rest API will send and receive access tokens as Json data we will store access tokens in our application state so they will be automatically lost when the app is closed we won't put these access tokens in local storage or cookies if you can store it somewhere with JavaScript a hacker can also retrieve it with JavaScript our rest API will issue refresh tokens in an HTTP only cookie this type of cookie cannot be accessed with JavaScript refresh tokens do need to have an expiration which will then require users to log in again refresh tokens should not have the ability to issue new refresh tokens because that would Grant indefinite access the overall access token process involves issuing an access token after user authentication the user's application can then access our rest api's protected routes with the access token until it expires our rest API will verify the token with middleware every time the token is used to make a request when the access token does expire the user's application will need to send the refresh token to our rest api's refresh endpoint to be granted a new access token of course the refresh token is also issued after user authentication our rest api's refresh endpoint will verify the the token if the refresh token is valid a new access token will be provided to the user's application and remember a refresh token must be allowed to expire at some point to prevent indefinite access we are back in Visual Studio code now before we can create the logic for our controller methods we need to create a couple of secret keys that we will use to create our access and refresh tokens that are issued by the rest API so to do that we're going to store them in our DOT EnV file they will be environment variables so let's name those variables now we'll use all caps and we'll type access underscore token underscore secret and we'll have an equals and then I'm just going to shift alt and the down arrow because all I need to do here is change this to refresh token secret and this is where we will store both of those values so now let's create those values press control in the backtick to open up a term little window I'm going to scroll up for just a little more room we can create our secrets right here in the terminal and we can do it with a module that is built into node so I'm just going to type node first and press return and now we're at a node.js prompt inside of the terminal now I can require the module that we need so I'll say require and it is the crypto module after that I'll put dot random bytes in camel case so a capital B and put 64 inside there and then one more Dot and then two strings so we call the two string method and let's Supply hex now after this I'll press enter and we get a secret key and of course I'll change mine after this as well but we copy this you can do the same and after you copy it you can paste it in as your access token secret now we could press alt Z to wrap the code and you can see it's a fairly long string now we don't really need to type all that again we can just press the up arrow and IT issues the same command so I'll press enter again and we get a different string back so I'll copy this one and I'll put it in for my refresh token secret and paste that in and now I'll save the dot EnV file and close out of the terminal well I guess I could go back to the terminal quickly and press Ctrl C to escape that node prompt and then close out but there is our DOT EnV file now we have an access token secret and a refresh token secret so now let's put our logic inside of the login method of our auth controller and I'll start out with the basics here let's go over this we are expecting a username and a password to come in when a user logs in this is the authentication process and so we'll say if we do not receive a username or a password we will send a bad request status which is a 400 and a message that all fields are required then we'll look for the user in our mongodb database in the users collection and if we do not find a user or if the user is not active remember we have that active status for each user that Dan D will be able to deactivate a user even if we still want to keep them in the database because they are linked to notes so if the user is not active or does not exist then we'll send the 401 unauthorized if the user does exist we will try to match the password then and we're using bcrypt to compare the password that we received to the password that is stored in the database and again if there is not a match then we'll return a 401 again which is again unauthorized after this I'll scroll for some more room and we need to create create our access token our refresh token and our secure HTTP only cookie so let's start out by creating this access token and so you'll see I'm defining an access token variable and now I'm using the JWT that we created above when we imported the Json web token dependency so this is JWT DOT sign and now we're creating that access token here so it contains what looks like an object and we've got user info and inside that user info we have username and roles so this information is being inserted into that access token and we would need to destructure that access token when we return that information in the front end application as well so all the front end will have in state is the access token until we destructure it or decrypt it and pull this information out and notice we're now passing in our environment variable that has the access token secret to create this now here in development I'm only setting the access token to 10 seconds at first so we'll see it expire very rapidly but when we're finished we're going to want to set this to something like 15 minutes likewise right now I have the refresh token at one day and will probably come back and modify this to even a shorter amount of time when we're testing it out just to make sure it works because we won't want to wait a day to see how it reacts when it expires however with Dandy's user requirements in the user stories we have he wanted users to have to log in at least every seven days so we'll probably eventually during deployment set this more like seven days and that way they won't have to log in every day if they don't log out okay now the cookie that creates secure cookie with the refresh token we've just created above so now we have a response with a cookie we're naming it JWT and we're passing in that refresh token now here are the options we want to make sure we have set so HTTP only is set to true and this means only accessible bioweb server likewise secure is set to true now this means https same site we set To None So cross-site availability is a possibility and that's because we will be hosting our rest API possibly at one server we may have our application at another server so we do want to allow a cross-site cooking now Max age here we're setting this to match the refresh token so this would be our seven days actually if we look at this this is one thousand milliseconds now this is 60. so 60 seconds and 1000 milliseconds so there we get one minute and now we have 60 times one minute which would be one hour 24 hours in a day seven days in a week and so that's how that Max age is calculated then we are sending and back the access token in the Json so the client application receives the access token the server sets the cookie so the client application with react never actually handles the refresh token inside of this cookie but we will ensure that when react sends a request to the refresh endpoint that this cookie is sent along with it now let's move on to the refresh method inside of this auth controller and we'll once again start out with the simple stuff at the top where we're expecting a cookie with the request and if we don't have a cookie named JWT as we expect then we're going to send a 401 unauthorized if we do have it then we're going to set the refresh token variable to that cookie and after that we need to use our JWT dependency to verify this token so then we're going to call JWT verify as you can see right here after we set that refresh token variable and then we pass in the refresh token variable and then we pass in our refresh token secret that we have inside of our environment variables now we're going to use that async Handler that we're using to catch any possible async error that we did not expect but notice we've already done the verify process here we've already completed the verify process I should say and if an error is created it is passed in here as an argument and so this async Handler is going to catch errors that we did not expect but if there is an error from the verify process it's right here and so then inside this function we're responding to that error and if we do have an error there we're going to send a 403 a little different than a 401 403 is a forbidden response and that's the message we're sending along with that then we once again look to see if we have a user and if we do have the user from the decoded username that should be in side of the refresh token then we're going to say or if we do not have that user then we're going to say 401 unauthorized again hopefully we do have the user and if we do we're going to create a new access token with that username and with the roles and then we're going to pass in that access token secret again because we're creating an access token right now I once again have the access token expiring in 10 seconds which we would change before deployment this is just for development and we're responding with the access token and again this is because the refresh endpoint should issue a new access token if the refresh token is valid and now let's move on to the log out method which has the easiest logic of all we'll just go ahead and add this in I'll press alt Z because this one line does wrap but we'll once again check for cookies we're expecting to get that HTTP only secure cookie that has the refresh token and if the Cookie doesn't exist with JWT in it then we're just going to send a status 204 which means yes the request was successful but there is no content otherwise we're going to call clear cookie if there is a cookie so we will remove that cookie when the user decides to manually log out and we'll look for that JWT cookie and you have to pass in all of the same options that you did when you created the cookie and then we'll just respond with a message saying the cookie is cleared so this would by default be a 200 status response meaning successful and the message cookie cleared after that we're just exporting all three of these auth controller methods now while we've created the auth controller logic and it does handle the endpoints it doesn't protect the other endpoints yet with those tokens so we need to create the middleware that will verify a valid token every time we make a request to a protected endpoint so let's go to the middleware directory and create a new file file now named verify jwt.js I'll start this file by defining JWT and requiring that same Json web token requirement or dependency that we have added to our project and now I'll Define verify JWT and this is middleware so remember it receives a request response and next and then we'll go ahead and have an empty function here and I want to put the module exports at the bottom before I forget so I'll say module exports equals verify JWT and now that we've done that let's go ahead and look at what we'll get first inside of this middleware and I'll put this right at the top and then we'll break it down here I'll press alt Z so it does wrap we're defining the auth header because we're going to look at the header of the request and make sure there is an authorization header either with a lowercase a or a capital A so we've got the or here because there is no requirement or standard for hey it must be lowercase or it must be uppercase so it's best to look for both and of course we're creating this application full stack mern project where we have control over that but this is a good practice so you're always looking for either the lower case or the uppercase authorization header now what is required is standard for providing the authors header is what's in the value and it should always start out with the word Bearer with a capital B and be followed by a space and after that space should be the token this is all in a string so we can check that by checking the auth header we've defined above and then verifying it starts with this string Bearer and the space and if it does not we can reply with a 401 unauthorized response and after that we can go ahead and grab the token so we Define our token which is the access token and we get it by splitting that same auth header string that we were looking at above and we don't want the word bear or the space we just want the token that comes after the space so we split on the space and take the second value of course the first value being stored at the zero position this would be at the one position now that we have the token we pass that into the JWT dot verify method and we pass the token in and we've verify it with our access token secret and then we have our function here once again if we have error we note that error and then after we do that we send the 403 Forbidden response otherwise we should have decoded values and then we'll set the request dot user to the decoded dot user info dot username and the request.roll should be the same and then we can call next at the end of this now next is the part of the middleware that calls either the next middleware inline or we'll move on to the controller if that's where the request needs to go with that complete I'm going to remove my semicolons just to once again stay consistent as I'm trying to break myself of that habit and then we need to apply this middleware again our verify JWT middleware to the routes that we want to protect and so let's move back down to our routes directory and first we're not going to apply it to the auth routes but let's look at the auth routes because here we brought in our login limiter middleware notice how we could apply it to just one route we just put it here after our post method and we put in the login limiter comma and then we called the controller method now that's possible if you want to just apply it to one route likewise in the server I'll scroll down to our server we applied app.use and then say our express.json middleware here is applied to the entire app so that came before any of the routes that was applied to everything so our DOT use method could actually be used to apply everything to all of the routes inside one of our routing files so let's look at the notes route and we can bring in our verify JWT so I'll say const verify JWT we'll set this equal to require and then two dots in our middleware directory and then there's our verify JWT and now instead of applying it to any one one specific route here I'm just going to say router.use and I'm going to pass in the verify JWT middleware now this applied this verified JWT middleware to all of the routes inside of this file and now I'm going to do the same thing so I'm just going to copy both of these and go to the user routes file and apply that here as well so I'll paste in the require so we've pulled in verify JWT and then we apply it to all of the routes in the file with those changes saved we're now ready to start our backend rest API and test out all the logic that we entered so let's go ahead and type npn run Dev add a command line and get our API up and running it should be running on Port 3500 now let's go to postman the last time we used Postman was in Lesson Four as well and we can check these endpoints so we're going to go to http colon slash slash localhost 3500 that's running on our computer here in the dev environment and then we'll go to the auth endpoint so for that we need to do a few settings here let's put in the headers first we need to tell Postman the content type that we're sending and that will be application slash Json and then we need to go to the body Tab and go to the raw selection here and we'll send that Json we'll have an object and the first thing will be the username it does go inside of quotes here inside of Postman and I'm going to send the user I've created called Dan D he's our stakeholder and after that I need to send his password that's not what I'm need so I'll say password and his password is an exclamation Capital lowercase D and then one two three four five just a simple one to test out here let's go ahead and send this to the auth endpoint and we'll see what we get back we've received our access token but we've also received more than that so let's see what else and here's cookies but this is not where the cookie that we've received is you can see if I click this it says no cookies received from server back here in the bodies in the body we have the access token however up here at the top right where it says cookies we have a cookie manager here is our JWT cookie if I click on that we can see we have received this secure cookie and it has our refresh token in it so this is a different token than we received in the body where our access token was now to send this back and it will send it with this path here as slash to all urls at our Local Host Port 3500 however it won't right now because we start out with HTTP and not https so we need to remove this secure just to test it out because that's secure means it must be https which is what we would want in deployment but not right now as we test so let's save the cookie with that one change and close our cookie manager and with that change we can now go to the refresh endpoint and notice we did send to post of course with that auth request but now we're going to send with a git method here to the refresh endpoint and it will send the cookie that we just saved over here our refresh token is inside of that cookie so let's send and I have sent to the wrong endpoint I need to send actually to auth slash refresh there we go instead of just refresh now I'll send again and I expected to get a result there so let's look at our server and see what's going on and we can now see inside of the terminal that I didn't just send to slash auth slash refresh I also had a space which is represented by this percent 20 at the end so if we bring Postman back up let's go ahead and remove that extra space that we can now see is there and now we should be good and yes we did now send to the correct endpoint and we've got an access token back because our refresh token was valid this is a new access token and if we were to send again we'll get a different access token and now we didn't receive a cookie with a refresh token but let's verify our cookie is still here so now let's go to the log out endpoint which would be slash auth slash logout and it should delete our cookie so by the way I haven't cleared out this raw Json data here but we're not using it with these other requests it was only for the login request but it doesn't hurt to go ahead and leave it in there so now I'm going going to send a log out and that goes back to the post HTTP method and this should delete our cookie so let's send that it says cookie cleared in the response let's look at our cookie manager now and there are no cookies so that also worked now let's go ahead and log in once again so we'll go back to just the slash auth route and now we need this information in the body and it is a post request so we'll send in Dandy's information he's logged in he's now received a new access token and we're going to use that to access either the notes or the user's routes or we could test out both just to make sure our verified JWT middleware is working and checking those access tokens so now to do this we need to go back to the headers and here we're going to add another header this is going to be authorization I need the capital A there at the beginning or just an a either way it would take lower case or the capital their authorization and now we need to start out this value with Bearer and then a space and we can paste in our access token now this is not going to work at first and I can tell you why after we do it but we'll just check that our unauthorized is also working as planned so now this needs to go to a get request and let's just request all of the notes so let's send this and oh I said unauthorized it's actually forbidden because it was a valid or at least a cookie that we ex or not cookie a token that we expected to be issued but then it had expired and of course that creates the 403 Forbidden so that is because we only have 10 seconds right now on our access token because I put it in a very short time here in Dev mode I'm going to quickly close the terminal and let's go back to our controller where we have that 10 second setting up here where we first issued that let's see here's 10 seconds and then we had that same setting in the refresh token or refresh endpoint so I'm going to select both of those with Ctrl D set it to one minute for now and save I can open up the terminal again just so it we can see it saved and it restarted the backend server with node mod and so we're running again on Port 3500 now let's go back to postman and what we need to do here is go back to our auth instead of notes and get a new access token so it's going to be post we'll go back to the auth endpoint and after that we need to switch over here to the body and make sure we have Dandy's authentication information so we send that in he gets a new access token which we can then copy without the quotes and then we'll take that over to the headers and I'm going to replace this access token inside of the header with the new access token we have one minute now to make this work so paste all of that in and then we'll go to the notes endpoint and it will be a get request we'll send our request and now we get all of the existing notes now if this access token hasn't expired yet we should also be able to request the users and yes we've got all of the users but it probably will expire fairly soon so we'll check that out as well so let's go ahead and request the notes again and see if we still have any time left and we send yes we still got it so I'll just wait a few more seconds and we'll send it once again and I guess this is a long minute for me let's go ahead and try it one more time and now we're forbidden so we got the 403 response again so when this is forbidden that's when we need to send the refresh token to get a new access token and we will automate all of that inside of our react application and you'll find out how to do that with Redux in the very next lesson our starter code is the completed source code from lesson seven which is the last time we worked on the front end app I also have the code from lesson 8 running the back end rest API that you see here and this is a separate instance of vs code so we can try out the login code when it's complete I'm going to minimize this now and we're back at the front end code the only change I'm going to make in the package Json to start is to change this lesson 07 to lesson 09 Dash front end now let's look at the user stories we have completed number two and number four in previous lessons and we also completed number 10 through 13. so let's check those off I'll put an X in each one of those and then we'll look at what we might complete today however many of the goals that we still have are waiting for the roles and permissions to be applied to the front end app after we have the authorization from the server so what we can complete today a along with the login that we of course expect to provide is to have a log out option so we'll definitely be able to check off number seven the rest of these may be waiting on another Domino to fall in place before we can actually check them off so let's save the user stories with number 2 4 and 10 through 13 checked off and we'll move on let's go to the source directory in our code and then let's go to the features directory and finally to the auth directory and we have a lot to add here today so let's create an auth slice to start out I'm going to click new file and I'm going to create auth and then with a capital S slice dot JS notice this is not an API slice but more of a traditional slice like we would have just with Redux now I'm going to import create slice from reduxjs toolkit and after that we'll create our auth slice so I'll say const off slice set this equal to create slice and there should be an object inside the parentheses and now I'll put in the first two properties of the object so we'll name the slice auth and then our initial state will have an object that has a token property and will be set to null because we'll be expecting to receive the token back from our API then we're going to have reducers and reducers are an object as well and I'm going to quickly insert the two reducers we're creating and then we'll go over those so the first one is set credentials after we get some data back from the API we're going to have a payload and that's going to contain the access token then we're just going to set the state DOT token to access token and that's because we're already inside of the auth slice here with the name auth so we don't have to set state DOT auth.tok token we know we're in that so then we also have a log out reducer here and that's just going to set the state DOT token to null at logout time and now we need to export the these things so just underneath I'm going to export set credentials and log out they're both the action creators here from the auth slice dot actions so those are exported we'll also export the auth slice dot reducer itself so all the reducers because we need to add that to the store and then we're creating one selector that's select current token notice here it does refer to State DOT auth.token and remember auth is here because it is the name of the slice we created above and now that we've created our slice we need to go to the store that's inside of our app directory so there's store.js and we need to add it to our store so first we need to import that so we will import auth reducer and that is going to come from and then we should go up out of this directory and then we're going to look inside of the features directory and then inside of features we have auth and inside of auth whoops I'll go back we should have a slash there then we should be looking in the auth slice now once we have imported that auth reducer we should be able to put it inside of the reducer for the store here where we have the API slice of course supplied as well so now we'll put in auth and have our auth reducer now let's go back to the auth directory and as you might guess we do need an API slice as well so let's now create that so we'll have auth and then capital A for API capital S for slice dot JS this shouldn't be A New Concept as we created separate slices for the notes and the users as well and we extended the API slice and that's what we'll do here let's start with our Imports first we're going to import the API AI slice so we can extend it we're also going to import the log out function or logout reducer that we created inside of the auth slice after that let's go ahead and say export const and we'll have our auth API slice we'll set this equal to API slice that we imported dot inject endpoints and then we'll have an object inside of that and now that we're injecting endpoints we should Define those endpoints so we'll start here with that and then we'll pass in the Builder and that's an arrow function and there will be an object inside of this where we can put each endpoint we'll start with our login endpoint and we'll quickly break this down so this is the login we call Builder dot mutation this will be a mutation and now we Define the query inside of the mutation we're passing in what we're calling credentials this would be the username and password that we send with the query then we'll have this sent to the slash auth route and this will be a post method and here we'll spread in the object that we expect to receive as credentials into the body object and while that endpoint is fairly straightforward the next one has a little more to it so I'll paste this in and we'll break it down so we've got our login endpoint above and now we have a send log out notice I didn't name it logout because we're importing our logout reducer from auth slice we have a send log out and this is also a builder mutation and we Define the query first and this goes to our log out route that we defined on the back end so it's slash auth slash logout and the method will be post which is expected after that it gets just a little more complicated so let's go over what we have here rtk query provides an on query started function that we can call inside of our endpoint now what this does and it's async it accepts an argument that we're not really defining but it needs it here as is the first parameter but then it also provides things like dispatch and query fulfilled so we can verify our query has been fulfilled and because we're putting async here we can await that so I'm putting a try catch inside of our on query started function and we're awaiting the query fulfilled now notice I have this commented out because you could set const data equals query fulfilled it returns a data property and then you could log that data and you'll get the message from the rest API that we created that says cookie cleared and that's what you should get as a response so if you want to get that go ahead and set the const data and destructure it from query fulfilled I just wanted to put that in there as an option and then of course you can view it with a console log after that we're going to dispatch our log out reducer that we imported from the auth slice this will set our token to null in our local state and we need that as well so we've logged out on this server we're setting that token to null and then the API slice which is separate from the auth slice and this is going to need to be cleared as well and so we can call Api slice because we imported it up here at the top and then we go dot util dot reset API State and that is a method that can be called and it will clear out the cache and the query subscriptions and everything to do with our API slice so that also needs to be taken care of at logout now this doing all of this inside of onquery started keeps us from needing to import the dispatch or I should say use dispatch into a component and then dispatching each one of these in every component so we can put it here and then we can just call this log out endpoint the mutation that we would import into the component and it will take care of everything so this is a more efficient way of doing that if there is an error we're just going to log it to the console they're really shouldn't be when you log out but if there is a log out error this is what we'll do here and now I'm going to scroll for some more room and we'll add our third and final endpoint and it is just the refresh endpoint it is also a mutation and we're just defining the query which goes to auth refresh and it's a git method because essentially we're just sending a git request that includes the cookie when we send it and it will hit that refresh endpoint so we could get a new access token when needed now just like with our other slices what we need to do is export all of the mutations that we have now created so you can see we have export const and we're exporting use login mutation you send log out mutation and use refresh mutation and with that complete we are ready to work on the login component that will use some of these things and you can see we've already started the login we just put in a placeholder functional component let's start at the top by putting in some basic Imports and we'll break these down so we've got use ref you state and use effect from react we also have use navigate and Link from react router Dom but that's not all we need we also need some things from Redux and rtk query so we've got use dispatch from react Redux set credentials from the off slice we created and then the use login mutation in our auth API slice now let's start at the top of the component and we'll bring in some of these basic hooks that we've imported from react so we're creating a user ref that we will use to set the focus on the user input and error ref that we'll use to set the focus if there is an error and then we've also got State for the username the password and a possible error message after the state I'm going to scroll up just a little bit and we'll go ahead and use our use navigate hook to bring in the navigate function use the use dispatch hook to bring in the dispatch function and then we've got our use law login mutation hook and will bring in a login function that we can call when we need it it's also going to have an is loading state that we're going to use mutations do provide other states but we will not need it in this component now let's go ahead and Define an error class and then also check that is loading state so we're defined in an error class first and if we have an error message in our state for error message then we're going to apply the class error message this is a ternary statement otherwise we're going to apply the class off screen so we'll see where this is used as we create our form also we have this is loading state that we are checking from when the mutation is called so this is where it's actually right here I scrolled up too far this is where we're using the mutation when we call log in it will have an is loading State and if it is loading we'll just return this simple loading paragraph you could use a loading spinner if you have one that you like to use and now let's define our contents so I'll say const content and it will be on more than one line so I'm going to provide parentheses as well and then here instead of this placeholder H1 login I'm just going to return the content as well now we'll pick our content inside of these parentheses I'm going to scroll up just so we have some more room and I'll paste in the first part and of course notice it gives us a closing Main and we're starting out a section here with a class name of public remember these class names align with my CSS if you've provided your own you could do something different here we have a header that says employee login now remember this is not inside of our protected routes where we have a dash with the dash header and the dash footer this is a separate public page much like the first page that provides some information about Dandy's business so right here we're just going to have to provide our own header and footer for the content of this page let's go ahead and close everything out after that closing main tag so we're going to have a footer as well that's just going to link back to the first page of the website there's also a public page and then we close out the section now inside of the main element is where we're going to put our form so I'll start the form here but not add everything yet we could add the closing form tag just so it lines up and doesn't show that error for us but inside of this let me go ahead and save and it should indent there we are we'll start out with a label and this label is for the username and notice it has an html4 that should align with the ID attribute of the input for username also notice the class name for form is form which lines up with more CSS in my CSS and then it has an on submit Handler called handle submit that we have yet to Define so we'll come back to that other than that you can look at the different attributes for this text type input notice we are applying the ref we created earlier the use user ref and then we're applying the state with the value so this is a controlled input and then the on change also has a Handler that is handle user input that we have not defined yet we want autocomplete to off because we don't want to show any other possible usernames that have been entered and we do want to make this required now let's provide a blank line underneath and we'll put in the information for the password as well very similar to the username input you can see the html4 is password that lines up with the ID password the type is password so it doesn't show the entry it also has a Handler that we have to create yet called handle password input it's a controlled input with the password State and it is required and then when you only provide one button inside of a form by default it is the submit button I'm going to press Ctrl B just so we can see this a little better but we're providing a button with class name here and that matches up with my CSS once again but we don't have have to say that this is a type submit by default it already is and then we're just putting sign in on the button itself now let's go back and provide those handlers and a couple of other things that we did not provide at the top of the component one of the things we did not provide was how to handle the refs that we've put on both the username and password input so I'm going to put in the use effects that handle those or at least handles the first one for user ref and what we've got here is userref.current.focus and this is an empty dependency array and use effects so it only happens when the component loads and it puts the focus directly in that username field the Second Use effect is to clear out the error message State when the username or password State changes so our user may have already read the error that has appeared and then when they once again type in the username or password field it will clear out the error that is being displayed because they've already process the air there's no longer reason to display that error and speaking of displaying errors I believe that's the one thing I currently left out of our main area so let's put that error in right above the form and here we'll be able to see how it is applied so we have the error ref on the paragraph which we will use in just a moment we also have that class name error class that we defined above and then there is an aria live attribute and it says assertive that means when this gets focused it will read like a screen reader would read the error message that appears and that's also important to do now let's create those handlers for the username and for the password fields and for the form itself I'm going to start underneath the use effects we've applied and then I'll put in the first two handlers we've got one for handle password input and one for handle user input and you can see they're very simple they receive the event itself and then they set username to event.target.value or set password to event.target.value the handle submit for the form is just a little more complex so let's start building that and I'll put the closing curly brace there we're going to start out by just having this be an async function and it receives the event and then we're saying event dot prevent default that's the first thing you need to do when you submit a form really because otherwise the default is to reload the page and you don't want that to happen inside of your single page application and now we're going to need a try catch block so I'll start with the try then we'll add the catch here after and I'll receive an error in the catch let's put in our tri-block contents first I'll paste this in and go over it we're going to get our access token back after we call the login mutation function this is what we received this login function from our use login mutation hook we can await that result we pass in the username and password State when the username and password are complete then we call wrap at the end because I'm not using the error State I actually want to use this in a try catch block and that's what we do in Redux if we want to use the try catch block instead of using the rtk query states such as is error so I'm doing that to catch the error here instead we're also going to dispatch set credentials which we mentioned earlier and we receive an access token back and that's going to be our credentials so we set that state DOT token then we have set username and set password just being set to blank and that's great because we just want to empty out that state and then we have navigate that will take us to the dash after we've logged in so this is all if it's all successful and of course nothing happens until we've awaited this login if we have an error there it will go directly down to our catch error so these things won't happen unless we are successful now the catch block might actually be considered a little more complex than what we just went over for the try but let's look at it it it's if we have an error status or if we do not have an error status I should say here's the exclamation mark saying if we do not have an error status we're going to just say there was no server response and that's the only time we shouldn't have an error status if we have an error otherwise we're going to check the status and if it's a 400 we know that should be missing a username or password 400 usually means bad request and that would be the case for a login 401 would be unauthorized or we can just go ahead and set the message and remember it won't just be error.message here we'll be receiving error.data Dot message and I'm using optional chain in here just as a precaution after that we have our error ref and we can set that error ref.current.focus so the focus is then set on our error message which would be read by a screen reader as well because we put Aria live attribute set to assertive and one last look at that handle submit it and I believe it is completed yes so now we have finished our login component let's go back to the file tree before we test this out and let's go up to our components directory and go to that Dash header because once we've logged in we also need to provide a log out we're currently only importing link from react router Dom but that is about to change so I'll paste in the Imports and we can look at those we're going to have use effect from react then we're also going to use a font awesome icon and then we import that very icon that we need which is fa right from bracket it kind of indicates a log out it's often used for a log out and then there is use navigate link as we had before and use location coming from react router Dom but that's not all we also need to import our use send log out mutation from our auth API slice and before we move into the component I'm going to import some cons that we are creating here and these are regex constants so I I have a dash regex a notes regex and a user's regex we're going to use these to compare to the location in the URL to verify what location we are on or not on and we can use those to decide if we want to display something such as a button in our header or not and now I'm going to scroll up a little bit and we can start inside the component that we already have for dash header and I'm going to import some of these hooks so we're going to get the navigate function from use navigate we're going to destructure the path name from the use location hook and now we're going to get the send log out function from our use send logout mutation hook we're also going to get several things about the status when we call the function is loading is success is error and error much like you've seen in other calls to rtk query hooks I'll scroll up just a little bit and underneath the call to that hook we're going to put in a use effect and use effect is going to check the is success status and of course we need to put in the navigate function just to appease the warnings that we might get inside of the console even though we know that the navigate function won't change so if is Success then we're going to just navigate to the root and this is because it's a log out so we would go back to the root of the site other than that we have an on logout clicked Handler that is going to call that send logout function that we're getting here from you send logout mutation and underneath that I went ahead and put in the if is loading we're just going to return the paragraph that says logging out and if the is error status is true we're going to return an error message here that we're going to get from our hook and as I look at this I realize I need error.data and then I'm using optional chaining again for the message underneath the error I'm going to define a class class for the dash and this could be done with the ternary as well but I just think it's easier to understand this way so I did it like this because it's kind of long I'm going to press Ctrl B to hide the file tree so you can see it all as well I'm defining this Dash class with let here and just setting it to null but then we're also checking to see if the tests here for the different reg X's we're essentially making sure that we're not on the dash path itself the root and we're not on the notes list or the users list we do not want to be on any of those pages and if we're not we will set this Dash class to a dash dash header two underscores container dash dash small I'm using a bem naming convention here if you're wondering why my class name is so long for this class that I have inside of the CSS but anyway quickly defining that class and you could do it with the ternary if you want to but this is how I'm doing it just because it's long it's a little easier to understand this way I think now let's go ahead and put in our log out button that we will see in the header we're going to Define it first so it is a button has a class name of Icon dash button the title is log out and we're going to call our on logout clicked Handler which I believe we already defined up here it essentially just calls send logout that we received before and now let's scroll down to see the rest of our content we have already defined content what we haven't done is put that Dash class that we created inside of our Dash so let's go ahead and add that it's going to be on this div that we have that has a class name of dash dash header two underscores and container but it's a modifier the first thing we need to do is go ahead and put all of this inside of curly braces here and so we'll do that first and then we'll turn this into a template literal so I'll select the first double quote and press Ctrl D to select the second one and press address back tick instead so now it is a template literal and now we can insert a variable and so now I have dollar sign curly brace I'm going to insert my Dash class variable and this way we can add this extra Dash class if it does exist and otherwise I'm just going to put the log out button below and here instead of saying add nav buttons later I'm just going to say we're going to add more buttons later because we absolutely will add buttons to our header depending on the path name in the near future once we have the different permissions worked out with our log out now added to the header let's go ahead and press Ctrl back tick and start up our react app now you should have already started your back end as well as I showed mine was running from the beginning of this tutorial that is the code we completed in lesson 8 which is the back end here we're in lesson 9 and we're starting the front end and we can check our changes so let's see what we get once the react app starts up we have successfully started let's go to the login and here is the login page I'm going to log in with Dan D and the password I put for him he is our main stakeholder the owner of the business and he's should have an admin role this is worth noting as well if you did not already create those test users or a user for Dan D before you added the verify JWT middleware in the last lesson then it won't let you create those new users so you need to create one with Postman before you've added that verify JWT middleware and hopefully you've done that in the past as I displayed that I had just noting that okay I can log in now with Dandy and I'm here on the home page notice we have this log out button in the top right of our header and we have the different pages we can go to now we do not have a JWT being provided when we make a request we should have received one and we can check that in our Redux State component but let's look at what happens if we try to view the tech notes we're not sending that access token back to the server so it says we're unauthorized the same if we try to view the user settings right now if we go to add new user we shouldn't have a problem getting to this page because it does not require any new data or any I should say any existing data from the API we're not making a request to go to this page so we can get there if we go back to home we're going to have a problem when we try to add a new tech note so we do that and we've got nothing and if I expand this over to full screen we should be able to open up the console and we see some errors here as well so we need to fix this not because it will be much of an issue in the future but I don't like to leave this hanging as it is so let's go back and we'll refresh here on the dash and we should get our Dash page back but what we need to fix is in the new note I'm going to drag this over and we'll drag Visual Studio code back and we can see what's going on here I'll close out the terminal we can leave it running in the file tree we should go down to features and then notes and we should go to our new note component the very first one and here's where the issue lies we're expecting the users to go into that new note form because we need to know what users exist so we can assign that new note to an existing user there's a couple of things we can change here first of all this use selector is calling select all users which has been renamed just from a select all and that select all memoized query always provides an array so even if we just check users here we're going to have users it's just an empty array so this isn't going to work exactly as we expect instead let's check to see if that array has length and we can do that right here and I'll paste that in and then we're just going to return a simple statement that says not currently available after that we can shorten up the next line and I'll just highlight over this one and paste this in and we'll just put our content equal to the new Note Form where users is passed in and return the content so essentially if we don't have users for any reason or we don't have any length of users we're just going to say that that form is not currently available so once we fix this we should be able to go back now and well I don't really need to change that I'll put over here to the left let's go back and once again we can just refresh to make sure we've got those changes and try to add a new tech note and now we get the not currently available and that's because we do not currently have access to that data so instead of unauthorized we're just putting that message in now when we are authorized or when we've protected those routes then another message will occur so we won't have an issue there I just wanted to temporarily fix it for now and it's nice to have everything at least responding as expected without an error at this point now I'm going to drag the app to a full screen and I'm going to open up Dev tools and inside side of Dev tools we can clear out the console but let's go to Redux and we want to check our state here and actually our Redux Dev tools if you have them installed it likes to have a little more room so I'll move this over I don't need it quite that much there we go I just want the state down here below and we're looking at the tree View and this has our off State we're logged in or we were logged in and we have a token null now let's go ahead and refresh this and yes we should have a token null after the refresh we don't have in our protected routes yet so we're not getting kicked back out so let's go ahead and hit the log out that kicks us out to the beginning we'll do the employee login once again and I'll do Dan D I'll put in his password and log in and now we can see our auth state here has a token and we have our token inside our API has also made some requests and it has subscriptions as well so we can see the get notes and get users although back in the console we see those requests are replied to with a 401 unauthorized because we're not providing that token when we're making those requests we're also seeing these subscribing and unsubscribing notes that we have inside of our prefetch component that we created in the previous lesson 7 tutorial we're in lesson nine right now okay so that's what we have in the console and our state is showing here in Redux what we want to test now and we're not providing that token yet when we do those requests but what we want to test is our log out to make sure that the subscriptions and the queries all go away that it resets our API State and the token is set to null so let's hit that log out and now you want to select your last Choice here inside of where your state was and it will show the different requests up here at the top I know the window is a little scrunched here is our log out the token is null we currently still have the subscriptions but then when we go to rest API stay or reset API State I should say the subscriptions are cleared out the queries are cleared out and everything is as expected and we can scroll on down to get to the very end and we can see the same thing the token is null this is the current state we're in and our API has been cleared out so our logout is working as expected and as I had mentioned before when we log in we're currently not able to see those lists that we had so let's log back in here's the console we can clear this out and see what happens in the console as we log in now so put Dandy in and once we get logged in we see the subscribing unsubscribing when the component unmounts and that's the strict mode from react 18 and then subscribing once again so that's all in our prefetch component and then we have a couple of 401s when we request the notes and the users that's unauthorized so our prefetch didn't really work they were both unauthorized requests and now of course when we go to view the tech notes we are still unauthorized and you can see that request here so we can go back same for users and we're unauthorized and now the changes we made to the tech note page gives us the not currently available message which is fine we can go to the add new user form although if we tried to add a new user we would once again be unauthorized now in the very next tutorial coming up we're going to learn how to provide that token with the request and of course if that access token is expired we're also going to learn how to automatically Supply the refresh token and make that request to get a new access token we're going to do that all with Redux and rtk query in the very next lesson our starter code today is the completed code from lesson nine so we're just going to open the package Json and change this lesson 09 to lesson 10 and we can save the package Json and let's move to the user stories now previously we checked off 10 through 13. we've also got number two and number four checked off of our list and really I think we could check off number seven because we provided our log out option in the last lesson but the others were not quite ready to check off yet if we look at some of these we're very close like add an employee log into the notes app we really did that in the last lesson but I can't say it's complete until we go ahead and provide those permissions and role-based user access so we're not going to check that off yet kind of the same for eight and nine where we have require users to log in at least once per week we'll eventually set that refresh token to a seven day expiration but we're not quite finished with that yet also provide a way way to remove employee access as soon as possible if needed we had put in an active status for each employee that can be checked or unchecked and we'll go ahead and check that off when we also put in the permissions so only an admin or manager can check that or uncheck it so we're very close on some of these and I think a lot of these will fall into place after we get those permissions in place we'll go ahead and save our user stories for now and let's move on to our source directory and in the source directory we need to open up the app directory and then the API directory and then the API slice.js so far this isn't too complicated and we've been injecting endpoints into the API slice in other files such as our notes feature our users feature and even our auth feature but today we need to do something here that will allow us to use our JWT access and refresh tokens and the first thing we need to do is go ahead and Define a base query so I'm going to come right here on line two to get a little extra room and paste in a base query that we can break down and see what it's doing notice previously we assigned our base query right here in the API slice and it is fetch base query now we're going to use this base query instead and since it has the same name as the object key right here so it matches we'll just go ahead and remove all of this and use the comma so we don't have to say base query colon base query we can just put in basequery and the comma into the object for create API now let's look at what this does we're putting fetch base query here so we're setting our base query equal to fetchbase query previously we're just providing this base URL notice right now it's localhost Port 3500 and that's what we're using in development we would need to change that upon deploying but then we want to add some other things as well one is to put credentials and include so that's an important thing to add and that way will always send our cookie remember we have that secure HTTP only cookie that contains our refresh token so when we need it it will be sent but also we need to prepare the headers and that is a specific thing that's available to the fetch base query and the first thing that gets added to it I said specific thing I should say specific function that we can put here with our fetch base query and the first thing we pass in the first parameter is the headers and then it has an API object now this API is specific to prepare headers one thing we can destructure from that is get state so we could say API here and then put API dot get state but I'm just destructuring git state right here and that allows us to get the current state of the application so notice I'm using get state I'm calling that and then I'm looking at the auth state and then I'm getting the current token that we have and I'm assigning that token so if we have a token then we're setting the authorization header notice we're using the headers here that is the first parameter and we set authorization and then we pass in that specific format that is expected it starts with the word word Bearer with a capital B then there's a space and then you have your token and so that sets our authorization header and we simply return the headers here from our prepare headers function now this is applied to every request we send I'm going to save this but before we start our app I want to point out that I am also running the code from lesson 8 which is our backend rest API and that's the last time we worked on it notice it's running here in a separate instance of Visual Studio code so our rest API server is available to our react code that's in this new lesson 10 repository so I'm going to go ahead and press Ctrl in the back tactic open up a terminal type npm start and we should see our application start fairly quickly in Chrome okay with the react application running I'm going to drag it to full screen and then I'm going to press Ctrl shift and I to open up the dev tools and notice I'm looking at the network tab instead of the console so find your network tab in your list of tabs and we want to see the requests come in and see what happens also I should note that in that backend code and I can pull it back up quickly that from lesson 8 that we're running I set the access tokens to expire in 10 seconds I set the refresh token this is just for testing purposes to expire in 20 seconds and so this will just help us see what happens much faster normally we will set this to where the access token expires in 15 minutes and we'll set the refresh token to seven days for our deployment for this specific application however wanted to point out we're at 10 seconds and 20 seconds right now so let's go ahead and log in and now I'm going to put Dandy our stakeholder and his login once we're logged in you can see we immediately had a auth request and then we prefetched the notes and the users now we can view the tech notes and we already have a 403 Forbidden because we were past our 10 seconds so let me log out and do that again because we'll need to do it fairly quickly and now let's view Tech notes and we have our Tech notes but it expires fairly quickly now we're not using the refresh token yet and remember every 15 seconds we have the polling set so our Tech notes re-queries that information and so we should see it expire and we will get a 403 Forbidden and that's what we see here in our Network tab so we are using our access token and we can briefly see those for 10 seconds right now before it expires when the next request goes out which is actually in 15 seconds we get this 403 so now let's make some changes and we will go ahead and start applying the refresh token as well I'm going to close the terminal window and now underneath our base query that we created and we do need it I am going to paste in a query wrapper that we create here and this is going to be called base query with re-auth now this is going to accept args which are going to be the arguments like we're passing in essentially to our fetch base query here it's the URL and things like that this has its own API so not to be confused with the API object I talked about with prepare headers that's a separate API object but a base query has an API object also that we can use and then there is an extra options object and we just pass all of these in even if we're not using them so we see args API and extra options now I put console logs for each of these now you could uncomment any one of these and you could see what we would get but extra options would be undefined unless you passed in a value and here I have the example of shout being the key and true being the value but these are just examples I wanted to leave those in just for the purpose of this tutorial now we set our result with the keyword let equal to a weight base query that we previously defined and we pass in our args API and extra options just like we have above now this would be the result that we get this result right here that we get from the first request so we have used our access token as defined up here with our base query so it passes the access token but now notice we're looking for a 403 so if we get an error status of 403 I'm logging sending the refresh token and after we send the refresh token which I'm commenting right here I'll press Ctrl B so we can see all of this then we're going to get a refresh result so notice now we're going to await the base query and our args that we see here is a new route to go to it goes to the auth refresh and then we're passing in API and extra options again what we expect to get as our refresh result is data and the data should hold the access token so now notice we are dispatching set credentials and we are spreading in that refresh result dot data we could just structure the access token from there as well but I did it this way in this place also with set credentials being used there we need to go ahead and import set credentials at the top so before I forget to do that let's come back up to the top and put in our set credentials that we defined in our auth slice that was that action Creator and then it sends the payload and sets that token in our Redux State okay now let's scroll back down after we have set credentials then we retry the original query notice we're using the base query again right here but we're passing in the args once again and now remember if you're wondering what the args are versus passing in this route let's scroll back up here and you can uncomment these and see but it will be the request URL method and body that we previously set so you can double check that with the console log statement if you want to okay that should then retry that original request and we should once again get our data because we've applied a new access token so what happens we try the original access token if it doesn't work and we get this error status 403 which is forbidden then we send the refresh token and then the refresh token should give us a new access token which is set here with set credentials and then we retry the original query but there's an else if we don't have the data we're going to then set the error status to 403 so we will have a forbidden from our refresh token try as well so we'll have two 403s in a row and then we're setting this message here to dot data.message your login has expired and we will see that and I've put a specific space after this on purpose because we're going to provide a link after that but we do that in the component where we will use it and then we'll return that refresh result which would be the error that we're sending on otherwise down here at the bottom we're returning the result which is what we hope to get after we retry that original base query or it was up here and it was successful and we didn't need to have the check for the 403 if that was the case this is the original query that might succeed without all of this if the access token hasn't expired I hope all of that makes sense and it really helps to understand what happens with an access and refresh token and it might help you to go back to lesson 8 and review that presentation on the jwts that I gave in that lesson now there's one one more change we need to make and that's that we're not just going to use this base query anymore we're going to use our base query with re-auth so once again this base query just becomes the key for the object and then we provide basequery with re-auth as the actual value here that we're using as the base query with these changes saved let's make sure our app is still running yes I opened up the terminal that says compiled successfully let's close the terminal drag Visual Studio code to the left our app is on the right I'll drag Chrome over for a full screen open up Dev tools so we're on the network tab once again and let's get ready to log in and see what happens now with these new changes in place that also use our refresh token we're logged in we've got the auth notes and users let's go ahead and go to the notes page we've requested notes again now because that used the get notes query that was on our notes list page and that starts a 15 second counter before that polling interval requests that data once again and we set that and this is what we see happen it failed because our access token only lasted for 10 seconds but the refresh token lasts for 20 seconds so we use the refresh endpoint we got a new access token and requested the notes again but now the second time we request the refresh token has expired at 20 seconds because this is now 30 seconds later and so our notes didn't succeed and then the refresh token did not succeed and now we get that your login has expired so at this point it would be time to log out and then we could go back to the employee login if we needed to so when we extend and those tokens to 15 minutes and 7 Days of course we won't get kicked out so fast but this shows us that they are working what happened was we prefetched all of our data we hit the auth endpoint we got the notes and the users then when we went to the notes List It requested that data once again because we loaded that component and then after the access token expired we used the refresh endpoint and we got the notes data again that was when we pulled at that polling interval of 15 seconds to once again refresh that list and then the second time we pulled which was 30 seconds the refresh token had also expired and so we see those failures there and then we hit the log out but there's something to note here we're continuing to request the notes and getting a 401 every 15 seconds this is something I discovered and I might report this as a bug I'm not sure that it is though so I need to dive into that but I did figure out a fix for it so now let's look at that I'll go ahead and close out the dev tools let's go back to visual studio code and look at how we can prevent that request from continuing to repeat after we've logged out let's open the file tree as we're finished with the API slice so Ctrl B I think I pressed control back tick there and open the terminal by mistake but what we want is the file tree and now inside of the file tree just so we can identify these queries better and discern those from the actual prefetch queries let's go to the notes list and the users list and instead of this undefined we put in as the first value of this use gitnotes Query or the first parameter I should say let's go ahead and put in notes list and that will give it a label and now let's do the same thing for users on the users list.js file we had undefined let's go ahead and put in users list and we'll be able to see these in react Dev tools and just tell these queries apart from the ones that are used in the prefetch component and now let's go up to the auth folder and we want the auth API slice this is where we have our log out request and then we have our on query started function and what we're doing here is waiting for query fulfilled let's go ahead and uncomment this let's put this all on the same line so you can see that message we get back which will say the cookie was deleted and we can log that right there but after that what is happening is we are logging out and we are resetting the API state but then it's still hanging on to that one query whenever we log out from our users list component or directly from our notes list component I noticed when we logged out from the other components or if we chose is the same log out button of course it's always in the header from other components we do not have this issue but we're on when we're on the users list and when we're on the notes list we do now those queries that are created by rtk query are supposed to unsubscribe the components when the component unmounts so we're missing something it's taking just a little bit of extra time and that is actually what I did to solve the problem for this application I just went ahead and put in a set timeout function and then we'll have this Anonymous function inside of set timeout and I put the dispatch of the reset API State inside of a set timeout and you could play around with the interval or the actual delay time it's not an interval so much because it only happens once I just set it to one second and that should give it plenty of time to go ahead and confirm or realize that it has unmounted that list component whether it's the notes list or the users component and then it can reset the API State and then it gets rid of that subscription so like I said I might submit this as a bug I'm not sure that it is a bug though it might be something that I am not realizing that I'm not doing in the correct order but I think I'm doing this correctly with the on query started to follow up our action here otherwise I would have to import use dispatch and whatever I wanted such as my logout action Creator or my set credentials action create Creator into a component every time I wanted to use it but this way we can put it into the actual request here that we have such as send log out with our query and then using on query started this will be called wherever we would call this mutation and likewise you will see when we create our persist login component I did play around with this and imported use dispatch and that actual set credentials action Creator there and I still had this issue so this is the place that I have found to solve the issue with set timeout for now with this in place let's go ahead and try this again and if we need to we can even look at react or Redux Dev tools and see the difference so I'm going to once again open this up and we'll log in right now it is still currently subscribed as notes so we saw that failure but here we have auth notes and users we've got everything here we go and we've requested the notes again now let's look at our Redux component and we can see some State here as well and this is where we want to go to see all of the state and here's the subscriptions uh if I could get it to stop there we go so there's our subscriptions we have two undefined those are the pre-fetch but then here's the notes list that we did label and Define and now if we unsubscribe let's look at our last state here we should no longer be subscribed to everything that we have here let's see well we're still getting the pending and rejected from that previous subscription I believe let's go ahead and try this again and this time I'll refresh the app now we have no State whatsoever let's go ahead and log in now that we're logged in let's look at our current state here I really would like to drag this over so it's a little bit larger have a little bit more room to work with everything there we go now our API comes down and there's our subscriptions and come to the end let's go ahead and look at the tech notes we've got the tech notes now let's log out and we have no subscriptions we can see where we logged out where our state was and we did have subscriptions we had get notes undefined and get users undefined that came in from our pre-fetch component get notes was from the notes list component then we have our subscriptions here that we're removing I believe and these are easier to see in the other view but then once we get down to the reset API it removes all of them so this was actually different fulfilled mutations or not I believe you know there removed those subscriptions one at a time there we can see those removed when we're highlighting each one of these there remove the mutation there it removed the notesless subscription and there it cleared out everything with the reset API State before we did not have that so that's just important to note if you don't put in that actual set timeout with a little bit of delay you will have that one subscription from your git users or your get notes that is still active okay with that work around now in place let's drag this back to the left and once again look at Visual Studio code we are using the jwts now we have the log out working correctly and we're ready to work on persisting our login State even when we refresh the pages I'm going to drop the features directory down and what we need to do is create a new directory called hooks and inside the hooks directory we're going to create a custom hook named use persist.js this is a simple component I'll paste in and review with you and it's very much like a used local storage component and if we were actually going to use local storage for more things in this application I would probably create a used local storage component and then we could still persist and do other things with it but this is specifically for our persist data so we have use persist we're setting persist and set persist with use State and we're looking at our local storage and if persist does not exist in our local storage it is simply false to begin with we're using the use effect hook as well and when persist changes we set that value to the local storage and then we're returning persist and set persist so we will use this very much like a use State hook but it's specifically for our persist data so let's go back to the file tree now and we want to open up the features directory open up the auth directory and choose our login component there we're going to import our use persist hook that we created at the top and then underneath our state we can use persist as well so we'll say const we'll have persist and set persist and now let's set this equal to use persist and now I'm going to scroll down to where we have our handlers and underneath the handle input and handle password we're going to handle the toggle of our persist and what we're going to do here is just use set persist take the previous value and set it to whatever the opposite is because it's really just going to be a check box and now we'll scroll down to the bottom of our form and we have a button at the bottom right now but we want to put this underneath the button and this is going to be that check box just a toggle so our label says html4 persist and we have a class name applied from my CSS and then this input right here is a check box it has a class name of form two underscores and check box remember these class names go back to my CSS if you're using my CSS the ID is persist which much must match the html4 attribute that we have up above and it is a controlled input so we have an on change with handle toggle and checked is equal to persist and notice I'm labeling here just trust this device next to the actual input the check box that we're providing let's save these changes and we didn't save use persist yet either or if you hadn't go ahead and do that as well so we've saved our use persist Hook and the changes to our login.js now we need to create a persist login component before we do that I want to highlight there is just one change I added to my utility classes of the CSS file note this class error message I'm now choosing any link inside of the error message because we're going to provide one and I am just styling it adding the underline and the air color so go ahead and grab these the entire CSS file if you want to just note that I have added a change to it from the previous lessons and now inside of the auth directory let's go ahead and create our persist login component this is the component that is going to help us remain logged in even when we refresh our application so I'm going to paste in the Imports first and we'll take a look at those there are several so note we have the outlet from react router Dom we're importing use effect use ref and use state from react we're importing the use refresh mutation that we created in the last lesson in our auth API slice we're importing the use persist hook that we just created we're also importing use selector select current token from the auth slice and then link from react router Dom and now that I'm looking at this link was a late edition let's go ahead and cut that out and let's just put link right after Outlet since they both come from react router Dom and we can remove at least one line out of all of those Imports with the Imports complete let's go ahead and start our component with rafce the es7 snippet that helps us go ahead and create a quick component a functional component it and now we have our persist login component and let's start with some of the state at the top and also a use ref so notice we're just pulling in persist and not the set persist from the use persist hook we created we're pulling in the token using our use selector and the select current token selector from our state and that would be the current token that we have received that will give us the access that we need it's an access token we're also defining effect ran and this is something I'm doing specifically for react 18 and I do have a tutorial on how to handle strict mode in react 18 and that's exactly what this is going to be for we're setting this use ref to false right now and that is the effect Rand value now we're going to have true success and set true success I separated this out because it is something that's a little unique also that we'll need to talk about next we'll go ahead and bring in our refresh mutation and this look looks like many of the other hooks we have used from rtk query so we have our refresh function and then we have several States one new state to notice that we haven't used before is is uninitialized that means the refresh function has not been called yet and that's another state that we're going to use and now I'm going to scroll up for some more room and after our use refresh mutation hook we'll go ahead and put in our use effect and we'll cover this there's quite a bit to cover here as I'm doing something that was covered in a separate tutorial about handling react 18 strict mode so that's what you see first we're using our effect ran which was the use ref defined up here with the initial value of false now we have to get the value from the dot current property so now I'm saying if effect rand.current is true now the first time use effect runs it will be false but in strict mode what happens to every component is they mount then they unmount and then they remount so use effect runs twice when you're in development using strict mode so if effect rand.current equals true will only be true the second time and that's because we're going to set it to True later on now next it says or process.enb dot node underscore EnV not equal to development so if we're not in development mode it's going to go ahead and do this as well so that's because react 18 strict mode only happens in development so if you have that in effect in your index.js and when you use create react app it is in there by default so it's good to know this so this will have a problem actually if we do this twice and usually it's okay and components won't have a problem but this does create a problem if we're going to use that refresh token so we won't only want to send it one time time and before I get into the verify refresh token function just to continue on with this strict mode notice using the cleanup function here so after use effect runs the first time the cleanup function sets it to true the effect ran.current equals true and then use ref will actually hold that value even after the component unmounts and remounts and so that will be okay so when we come back through this will be true now you see our function verifying refresh token or verify refresh token it's an async function and notice I'm just logging to the console here so we can see it happen verify and refresh token and I've got a try catch block now what I did was comment out the response because we don't really need it here we're going to set this response in our on query started back in our auth API slice but I wanted to go ahead and leave it here in case you want to uncomment it and go ahead and log that console here or log the access token to the console I should say you can do that here and when I first put this together I actually imported use dispatch and then I imported set credentials and that is the action Creator and we dispatch that action Creator right here but I think it's going to be better to do that in the auth API slice and that on query started much like we did with the logout action Creator so we're going to await the fresh refresh right here but then we have a problem and I didn't think about this at first but we can have that is success status from our use refresh mutation hook it can be successful before those credentials get set and that happened to me when I was dispatching it here and it still happened to me when I used it inside of the on query started inside of the auth API slice so either way so what I needed to do was add one more piece of state so that's why you see this set true success I needed one more flag to say yes we have got the data and those credentials have been set and it really it just needs that extra little bit of time to work it doesn't really make sense it's not something you would think of at first but then when you try it the way you think about it when you just wait for the is Success you realize when it's not working that you just quite haven't given the credentials time to be set and then be used when the request is sent so by setting this other piece of state right here we get that extra little bit of time and so that's why I just called this true success so once we set that to true as we have that in state above right here on line 14 that's why I set it aside because it just needed a little bit of explaining once we set that to true we should be ready to go ahead and display everything inside of our components and this persist login component is a wrapper it's wrapped around everything that we want to persist that we need the token for and now that defines our verify refresh token function and notice after that we say if there is no token and we have checked persist so if persist is true essentially then we're going to verify the refresh token now why do we say if there is no token well that's what happens when you refresh the page and the state is wiped out you have no access token or any other state at that point so we need to verify that refresh token and what we do with that endpoint is just send that cookie back and that contains the refresh token and then it gives us access to all the other state because we get a new access token one more thing to highlight before we're finished with use effect and that is this comment right here so this disables some warnings that will tell me I need several things inside of my dependency array here but I really don't because I only want this to run the one time when this component mounts and it makes this check so if you put in this line eslint Dash disable Dash next dash line then you will not get those warnings now I'm going to scroll up and instead of returning the div that we have right here I'm just going to say content and we're going to Define some content and it's really going to be a larger if then statement than is needed but I wanted it to explain some things so you could condense this down after you understand what all is happening but I really thought I needed all of these different else's here to show what is happening so the first thing we're going to do is just say if persist is essentially false if we're not wanting to persist our login then we're going to say no persist in the console and we're just going to set the content equal to the outlet so that's fine we don't want to persist the login it won't have an access token it will tell us we're not logged in if we refresh when we're on a logged in page a protected page the next is the is loading state so if that is true maybe we've told it yes we want to persist but we don't have a token because our refresh mutation will only get called if we don't have that token so that's the only time there would possibly be in is loading so then we could display the content of loading while that is true now we might have an error if persist is yes and token is no as well but maybe we get an error so we're going to display that error and this could happen when our refresh token expires so we get a 403 not only from the access token but also from the refresh token and then we're going to go ahead and use that link from react router that says please log in and again and we're going to display that right after our error message so we should see that all in one line finally this is the one we want is success is true but remember we also needed to wait for that true success or it just didn't get time to set the credentials so here we've got persist as yes and yes now we have a token and everything is ready to go but also there's the possibility right when this component loads that we do have a token but we haven't yet initialized that refresh mutation function so this could also be what we see and this has token in uninit is going to the console and you'll probably see that because that should be what happens first or also just logging is uninitialized so you can see what that value is it should probably be true at that point and this would also just return the outlet now after you take all of this in as I said some of it could be condensed I just wanted to show you each possibility inside of this if and then elsif statement and there are several possibilities to take into account now let's go ahead and save this file let's show the file tree once again and go back to our auth API slice in the previous tutorial we went ahead and added our refresh mutation right here however I mentioned we did not put in the on query started yet here and we need to do that so let's put a comma after the query and then let's go ahead and put in our on query started and you'll see why we need it here we have onquery started much like above we used it here in our log out as well and we're once again pulling in the dispatch and the query fulfilled we're once again getting the data I'm going to go ahead and log the data here which would be the access token and here you can see I'm de-structuring the access token now we need to import set credentials at the top as well so let's make sure we do that before we forget and it comes from the off slice just like law log out so I'll put set credentials in there and then if we come back down and look at this we're taking our dispatch and we're going to go ahead and call the action Creator set credentials and pass in that access token right here and we're doing this here so we don't need to import use dispatch in the action Creator in every component that we want to use it in now anytime we use our refresh mutation it will go ahead and set the credentials for us as well and with that complete we are ready to go to our app.js and import our persist login component so we will import persist log in there it is in our list and once we have that let's scroll down and we're going to wrap this around everything just like we did our prefetch component so I'm going to click on the line of the prefetch component and press shift alt in the down arrow and then I'm just going to change the top one we want this to wrap around the prefetch as well to persist login and then I'll scroll to the bottom and where we have our closing route I'll do shift alt and the down arrow to get another closing route when I save it should imply that or apply the indents and we see that so persist login is now wrapped around the prefetch and the dash layout component and of course everything else that's inside of those and with our changes all saved let's drag this to the left and it looks like we're having a hard time finding this hook that we created let's see what's going on with that and yes I've got the hook way up here the hooks directory needs to be inside of the source directory sometimes I miss that when I create a new directory so we're inside of the source directory and that is where we have the features directory we have the hooks directory the config directory and so on so if you were following me and had it outside of the source directory please move the hooks directory inside of the source directory okay let's drag this to the left once again no more air that looks good let's drag our screen of the browser over so we can see everything that we want to see now and what we're going to do is clear this out and we're going to refresh everything let's go to the network tab once again so when we log in we're going to have Dandy and sign in and we've got our auth notes and users let's go to view Tech notes we're still good let's refresh and our tokens haven't expired and notice what happens when we refresh we hit the refresh endpoint we got notes and notes users from the prefetch as well one of these notes came from the use get notes query now I haven't changed our back end so it's going to time out fairly quickly so let's go ahead and change our back end now as well I'll pull this back up and let's put the proper times here so we'll save 15 minutes for the access token and we can say seven days for the refresh token so that shouldn't expire but remember there's a second spot for the access token because our refresh endpoint issues a new one so we need to scroll down and find that other 10 second spot and change that to 15 minutes as well now those shouldn't time out on us and we'll be able to test everything just a little bit better here so now now clear this out go ahead and log out here and everything should be clear but I want to go ahead and refresh just start with a clean slate now let's go ahead and log in again I have Dan D [Music] and notice I should go back to the home page here I'll log out one more time so we can look and log in notice we have the trust this device now with the check bar and if you want to check that you can go to the application Tab and then you're in local storage localhost 3000 persist is true right now we can uncheck it you won't see it change here you need to actually right click choose refresh now it's false if I check it again and I refresh again now it's true so that's how you can check that now I'm going to go back to the network tab refresh all of that or clear it out at least and now we'll say dandies log in one more time we've logged in he hits the auth endpoint prefetches notes and users let's go ahead and look at the notes so now we have the other notes request now if we go ahead and refresh we're still good we hit the refresh endpoint one of the notes was pre-fetched and one was from the notes list page and then we have the users prefetched as well we can even go in to one of the specific notes and we can refresh and we still have all of the data and we're still logged in so now that we're using our jwts and our persist login state is in place we are ready to apply role-based access control and permissions and that is in the next tutorial our starter code today is the completed code from lesson 10 so I've got the package Json open let's just change this name to lesson 11 and save the file but after that we also need to add a dependency today so I'm going to press Ctrl in the back tick to open up the terminal window and then I'm going to type npmi and then JWT Dash decode so we can decode the access token that we're receiving from our back end rest API and then we're going to use that information inside of that token where we store the username and the roles that we receive for our user and now we can see we have jwtd code installed in our dependency list here in the package Json now let's move over to the userstories.md and we've got quite a few here that we haven't checked off but really we can check off a few and by the end of this lesson we'll have most of these complete so the third one add an employee login to the notes app well we've done that and after we add the extra role-based access control and permissions today this will be completely in place so I'm just going to check that off now number eight require users to log in at least once per week what we have set our refresh token to expire every seven days so that pretty much completes that and provide a way to remove employee access ASAP if needed we do have that with the active and inactive state for each employee and once they log in they can't receive that data if they are inactive so we can check that off now that leaves several others that we can go over we're not going to check off number one today or complete that now everything else we've completed in previous lessons including the ones I just checked off but now five and six easy navigation will complete that today display current user and assigned roles we'll complete that today number 14 notes can only be deleted by managers or admins we will add that permission in today for those roles anyone can create a note when the customer checks in so even though we haven't checked this off yet we really have that in place but I don't want to check it off until we verify this with the permissions and role-based access control in place then there's employees can only View and edit their assigned notes we will Implement that today managers and admins can view edit and delete all notes we'll verify that as well today only managers and admins can access user settings we'll take care of that and only managers and admins can create new users we will also take care of that desktop mode is most important but should be available in Mobile we will wait on that just like we did with number one so we will have those two left today for at least the final lesson in this series but let's save our user stories.md and move on let's go to the source directory in our file tree and from there we're going to open up the hooks directory and you can see we have one one custom hook that is used persist let's create another new file here let's call this use auth.js I'll paste in our Imports and we can quickly look at those we're bringing in use selector from react Redux and then our token selector select current token from our auth slice after that we're going to bring in jwtd code from our new dependency jwt--d code that we just added in our package Json from there I'm going to type rafce with our es7 Snippets it should quickly create a functional component called use auth and now that we have that let's remove the return as this will be something that starts out with a few values so let's pull in our token which is our access token with our use selector and the select current token selector that's passed into it and then we're going to set some different values here for is manager is admin and Status right now false faults and the status the default value will be employee after that let's go ahead and return some values and we're going to start off with a username inside of this object that we're returning and it will just be an empty string then we'll have roles and that will be an empty array after that we'll just put in the is manager is admin and status now this will be what is returned if we don't have a token but now let's check to see if we do have a token so we can say if we do have a token then let's look at what happens inside of this if statement because this is where we actually get our values from the access token so we're going to Define decoded and we're going to decode the token with jwtd code from there I'm just going to destructure the username and the roles that are stored inside of that access token and if you remember from our backend rest API code we put all of that inside of a user info property inside of the token so we have decoded dot user info and that's where we can destructure the other values such as username and roles and now we're just going to set some different values and things that might be useful that we could use anytime we pull this hook in we don't have to use all of the values we just want to make this hook very useful for any type of situation that needs to confirm if we have a manager or an admin or just what the username or roles are so we're going to set this value for is manager to check the roles to see if it includes manager because it's an array with the different values inside of it the same for is admin we're just checking for an admin and then we're going to set the status equal to whatever the highest role is so we need to check for is manager first and then we check the status to manager instead of employee that we've set above likewise after checking is manager we can check for is admin and then anyone who is an admin and a manager will have their status set to admin instead so we could have named status highest status if we wanted to be very accurate about that but whatever we're storing in status is the highest role available to that user and then we're returning the username the roles array and then the status is manager and is admin you might think you wouldn't need all of these and you could go without some of them and create other logic inside of your components but I think it's better to just handle the logic here deliver all of the different information in these different forms and then just destructure out of the hook whatever you need at that current time now let's save our new use auth hook and let's move on to the components directory and go to the dash footer.js file we're going to import our new use auth hook at the very top and now let's destructure what we need to use inside of the footer so I'll say const we're going to pull in the username and the status and then we'll just set this equal to use auth and now let's scroll down to our content and you can see we have the current user and Status here available so let's just put those values in here with username and then we can put status here as well so status and save this file and now let's see how that looks in our app and to test our app we need our backend code running so I also have the code from lesson 8 running in a separate instance of vs code and you can see we have our backend connected to mongodb it's running on Port 3500 for the local host and this is our rest API so now let's go back to the react app code that I have in the other instance of vs code open a terminal window here and type npm start and the app is up and running let's go ahead and go to a login so we can log in and then see our footer that we have in our welcome page so here we go with Dan D's information and now we can see in the footer we have current user Dandy and his status is admin let's go ahead and log out and check one more so we'll log in and check mark our manager and we'll enter his credentials and now we have current user Mark and the status is manager so our footer is working as expected I'm going to close the terminal window and I'll go ahead and close up the components directory for now let's move into features and the auth directory where we have our welcome JS file now at the top of the welcome.js file let's once again bring in that use auth hook and now as the component gets started here let's bring in the values we need so we're going to destructure username then we also want is manager and is admin and we'll bring all of those in from our new use auth Hook and the very first thing we can do is extend our welcome with the username so let's just put the username right here inside of our H1 with the welcome after that let's scroll down and remember we only want to allow managers and administrators admins to view user settings or add a new user so let's put some conditional logic around these links inks I will put a curly brace at the beginning and the end but then at the very beginning we can check to see if we have an is manager status or an is admin status set to true and if we do then we can just use the double Ampersand so now if we have a manager or admin if either one of these are true then this link will show for the user settings in this welcome page now we can copy this exact same logic and do the same thing for the add new user link so we'll put this right there and then we'll put the curly brace at the end and we have both links now only provided to our admins and managers on this welcome page and let's go ahead and verify that with chrome so right now I'm logged in as a manager mark and it is still showing all four links let me log out and I'll log in as an employee named Joe and his only role is employee and Joe can only view the tech notes or add a new tech note he does not have the links for the user settings or to add a new user if we log back out and we'll log DND in the administrator and we'll verify here on the welcome page Dan has all four links let's go back to vs code before we move on to the header I just want to point out that yes I've got this conditional logic in here twice you could put it once and then of course have a fragment and put both of these links inside but I wanted to show how to apply this to individual links and we'll see more of that as we move on to the header and apply it to buttons but you could do it either way there's always more than one way to do things and sometimes I get comments saying you could have done this but then I think if I had done that then I would have got a comment saying you could have done what I already did so either way just do it the way you want to but I'm providing it here for each link okay let's move on now back to the components directory into the dash header this is where we're going to provide that easy navigation that is in our user stories list and I'm just going to come down here and add some more lines to our import as we bring in these different icons from font awesome because I need to bring in several more so now you can see I've got four new icons on top of the existing one that we already had and then underneath our send log out mutation I'm going to bring in our use auth hook as well and now scrolling up to start out the component we're going to go ahead and destructure some information from our use auth hook so I'll say const and we need is manager and we also need is admin and we'll bring those in from use auth and now I'll scroll again and underneath our use effect I'm going to put in four click handlers all for the new buttons that we're going to add and you can see each one of the buttons is going to have a different Navigation destination we're bringing in that use navigate hook that we already had to call the navigate function and so we could go to add a new note add a new user to the notes list or to the users list all from the header we're going to change our is loading and our is error return statements that we have here as well but I'll come back to that right now I want to go underneath where we defined our Dash class and we'll look at how that Dash class is applied because we created it in a previous lesson but we really didn't look at the result of it too closely we've also got a log out button here between these two I'm going to add our four other buttons and we'll look at what they do so they follow that same pattern that I used before for the dash class and for the log out button so you can see we're defining the button initially with the keyword let and setting it to null and then we're using our reg X's that we created above in the previous lessons as well so we had the three different reg X's here and we're checking those with conditional logic to see if we want to turn the button from null into something more if we're going to use that button and it really depends on the path so here we're making sure that we are on the notes list essentially with this regex X and if that's the page we're on then we'll include the new note button here we're doing the same for the users list and then we're including the new user button down here we have a user Button as well but now we're making sure that we are not on the users list and we are also making sure that the path name includes Dash and we're pulling in that path name from the use location hook but we're also checking to see if we are a manager or an admin so this is the user button for the users list so what we're doing really is checking to make sure we're not already on the users list because then we don't want to provide the button to go to the same page that we're on but we are making sure that we are in the protected pages with Dash and then we could provide a new user button if we're a manager or an admin I said a new user button this is actually the users list button now above notice we didn't check to see if we were an admin or a manager for the new user button however we don't really need to because we have to be an admin or a manager to be on the users list in the first place and the only place the new user button will appear is if we are on that users list page and then scrolling down we have a notes Button as well and this notes button is checking to make sure we're not on the notes list page and that once again we are in the protected pages that start with Dash and you can also see each one of these buttons has the class name icon dash button this applies back to the CSS that I've created they all have title attributes as well and the on click applies to each of the four handlers that I supplied above these buttons in the code that we recently put in also they all have their own unique icon that we're bringing in from font awesome okay under this underneath the log out button as well but let's put it maybe above the content that we Define I want to add an error class like we have previously had in components before where we're checking to see if we have an error and remember this would only be for the log out because we have that send log out mutation and it does have an is error status so if we have logged out and we have an error then we're going to apply the error message class otherwise off screen so this means we're going to present the error in a different way than we had above so I'm actually going to put the error just on top of the header otherwise the way we currently have it it would display inside the header and that would look kind of weird because the header is constrained to a small area at the very top of the page if we put the error above the header it will span the page just on top of the header so let's do that we're going to need a fragment to do that because then we'll have two different elements underneath as children so then after the header will close out this fragment as well and we can save and now we have our error and I could even put a space to set them apart but now we have our air that has the error class we Define so it's typically off screen unless we have an error and then the error message class applies and it will display that message across the top of the page now notice inside of our content here we had add more buttons later and we have our log out button but I'm actually going to Define all of the button content above and then we'll put that inside of the content so I'll paste this in and we can take a look and now you can see we're also going to change what we do for the is loading that we previously had above but I'm defining button content we're checking that is loading status again that only applies if we call that send logout mutation and if that's what happens then we have button content equals logging out otherwise the button content is going to equal all of the buttons that we've created if they exist if they're null they won't show up and so either way we're going to put button content in our content account below so it could display logging out if we have is loading otherwise it will display the button icons that are appropriate for each page that we're on so now we can scroll down here we can get rid of this note all together and instead of log out button right here we can just say button content and save now we need to go up and remove the is loading and is error that we previously had in our page right here so we'll remove both of those and we should be good let's check it all out in Chrome now I'll pull Chrome up oh and we have a blank page we may have an error let's drag this over so I can open up Dev tools as well and see what's going on yep we'll scroll up to the top to see where the errors start okay cannot read properties of undefined reading data at the dash header in 130 I think this has to do with us reading our error if we have one so let's go back look at the dash header on line 130 so scrolling down here and there we are yep where the error is displayed I didn't use optional chaining here and we're not checking the is error status first so if we don't have an error that data property doesn't exist we need optional chaining there to make this work and we can save while I'm doing that I'm going to go ahead and highlight the source directory and then I'm going to right click and choose find in folder search for error.data to see if I did this anywhere else that will have any possible consequence that I hadn't caught I do see it in a couple of places let's look at those quickly in the persist login component I've got error.data and then optional chaining for the message just like we saw in the other file but I am checking the is error property here or I said property value here first so this would only happen if we do have an error which would make this okay but we can be doubly safe just by adding that optional chaining there to the persist login component now let's check out in the API slice where it says it has it but this is where we're setting the value so this is what we need we don't want optional chaining here so this one is fine let's go ahead and close that and close the persistent login component as well go back to the file file tree over here and I think we're now ready to check everything out inside of chrome so let's look yep and Joe is logged in now and he's got access to the tech notes and add a new tech note but does not have access to those other links for the user so all is like we expect but we're also checking the header now and notice he has an icon to go to the notes list or he can log out because that's all he really has access to let's go to the notes list and he has the notes and now there's an icon for a new note and we click that and we go to the new note now notice the icon changed back to the notes list so this is all working as expected let's log Joe out and let's log Mark in who will have access to the users as well because Mark's a manager now logging him in and we can see at the top we have an icon for the notes list or for the user settings so let's go to user settings there they are now that we're on the user settings page we can create a new user with this icon or go back to the notes list so there we go when we're on the create a new user screen we can now go to the users list with the user settings icon or the notes list so let's go back to the users list let's go to the notes list and now we've got a new node icon or the users list let's go ahead and create a new note we're on the new note page now we could go back to the notes list or the users list let's edit a note now we could go to the notes list or the users list again everything seems to be working like we expect it to for Mark as well and of course here on the welcome screen he has access to all of the links too let's log Mark out and we'll log back in as Joe so here's Joe and he is an employee only so he should only have access to the notes and the add new tech note now let's view the tech notes and he can see everyone's notes like he's an admin or a manager so we need to change that as well so let's go back to the code let's close the components directory let's look in features look inside of notes and we'll choose the notes list JS now at the top of notes list JS we once again need to bring in our use auth hook and as the component gets started let's destructure what we need which is the username is manager and is admin and we'll pull all of those from our use auth hook now I'll add an extra line there and let's scroll down to our is Success area where we're destructuring the IDS from notes now remember we're using our entity adapter from Redux and rtk query and so we have an array of IDs but we also have entities so what we want to get here is not just the IDS but also the entities so we're destructuring both of those from the notes that we get from our hook above the use get notes query we renamed the data notes so now that we have IDs and entities we can change this just a little bit and we will only view Joe's notes because we can filter these so I'm going to paste this in and we'll go over it I'm going to create a variable called filtered IDs then we're going to check if we have a manager or an admin the filtered IDs are essentially going to be the same as the actual IDs array but we're just going to create a new array right here that holds those so we spread in the IDS array but else so if we're Joe and we're not a manager or an admin then filtered IDs is going to equal the IDS array filtered where the note ID each ID passed in is going to be used on the entities so we can identify the entity and we're going to look at that username for that specific note and see if it matches Joe's username and if it does it will be included in this filtered IDs array so then we want to move down and change a little bit of our Logic for our table content I'm going to press Ctrl B to hide the file tree just so we have some more room I'm going to change this from a ternary too because I think we can switch this pattern let's go ahead and use backspace to remove that and I'll say if the IDS array has length then we're going to apply the filtered IDs to map instead of IDs right here we can also just get rid of this null we no longer need the ternary because we're using the double ampersands that we see and I think I can get rid of that parentheses as well nope that one's for map I do need that so what we're doing instead of using a ternary is just saying okay IDs have length and then we can filter those IDs and of course apply that to the entity that we did up here so this is just Joe's post by the time we have filtered IDs right here or I said post it's his notes actually so we save that and now when we go to view the notes with Joe's login we should only see the one note that he currently has so let's go back and check that out and yep only this note is what Joe has access to now he can create notes for other people but then after he creates them he won't be able to go back and view them because he only has access to the notes that are assigned to him now if we we go back as Mark as a manager he should be able to see all of those so let's check that out as well now let's look at the tech notes Mark can still see all of the notes no matter who they're assigned to so it works either way now of course as we drag this out and we get a wider screen we can see more columns here as well and I think you see who those are assigned to there but if we open these up now like if we look at Bob Jones iPhone Title Here for his note it is assigned to Joe and if we go back to the list and look at Food City schools with their laptops to repair that's assigned to Mark and so on so you can see Mark has access to all of these okay we'll log out and let's once again log back in as Joe and we'll check everything out looks good Tech notes still just Joe's note that's all good let's go back to visual studio code I'll pull the file tree back up with control B and that logic we just changed there with the double ampersands instead of a ternary I remember one other place we could use that as well and that was in the users list where we did something very similar so let me scroll down we once again have the IDS length here we do not need to filter anything but otherwise we can use that same logic so let me get rid of the ternary put the double Ampersand in and then we can get rid of the null as a possible result as well and this works just as well and I like the logic just a little bit better I'm going to bring Chrome back up now and we're logged back in as Joe and let me take this to the full screen and what I want to show is we've applied permissions to several components and those permissions are applied to the roles instead of any one user so you can assign as many users as you want to those roles and that's more efficient we abstract those permissions away from each individual user to roll so we have role-based access control but now I want to highlight that we haven't protected the routes yet so even though Joe should not have access to the users really we're just not showing him an icon to get there so if Joe were to know the address and just type in users he can still view the users list here so we need to change that by protecting the routes likewise if I log out entirely now and say I were to try to go to one of these pages and I'm not logged in we won't be able to see it but it's not because of a protected route it's just because of an error that we're getting from our API the response and I see we need to add a space there so let's fix that quickly before we add the protected routes I'll pull Visual Studio code back up and from the last lesson you might remember we were in the app directory working with the API slice and here I'll press Ctrl B again to hide the file tree so we can see this better but we had this error message and I left the extra space here but that's not the error message we were seeing mean we were seen unauthorized so that space really isn't helping us out let's go ahead and remove that and handle the space somewhere else so I'll save that show the file tree again and now let's go back to our persist login component and that's what's showing this error data message that we have and then it shows please log in again so we need to change this so there's a space and I can do that by making this a template literal so I'm going to start with a back tick and then the dollar sign and the curly brace and then we want to have a curly brace after it all and I'm going to also put a space and a hyphen and a space actually so we can separate the error message from our please log in again message and there'll be a hyphen in between and then I'll put my closing back tick and then I need a closing curly brace now we'll have that error message and please log in again so let's save that let's go back to Chrome now and we can see this has changed so we have our error message space a hyphen or you could call it a dash and then a space and then our link to please log in again which takes us back to the login and now we've shown the reasons to protect our routes one we're really just getting an error we're going ahead and requesting something from the API even when a user isn't logged in and we don't want that even though it returns an error and then when Joe is logged in even though he doesn't have the permission to see those icons to take him to the user settings he can still get there if he knows the address we need to change all of that by protecting our routes to protect our routes we need to create one more component inside of our auth directory so I'm going to do that and name it require auth with a capital R and a capital a DOT JS I'll put the Imports first we're going to import use location navigate and outlet from react router we're also going to import our use auth hook then I'll use rafce to get our functional component quickly but this is not going to be what we need here so I'll just replace that and here's the content we need so here we're getting the location from our use location hook and we're only bringing in the roles array from use auth now that we have that let's define the content so the content is going to equal this ternary statement and I'm using the roles array and then the sum method which means if this is true at least once this will return true so if we find one of the roles that's all we really need and we also need to pass in the allowed roles as we see here inside of our sum method here so let's pass in those allowed roles and as you can expect this allowed rolls is an array that is being passed in so now we're calling includes on that and we're checking each role there so essentially if allowed roles includes one of the roles that the user has that we're getting from use auth then we'll have true and we'll just return the outlet which as you might remember is all of the children whatever we're going to wrap this require auth component around so it is a wrapper to protect whatever we have inside of it whatever routes and make sure they're only sent for these allowed roles otherwise we're going to use navigate and send whoever is trying to access a route that they're not allowed to access back to the login page and what this does here we have the state so we we get the location from use location and we're passing that in here as the from for our state this is a react router thing and then we say replace so we're saying replace this what we don't want is to have this require auth component in the history so say Joe tries to access the user settings and then he would use the back button if we didn't do this he would just go back to the require auth and it would send him back to the login again so his back button essentially wouldn't work this will ensure it does so if he's on the say the tech notes list then he tries to access the user settings by typing in the address it'll send him to the login but Joe thinks hey I'm already logged in I'm just going to hit the back button he will be able to do that so he could back up and be back at the notes list or he could log in again and that wouldn't hurt anything either so that's our require auth component and we're going to use it as a wrapper more than once inside of our app.js let's now head over to our app.js we can close the features directory in the file tree we haven't looked at the app.js in a little while since we brought in the persist login component in the last lesson least but now we've got a couple of things to add here for imports one would be the require auth component that we just created but also we need the roles if you remember we created a Rolls object in the config directory before and we're going to pull those in let's look at that real quick just so we can remember what we have there we have a roles object and it's got keys and values that actually match so we have employee employee manager manager admin admin if you went through my node.js course you've seen this also where the employee is assigned a number the managers assign a number this could be different at different companies this is just what we're doing now and you'll see how we can still use dot notation to refer to these when it's constructed as an object and I think that's ideal when we bring this into app.js so we're also importing that roles object and now I'm just going to add a comment here for the public routes so everything is wrapped inside of our original layout that we've talked about in the past and these first two routes are our public route outs the public can access the home page of course that's the public page and then they can also access the login page because we have a link from there to the employee login it wouldn't be necessary if all the employees bookmarked it for instance and maybe you wouldn't want that on your home page but we've done it for this project after that let's go ahead and add the protected routes and I'm going to just Mark those as well that's going to be everything after these so protected routes start here with the persist login that we currently have and then they're also wrapped in our pre-fetch component and then we have a separate Dash layout that has that header and footer and then all the internal routes for that as well so let's go ahead and mark the end of these as well so I could Mark the end of the protected routes we don't really need to do that for the public since there's only those two but the end of the protected routes is going to be down here at the very bottom so I'll put that right there and now let's scroll back up and let's protect all of our routes I'm just going to click here on line 27 and then you shift alt and the down arrow because we want this to be our require auth component at least our first one that we're going to add we want it after the persist login because it's going to need that login data to get that from the use auth hook however we want it before the prefetch component so if someone's not authorized we're not going to go ahead and prefetch that data there's no reason for that so let's go ahead and add require auth right here and now require auth needs to pass the allowed roles in and the allowed roles is going to be an array so we're going to create a new array right here by putting in the brackets and now we can put in each role we want to allow to access the protected routes now this is for all of the protected routes even the welcome so really all roles should be allowed to view this at least if they have a role likewise the public should not be able to so we could put in each individual role like we could say roles Dot and then you can see we get dot notation we can choose admin employee manager so we can have roles dot admin comma and so on which is what we will do for another route coming up but since it takes all of them we can also say dot dot dot we're just spreading in and then say object dot values and then we'll pass in the roles and this will just spread in all of the roles inside of that object now I'm going to press Ctrl B just to make sure that we close this out I couldn't see the end of this yes and that looks fine so we need to go ahead and add one more closing route element here as well so I'll just click on line 47 and bring that down now when I save we'll get the proper indentation and now everything should be protected but it's allowed to All Rolls now let's go ahead and use require auth once again for a nested route and we need to do that for our users routes so I'm just going to copy all of this and then we'll change the roles and I just want to wrap it around the user's routes so I'll bring this down here paste it here and I need one more closing route there and now let's just change the routes or the actual roles I mean that can access the user's routes so here we'll say roles Dot and a manager can access the users and then rolls Dot and an admin can access the user so we're passing an array with only those two values and I see a little red to indicate an error over here from vs code and that's because it instantly put a closing route tag there as well but we have that down below so allow save and we've got the proper indentation again and now let's go back to Chrome and check everything out so first we'll log in as Joe whoops I had my caps lock on there and did it the opposite of what I needed so I need capital J then o e okay here's Joe's password we are logged in he only has access to the notes again and we see all the proper links but what about if we try to just go to the user settings once again so I'm going to type in slash users at the end here and he gets kicked back out to the login so that's fine let's see if the back button works as expected yep it took him right back to the dash so that is what we want let's go ahead and try to do the same thing now for Mark who should still be able to access all of the routes so here's Mark let's go to user settings he can still see the user settings and he can edit a user he could probably even create a new user we can do it with that icon now notice the dash class if you remember us setting that up in the header as well so when we go to the forms that aren't as wide as the list when we take up the full screen it brings these icons over even with the form so that's what that class was about it's just changing the width a little bit so now if we go back to the user list they're back over here to the right taking up the full screen which is fine we can see this with notes too by the way let's go in and edit a note now our icons are all lined up over here with the form instead of way over here to the right so everything seems to be working just fine for Mark 2 and the routes are good let's go ahead and log out now and now let's just try to access those routes and see if we get that error from the API or if we actually just get kicked to the login screen by our require auth component so we'll say Dash and users now we're not logged in at all and we get unauthorized please log in again which I believe that does indicate a request is going out so I'll go back to that let's open up Dev tools and let's see what we got yes we got the persist login error right here and there's an error object from the auth API slice that's all good let's check the network requests as well so here we're at the network and let's try to reload this page and we hit the refresh and that's what gives us the error so that's okay too and really this is better than taking someone straight to the login page if they're trying to access something they don't have access to so now they have to do a little more work and that's just fine with me let's see what happens if we go back to the login page and uncheck trust this device now we're not logged in at all we're on home I'm going to refresh Network request is good let's go ahead and try that users again so we're at Dash and now users and we're not checking that stay logged in on the login page and we get kicked right back to the login and that's fine too and that's what I expected the first time I didn't think about the trust this device if it was just a public machine and no employees had logged in maybe a customer logging in on their home computer and they tried to access a route that was protected they would just get kicked to the login because they don't have access a quick final note I am back here at the user stories and I was reviewing those and notes can only be deleted by managers or admins I realized we skipped over that one so let's go ahead and finish that before this lesson is over we should go to the features and then the notes directory and now we should go to edit note JS and then edit note form JS and this is where we will actually work with that trash can icon and only let it appear for managers and admins so I'm going to paste in our use auth hook once again as the import and then from there we're going to destructure what we need and that is is manager and is admin and I'll set this equal to use auth and pull that from the hook I should mention as you might have already noticed the manager can access everything the admin can at this point in the app and really our user stories don't require for more than that however I'm providing each because there could be additions in the future we're just making it flexible possibly we tie this into a ticketing Financial app or something like that something that Dan our stakeholder wants to add in the future so it's still good to have that separation between managers and admins so we're just building it in now okay after we've brought in the is manager and is admin status we need to scroll down and I'm going to scroll down until we're underneath our content here for the error and everything we've created there we go between the error content and the regular content I'm going to Define our delete button I'll just paste that in and we can go over it it has the same pattern you've seen before so we have let delete button and it equals null but then if we are a manager or an admin the delete button then has some content and of course it calls the on delete note clicked so let's scroll down into our code now and we can replace where we originally had that delete button which was right here so we'll just grab all of that backspace and I'll put our delete button right there and save now this should not be available to Joe but it should be available to Mark and our stakeholder Dan so let's check that out now inside of chrome I'll pull Chrome up and let's view we're logged in as Joe so let's view the tech notes pulled up Joe's only Tech note right now and if we go to the edit form he has a save button but not a delete button and that's what we wanted to see so now let's log out and check the same for Mark [Music] sign back in go to Tech notes let's go ahead and look at any one of these notes let's look at Joe's again so Mark can delete Joe's Tech note if he needs to so that's what we needed there for that last user story so we have made a lot of progress today and I think we're through most of our user stories we can check off more of those in the next lesson and also in the next lesson we'll be doing a little bit of code review and refactor and then we'll deploy everything the back end and the front end as we wrap up our myrn stack project series today's lesson will have two code repositories one for the front end and one for the back end of our myrn stack project our starter code for the back end is the completed source code from lesson 8 which is the last time we worked on the back end rest API I've got the package Json open for our backend code now and I'm just going to change lesson 8 to Lesson 12 and then I'm going to put a dash and put be for backend because we're also going to have a repository for the front end so when creating projects I don't get a traditional code review like I would working on a team but the nice thing is as I release Lesson by lesson and build a playlist on YouTube or wherever you've watched the video I get feedback and questions and I'm able to answer those questions give responses look up details and sometimes viewers catch things that I may have overlooked or they think about things in a different way that's actually one of the things I love about teaching is because I learn as I teach as well my students at universe City or just viewers on YouTube help me see things in a different way so I've had some questions as I've built this playlist for our myrn stack project and they've identified some things and a code review and building in public can of course make you go I am not perfect and I know I'm not perfect and there are some things we need to correct today so thank you in advance well I say in advance thank you for previously reviewing those things and thank you in advance for anything you helped me with in the future I do sincerely appreciate it now what we're going to look at first are the controllers and that's when I really started to get some comments when we were building the logic for the controllers specifically the notes controller and the user's controller so let's look at this notes controller first and what we'll look for is the duplicates area so we can do control F and we can just search for duplicates for when I was searching for duplicates and I guess not with an S but just duplicate and there we can find it in the file you could also just go to the controller directory here and then right click and choose find in folder and then you can just search duplicate and it will find everywhere we look for a duplicate in these controllers and then we could bring that up and that's a good way to do that now the first thing I actually want to do is go to the model because I was asked instead of looking for a duplicate title for example or in the user we were doing usernames why not just set that to Unique well unique does help but it creates an index and that will provide a duplicate key error when we attempt to save a record that would need to catch a duplicate but we're not sending you know that user-friendly error like we have in the controllers when I look back here let's find the user area here and we're sending specific messages and Status numbers for these error messages and so we were getting some granular control some specific control over that and we would have to do that in a different way if we based that say on setting that unique or some of the other things we might do where we would only catch the error when we attempted to set save the new user for example and we find that here as we go oh here's created this was actually user.create but other places where we update I believe we save as I scroll down here and look yep awaituser.save in the update that we see here so we would be catching the errors there in a try catch block if you remember in the controllers we used an async Handler and so that catches those errors instead of using a try catch for the await and if we're not expecting the errors the ones that we did not already anticipate that we're grabbing and sending the specific errors that we defined and of course those user-friendly messages then they get kicked out to our error Handler middleware that we created in the middleware directory here and then it sends whatever the error is that's generated not always quite as user friendly so that's why I took this approach I wanted to handle all of the errors that we could that we expected that we knew we might get and send the specific error messages and status of HTTP status numbers like 400 here for example or we'd have a 409 for conflict I believe when we have a duplicate yep there we have that and I wanted to send those specifically and have control over that so that answers some of that like why we didn't specifically use unique but another reason is unique doesn't necessarily check for case sensitivity and that's the second thing I need to bring up that I got called out on and it's correct I'm busted on that one I should have checked for case insensitivity and I didn't so in other words if we put in a name like capital D at the beginning of Dave for a username and then we put in Dave all lowercase they would be different unique wouldn't catch that and we would allow two Daves to have that username so we want to make that search case insensitive in other words instead of case sensitive now I'm currently in the user's controller I can highlight that here in the file tree so let's make the change here first that will adjust our search and make it case insensitive and I've received several suggestions on how to do this also as far as just setting everything to lower case or acquiring that on the input but then of course our users would have to say they just want lowercase and we want to do go ahead and allow uppercase letters or I wanted to for this project so I didn't do that a regex was also suggested and you could set the case insensitivity on the regex that would be another good solution however there is a solution that is documented for mongodb and the Mongoose JS documentation links directly to mongodb for that and it will easily adjust us this for us so all we need to do is find our initial search for that duplicate so let's go ahead and search for duplicate in this file once again and we can see we found five of nine so it's in at least a couple of places here's the first area right here so let's see what we're in we're in the create new user Handler here inside of our user's controller and we're just going to change our find one that we have looking for this duplicate right now it says awaituser.find1 we pass in the username we have lean because we don't need to get the entire object back we're just checking that username then we execute that but what we can do is use a collation and then you just have to add what strength you are providing for the search and we can chain it right in here I'm going to press alt Z so this wraps so now you can see we have the find one and the username and then I've added this collation and I will link to the documentation in the description for this but you must provide the Locale property here and after that you can set a strength and we'll just go ahead and set that to two and there's several things things that that does one of the things that it does is it checks for that case insensitivity so simply by chaining this to our find one request and then of course having lean and exec after this will fix our problem and it will check all capital letters or all lowercase letters it doesn't matter two days will still be identified and only one person will be able to have the username Dave no matter the capitalization or the lower case so let's go ahead and find the other instance that we're looking for a duplicate in this file and let's apply the same there and here we are on line 72 now let's see what we're in this is in the update user once again we're looking for a duplicate here so we want to put that right after the find one I'll just paste that collation in and that will work okay now let's go to the notes controller and make this same adjustment for where we look for duplicates there and let's make sure we're on the first instance of duplicate there we are so we have note find one and we can put the collation it's the identical code there's nothing that changes here that's different than where we put it in the user controller it's just a collation with the Locale property I'm setting it to en for English and you can set Yours differently if you want to and then we have strength and it's set to two and after we find that one let's go ahead and find the next time we use duplicate and it's here probably inside of the update Note just like we had update user and we'll put that here as well and save okay another review comment that I had was we have a default in the user model and that default has employee set here and we have a string for the array now it said the comment I received and they're correct that if we provide this default we don't really need to require a default role to be sent or the roles value to be sent at all when we create a user and I remember going through that tutorial and I said I'm going to require the roles anyway it doesn't hurt a thing but we can fix that so the default is available however I believe in our front-end code we've already required the roles so it's not a big deal but I did just want to show how to do that and I also wanted to fix something here in the schema as I went over that and this is worth noting because we actually put this in differently than it should be and I just didn't catch it before so this is good to note right here what we want to have instead of having the array here around everything we'll put roles have an object then we'll say type string and we'll just put the word string inside of this array right here after that we'll have a default and we'll also put the default value inside that array like you see there okay now that we've made this change to our user schema and I'm going to save this file let's go back to the user's controller and let's find the create new user method once again on scrolling up here we are on line 24 in the user's controller for create new user so we can just make a couple of changes here that will not require the roles but we'll still use them if they are received like we are getting here from the request body so here's where we were requiring those and saying all fields are required well we can change this then if we're not going to require the roles to be received and just remove this last part of the conditional so now we're just checking to make sure we've received a username and a password after that let's just scroll down to where we create our user object and now there just needs to be a little bit of conditional logic right here instead of always sending the username past the hashed password and the roles as we create a user so I'm going to change this and we're going to use a ternary statement and I'll just put this in and save so you can see the better formatting and here we're creating the user object and we're providing a conditional here basically the same conditionals that we took out up above and now we're saying if these are true if one or the other then we're going to do this where we just send the username and the hash password so this means if we do not have an array of roles or if we have an array but it doesn't have any length essentially nothing's in it then we're just going to use the username and hash password otherwise we're going to do what we were doing before send the username the hash password and the roles as we create the user so that easily makes the change for the comment I received on that and of course like I said you don't have to because in our front end code we were definitely requiring the roles but this just makes it a little more thorough and shows yes that can be done I did also receive a couple of comments about why I was choosing for instance save instead of using say find one and update or find one and delete where I was just using say find by ID or find one and then later on actually saving the changes as we see here in the update user and I've got a couple of reasons to explain that one is again again I wanted that granular control or more control you could say to give those specific error messages where as if I was using the find one and update essentially we'd be trying to do everything at first I wouldn't be checking any of this beforehand and then I would be handling errors afterwards and that brings me to my second reason then I would have to use a try catch block instead of using the async Handler that we had before that would kick those errors out to our error Handler middleware immediately using the try catch we would have to handle those errors afterwards and of course we could give different reasons inside of the catch and then we'd have to pass the error to next so it could be done it's just a different way of doing it also I guess a third reason here is when I teach things I tend to do one step after the other not so declarative and sometimes when I'm just coding for myself I may be a little bit more declarative but it's easier for me to walk students through steps one by one so that is another good good reason that I didn't just try to do everything at once so we walked through each step here everything that I would look for in a controller each error message that I would send back and eventually we save our changes and of course send a successful message and just one final note for our back end code and this will impact the controllers and it's our use of async Handler we're bringing this into each controller we're wrapping our methods that have async await and of course if there is an unexpected message because this async Handler lets us avoid using try catch blocks but if there is an error that we didn't expect of course like here's the 400 we are expecting that says no users found but if there's something we didn't expect and it gets kicked out then it goes to our error Handler but there is another package I have discovered that is actually easier to implement than this async Handler it doesn't require us to wrap every method but it is easily applied by just requiring the pack package in your server.js so you don't have to make this change our async Handler is doing the exact same thing I would just recommend it for the future because it's easier to use if you do want to implement it we will need to remove the async Handler and anytime we wrapped it around a method inside of our code so I won't walk through doing each one of those but I will show you how to install the new package and what the name of that package is so let's go to the package Json I'll scroll up here so we can see our dependencies and then I'm going to control backtick and then I'm going to say npm I and then it is Express I can spell Express dash async dash errors instead of Handler I'm going to go ahead and install this and then all we need to do is require it at the top of our server.js so I'm going to close the terminal so we can see just a little bit better and I want to put it before the port but after that is fine so we could just require it right here and as long as it's required and I guess because we're doing the same with DOT EnV instead of having it right here I'll just put it at the top underneath the dot ENB require and then it just applies itself everywhere in your application so you do not need to do what we did with the async Handler that you see being imported into each one of the controllers and then wrapped around each method so I'm going to remove those you and then I'll come back to the code you can do the same if you want to or for this project if you want you can just leave your async Handler in there I'm also going to uninstall the express async Handler and I guess I could do that now to show you in the package Json as well so that would be npm uninstall and then you just name the package so Express async Handler again only make this change if you want to okay I have removed all the instances of Express async Handler from my controllers I'll just show you one for example no import at the top of the auth controller now previously the login method had the async Handler wrapped around it and I have removed that as well and I've done that for all of the different methods in each of the controllers that we're using the async Handler so no import and no wrapping the async Handler around any method if you're using the package express async errors now and again the only thing you need to do to use express async errors is it required at the top of your server.js so yes a nice change to a different dependency if you want to make that change one more change to our backend code and then we'll be finished and able to move on to the front end repository but this change is going to be inside of our middleware and in our error Handler and this is something we need to do because of how we're handling errors in read ducks and rtk query right now if an error gets kicked to our error Handler it sends the message and that's pretty much it so we don't know what the status is going to be it's kind of a mystery status and we figure it out along the way and if we don't know it we set it to 500 which is a server error but what we do need to do is one extra flag that rtk query is going to look for and that is to be is error is true now the other errors that might be encountered rtk query will already know their errors but we want these messages from our error Handler to specifically be flagged as errors and we'll be able to handle this as we validate the status back in our API slices in the front end code so this is just something we would need to communicate to the back end developers if you were working on a team that hey we're using Redux with rtk query and any unexpected error it would be nice if you could set is error to true for us so I'll go ahead and save that and with that final chain change we're finished with the changes to the back end code so now let's move on to the front end repository now we're at the starter code for our front end repository and the last time we worked on the front end was just in the previous lesson lesson 11. let's just go ahead and change this to Lesson 12 in the package Json and save our file now from there the first thing we need to discuss is what is in the notes and the users API slice unfortunately we have a few more changes to make to the front end so we better get started quickly and we'll go to the features directory and let's go to the notes and now we can scroll down to the notes API slice now something that I overlooked that a viewer kindly pointed out to me was the validate status I put in here I put it outside of the query and it hasn't heard anything our app has been functioning however it's actually a property that belongs to the query right now I'm just giving the query the notes end point here the address to attached to the base URL we need to change this and apply the validate status and then we'll identify notes Here with a URL key so let's go ahead and highlight this full query right here under get notes you can see when I paste this in now it's going to look just a little different now we have a parenthesis and an object and here we say this is the URL and there's notes and now we have our validate status here now coming just from the back end code where we made that other change if we have an unexpected error we're not sure what the response is going to be then it goes through this validate status process and notice we say if we do not have result.is error and that's specifically why we were setting that is error to true in the error Handler middleware in the back end so it would catch right here which will allow us to display the error message that we get something else worth noting while we're in here is that if you've got an error about response.data and map not being a function well that means you do not have an array at this point that response data has to be an array to map over it so you could check to see if you have an array here and do an early return I'm not going to put that in because I'm going to say look you need to know what errors you're receiving and of course this validate status helps with an error that you might not expect as well so if it's not coming from your error Handler or it's an unexpected error well then you just need to have control of that data and you should always be receiving an array here so you could put in a check for an array but you're going to have other problems right afterwards with the provides tags as well for example and you really just need to have an array at this point so make sure that back end is sending the expected response and if it's not the expected response it should be an error okay let's save these changes to the notes API slice and let's do the same to the users API slice because I made that same validate status mistake right here where I had it outside of the query so I'm going to go ahead and adjust that and now we have our users URL and the validate status is part of the query object okay now I'm going to close these files but we're going to go up and look at our pre-fetch component that is inside of the auth directory now this has definitely been working for us I'll press Ctrl B so we can see it a little easier here and what it's been doing is initiating the state for Redux and so it's made sure that these queries have all of their data at a time and of course we can even refresh the page and it grabs that data again quickly but it is using the initiate we need to break away from the actual Redux that we're used to using because then when I pull in this data later say in the note component or in the edit note component for example we're using the use selector and then we're passing in a selector but what we really need to do is use the rtk query use get notes query that also runs and then of course we can select results from that we don't have to request that data again and we can use this prefetch component to instead of putting that initial state with initiate in a Redux we can use it to actually prefetch and it makes it just a little bit easier actually so let's go ahead and do that I'm going to remove the console logs as well and I'm just going to paste in what we do and I'll save this so it comes over but what we do to actually use a prefetch that is built in and we can prefetch those hooks that we are using so we have the notes API slice dot util Dot prefetch and then we identify the end point and we have a get notes endpoint and a get user's endpoint now let's go ahead and pass in an argument to name these just like we did in the hooks query notes list and users list and of course then they will be the same subscriptions and that subscription is is what a component does it says hey I'm using this data to Redux and so it is subscribed while the component is mounted after it unmounts it holds the data by default for 60 seconds but we've shortened that up in our slice by saying keep unused data for only five seconds I'm also passing this Force true here so that means anytime it comes to the prefetch even if it has that previous data it's going to query it so that just forces that query even if the data already exists in there we can also just remove this return there's nothing to unsubscribe from here this is just a prefetch so I'll remove that return so we don't have to clean up that is the cleanup function of use effect and we can pretty much get rid of the empty spaces if we want to as well I guess I could bring use effect down one so it's a little easier to see from the prefetch but there we have changed our component now this is going to break a few things right now so we'll need to change those as well and we'll see those in those children components from our list right now we'll just be pre-fetching those hooks that we have in the users list and the notes list I'm going to show the file tree again and let's go to the package Json because as we go through some of these child components like the edit note and the edit user I want to add a spinner as well so let's just go ahead and add that dependency and as we're editing those different components we can add the spinner in also so control back tick to open up the terminal and npm I and then react Dash Spinners and this is a nice package that provides some pre-defined some already created essentially Spinners that we can apply inside of our project and so now we see react spinners has been added as a dependency now let's go to our note component and what we need to do is actually use the data we already get from our notes list query right here we have use get notes query inside of our notes list but then when we pass it to note what we've currently been doing is using the use selector and passing in a selector what we're changing this approach now so we won't have the use selector or select note by ID so let's go ahead and remove those and then in its place let's go ahead and import our use get notes query that we're using inside of our list as well but we're not going to have to query all that data again because what we can do to Define note instead of this use selector and I'll delete that and just paste in the difference and we'll look at how this works we can Define our note from the use gitnotes Query that we have in the notes list and we're naming it the same but then it has this function called select from result so we already know we have a result and we're getting the data from that now remember we have our data broken into an IDs array and then entities and what we want is the specific note so we're passing in the note ID and then here we're just defining the note when we select from result this is a selector essentially for our use get notes query data and here we have data dot entities and then we're providing the note ID and that gives us the note in the same way there's no other chain changes to be made here we're just getting that data in a different way so we'll save this and now we should still be able to have all of these notes and we're only making the one query with use get notes query this will not create a separate query or network request I should say it will get this note from the data that is already queried and while we're in the note component there's one other optimization we can make so let's go ahead and add it as well we'll say import and this is going to be memo and it comes from react you may have heard this referred to as react dot memo where we would just import react and then use dot notation to use memo but we can just destructure memo this way as well now at the bottom of this component then we need to go ahead and put that in place and I'm going to say const memoized note and then set that equal to memo and then pass in the note we have created we'll create some space here as well and then instead of default here for the export default note we will go ahead and Export the memoized note now this component will only re-render if there are changes in the data now let's do the same to our user component so we are no longer using the use selector or select user by ID and instead I will import use get users query and then from that we can get rid of where we're currently defining the user with the use selector and instead I'll paste in once again our use get users query we select from result and we get the data and then we get the user that we need after that we can also import memo here and let's get that from react there in our list there we go and then we can scroll to the bottom and I'll create an extra line here and I'm going to Define const memoized user set this equal to memo pass in the user and then our default export will be the memoized user here and I should add if you're not familiar with how react memo works I do have a separate tutorial on that that I'll link to in the description as well now let's move on to our edit user component and we have a few changes we can make here at the top I've got the Imports we need so I'll put in the use get users query once again and then I'm also going to import a pulse loader from that react Spinners package that we added as a dependency and you can see it has react Dash Spinners slash pulse loader which is one of the choices and I'll put a link to that full package in the description also you might want to make a different Choice than the pulse loader that's what I'm going to use I'll get rid of that space and we can once again Define our user inside of this component and it's going to be just a little bit different because notice we have an ID now that we're passing instead of an ID that comes in here we're getting it from the params which would be in the URL and so then we can use that select from result and we pass the ID here instead of being destructured as a prop it comes from the use params and either way we still end up with the user and I'll scroll up just a little bit and I'm going to change some of this logic that we have here no longer going to use the turn array I'm going to say if we do not have a user we're just going to return that pulse loader that means it is probably still loading if not we're going to of course create the content and then return that content now let's move on to the new note component in the notes directory and we'll once again import what we need at the top this is the use get users query notice that even though we're in the new note we're pulling in the users because we need those users when we create a note to assign the note to a user and once again we're going to replace the use selector and the select all users selector and we'll put in our select from result using the use get user there's query here and that means we do not need these Imports I should go back and check that of course in the last component we're in I may have forgotten to remove the old Imports but after we Define the users going to change one other line here and that's because we're going to use that pulse loader again so instead of saying not currently available we'll put the loader here if the users do not have length and then we of course have the content equal to the new note form and return the content let's quickly go back and see if I have some old Imports at the top and I do we don't need the use selector or select user ID here inside of the edit user component how about the user component it's fine and the note component looks like it's fine too so we're good there and now let's move to the edit note component now I had a separate question on this component that I received and it said hey we could use one more layer of security other than what I put in in the last lesson which was about role-based access control and permissions and this would be what if an employee tried to edit a note that isn't available to them through a role just by changing the note ID in the URL now you'd like to think your employees aren't malicious and that it might even be hard for them to get whatever note ID would exist that they would want however we can go ahead and programmatically correct that or look for that so let's go ahead and do that while we're here so I'm going to add a few Imports at the top we'll notice we've got four Imports here we've got the use get notes query and the use get users query we're also going to bring in our use auth hook and then that pulse loader that we're going to use and we can get rid of the selector select note by ID and select all users and we can also get rid of use selector so let's delete all of those and now let's go ahead and put this code into place I'll just start by replacing how we're defining the note and users here and paste in a destructure from our use auth hook and then also how we Define the note and I'll save that but we still need to handle the users so now I'll put that underneath and let's look at the information that we're getting here we'll quickly break it down in case anything is different so we're bringing in the username is manager and is admin of course we're using that use auth hook to make sure for that situation that I describe where an employee could still possibly enter a note ID in the URL and get access even though their role didn't permit them so we're going to prevent that from happening here we're getting the note and we're getting that ID from use params once again to define the note now when we get the users list we're doing this a little bit differently and we should have done that in the last component too for new notes and that is we're mapping over that data the IDS array that we get back that is iterable the entities are not so we need to map over the IDS array for each ID we're grabbing the entity which is the user and putting it in a new array and so users ends up being a user's array for us here and if we look back at new note that is the same thing we did here which I didn't review quite as thoroughly but it's the identical thing we end up with a user's array so we can save those changes and now we're going to change this content line here so I'll highlight this and put in a few changes again this is somewhat to prevent that possibility of an employee entering in a note ID into the URL and still gaining access to it even though their role didn't permit them but the first thing we're doing is making sure we have a note and that we have a user's array with some values in it and we're returning the pulse loader if we don't so we may briefly see that while we're waiting on this data after that we're checking to see if we do not have a manager or we do not have an admin and if we don't have either one of these we're just going to pass along this second conditional here which we could chain but then we'd have to put this twice like uh is manager and this and then is admin and this by nesting this we just have to do this once so we're checking to see if we have an admin or manager and if we don't then we're checking to see if the notes username matches the current username that we get from use auth now if they don't match then we return no access so that solves our problem other than that we Define the content and return the content here okay so we've made some big changes into how we get the data now we're not pre-populating Redux and that is going to let our queries use the data that we get from the use git users query and use get notes query in the lists to be reused in the child components and that works out just a little bit better it's also going to allow us to see updates from other users and that's very important I'm back in the back end code now in a separate instance it's a vs code I'm going to start the back end rest API first with npm run Dev once we confirm it's running then I'll go back to the front end code and I'm going to once again open up a terminal window and there I'll type npm start to start the react app and we should see it open in our Chrome browser okay our app is up and running I'm going to open up Chrome Dev tools and I've got the network tab open so let's log in as our stakeholder Dan D and this network tab is going to let us see the requests that are going out so we're at the welcome page and now we have a request to the auth endpoint to the notes endpoint and to the user's endpoint so we have pre-fetched that data now if we go to view the tech notes another request went from our query to notes and that's okay so we have that data now let's go ahead and look at an individual note and notice no extra query went out we're using the data that we already got from our use get notes query so that is what we wanted to happen and now I had an access token timeout and so it hit the refresh endpoint and we've got another notes query here but that is due to how the timing is set currently in our backend code which of course before we deploy we want to make sure we're at 15 minutes and seven days 15 minutes on the access token seven days on that so I'll want to change that I think from lesson eight we had it shorter okay now let's go to the users and we can see we have a user's request here by the way notes is still has a polling interval of every 15 seconds it's going to request notes again but we've got the users and now if I go to an individual user like our test user it didn't put in another request to users either so that is also working as we wanted it to so that's great now let's go back to our user notice I've got a user here Named Dave that's an employee let's try to create a new employee and we'll just name him Dave all uppercase and I'll just put in a simple password and let's see if we can save and note now we get duplicate username and that's because the collation we put in our backend code is checking for that case insensitivity so even a lowercase Dave will match an all uppercase Dave so that's also what we want I'm going to quickly bring up the back end code once again let's go to that auth controller and I'll check the timing that we've currently got set here from lesson eight yep 15 seconds on the Access Controller we want something a little longer than that so I'm going to go to 15 minutes and I'll probably need to scroll down to find the second place that is set yes 15 minutes instead of seconds it looks like we were already at seven days for the refresh token those are the numbers we want to use in for this project so now that we've set that that should change things a little bit I'll clear that out we'll log out notice on the log out we had notes because it refocused on the window and we've got a refetch on Focus but after that we hit that log out endpoint it deleted our secure cookie with the refresh token when we logged out now let's log in again and check out some state in Redux Dev tools so I'll log in with Dandy first and once we're logged in I'll open up our Dev tools window and now let's go to Redux and I'll pull this over so we can see the state a little bit better on the right and let's look at this API State and we currently have our queries that are identified as notes list and users list and then we also have subscriptions and we can see the subscriptions here as notes list and users list and of course it lists the endpoints beside those as well now if we break this down we have two subscriptions here it looks like and two here under get users see what happens when we go to Tech notes and it adds some more so now this is one for each of these notes that it created and that's okay too because we're using the use get notes query there but we're not creating another Network request as we saw before when we look here we've just got notes and then once again notes there and we could log out and see all of that happen one more time so we'll go Dandy log in and so now we went auth notes users we go to notes we'll see another notes request but now we look at one of these and we don't see another notes request there so requests Network requests are not the same as Redux subscriptions and that's important to point out but subscriptions last as long as a component is mounted and remember each one of these notes in the list is a note component that is mounted as well so now instead of looking at our state here let's go ahead and look at the profiler too now we can record some data as we profile so let's go ahead and make a change to Mrs Smith's computer problem although it says it's completed we can go ahead and just maybe add another exclamation mark here to the end and save but I didn't profile anything so I should have hit record so I'll hit record here and let's do this again and I'll just remove that extra exclamation mark and save now let's stop the profiler and let's see what we get this is showing everything and notice we've got one of nine screens to look at so I'll scroll all the way down here's our notes list and when it rendered because we memoized those notes the notes did not render so that makes it a little more optimized now let's go to the next changes and of course if we pull this over I think maybe I need to pull this over further devtools at least it can see what caused this update and that says browser router so it'll give us some information as we go edit note so we were at the edit note form and every time we typed of course we got a render there and anything else we did and so it has a few renders now we've got what caused this update it was browser router when we went back but now let's look at the final one and the only render we got was the one we updated so it knew that the other two notes were not updated and we got that final update right here so our react memo is working as we expected as well okay now that we've checked our optimizations I'm going to make this full screen and I'll go ahead and log out and we want to go back to the code there's just a few other changes we could make so here is our react code and we can leave it running as far as that goes I'll just close the terminal window and one thing I'm going to do I'll collapse these directories over here in the file tree but I'm going to highlight this Source directory and we could find in all the folders anywhere we have a paragraph that starts with loading and then dot dot dot and that's usually what I would want to replace with that spinner we included and so I will go through and do all of these but just to let you know you could search for that as well or you could also search for that if is loading that seems to appear at all of those so check if is loading and then look for all of those in files and you may want to replace what you have there with one of those spinners instead again I'm not going to show you that I change everyone you can just do it and you can trust that I did it as well okay one final change today I'm going to bring the browser back up notice at the top because a react app is truly a single page app that we make look like it has multiple Pages by using react router but notice the title is always react app and that's what's set in our basic HTML page that's in the public directory however we can create a hook that changes this for each react router page we visit so let's go ahead and do that that's one nice little addition to add at the end of our project I'll go back to the file tree and now we'll go to the hooks directory we're going to create one more custom hook and we'll call this use title.js now inside of use title JS I'll just paste what I have and go over it we need use effect from react and then we're going to receive a title whatever we want the title of the component to be that is currently displaying a page and then we'll use use effect here we'll get the previous Title by selecting document dot title that's from the Dom and then we're setting the document.title to the new title value we're storing the old one in previous title our cleanup function restores the previous title to the document title so whenever the component unmounts it sets the title back to whatever it originally was and we're just looking for changes in the title now this is a true side effect it doesn't have anything else it's returning from this hook and it's really in my mind kind of the perfect react hook it does a simple thing and it sets things back to the way they were with the cleanup function when it is finished so a nice little hook there that we call use title and let's just apply it in the app.js and you can apply it throughout the rest of the project where you want to and you can trust that I will do the same as well so we're going to import use title and now that we have used title this would be our main page and so we just want to put the the name of Dan's business which is dandy repair so we can just say use title and we'll pass in Dan B repairs and that's really all you need to do to set the title of the page you're on so we would have other ones like notes list the users list things like that you might want to start all of those with tech notes or something that indicates you're in the back end where employees log in those protected pages and you can do what you want of course you can check the source code that I'm going to link to in the course resources for mine but right now let's pull up Chrome once again and now you can see we've changed from react app at the top to Dandy repairs and so our use title Hook is working okay I thought I might get the chance to deploy everything today but we're going to carry it over to one more lesson where we're going to deploy the back end code and then deploy the front end code and take everything online and make sure it's working and of course there's a few changes you need to make as you deploy your project as well our myrnstack project is essentially complete and we're ready to deploy both the front end and back-end code repositories there's just a few setting changes that we need to make first and we're going to start in the front end code base and that is from Lesson 12 at least our starter code so let's just change to lesson 13 here in the package Json and we can save that change but we need to add one more dependency and I know you think this is fairly late in the game to do that but you'll see why we're doing this one let's type npm I and then we need the at symbol and then F vilers slash disable Dash react Dash Dev tools and this dependency will do exactly what the name says we're going to disable react Dev tools for our deployment okay now that we have added that and I'll close the terminal you can see we've got that new dependency right here now we're going to apply that in the index.js so let's open up the source directory and go to the index.js file I'll get rid of this extra line we have here between the Imports I'm going to add this extra import here this is import and then it is disable react Dev tools and you can see it comes from at F filer slash disable react Dev tools once we have that we can put it into place it doesn't go inside of the render it can actually go above we'll type if process dot e and B dot node EnV and then we'll say equals with three equal signs production so this only happens in production mode then we will disable react Dev tools so we just call that right there and that's all we need to do to implement that but this will disable reactive Tools in our production mode when we have deployed our application so now to go with that change let's go to the app directory and then we'll go to the store.js and this is for Redux and notice we have Dev tools set to True here let's just change that to false inside of our store.js and now this disables Redux Dev tools and finally let's go inside the API directory to the API I slice and we need to change our base URL value you can see we still have it set to localhost Port 3500 well this is going to be https now and we're going to host our application on render.com and I can already just put in what the API address will be so we're going to call it Tech notes Dash API and then it will be at Dot onrender.com and after that change we are ready to deploy the first step in deploying our code will be ensuring that it is on GitHub and we need to do that with Git so we're going to initialize a repository if you already have a code repository by the way with Git and GitHub that you're doing with this project you could skip this part but I'm going to quickly show how I push the code to GitHub so we'll have git init and after we initialize a repository I'm just going to add all of the code with Git add and a period or dot we've added all the code now so let's Commit This so we'll say git commit and dash M for message and we'll just say ready to deploy and after that we need to have a repository on GitHub to push our code to so let's go to GitHub let's create a new Repository and we'll just call this repository Tech notes and we'll scroll down and click create repository after that we get a page that tells us what we need to do to push the code and we have an existing repository on our computer so we can do this from the command line we need these three lines I can just click the little icon over here to copy all three we can go back to vs code now and in vs code I'm going to expand this so we can see more of the terminal and if I right click it will paste all three in and I'll just press enter and we are pushing our code to GitHub and it should now be there so we can go back to GitHub and I'll scroll up and I'll click on Tech notes and here's our code so it is now in my GitHub account and then I can go to render.com and that's where we're going to deploy our code and now what I need to do is create an account if I don't have one now I already have so I have a dashboard link here that's just ready to go but you need to create a free account it does not ask for any payment information and that's one thing I like about this for students you can just set up a free account without having to provide a credit card or anything like that and after you do you may have to confirm your email address you may want to pause the video and do all of that to get your account set up but then you should have access to a dashboard so I click dashboard and I don't have anything deployed here yet so now I have options static sites and web services we're going to do one of each today our react app is a static site so I'm going to click new static site and it says connect to repository so one thing you'll do when you set up your account is connect your render.com account to GitHub and you can see mine's already connected over here so you want to make sure you do that after you connect GitHub to render and you could probably log in with that if I remember right but double check that either way once you have your GitHub connected you can see your repositories here and you can see Tech notes from my GitHub account is right here so I just want to click connect now I'm connecting the repository and now I need to put in a name here and so I'm going to do the same thing I'll call it Tech notes and then it has a few other questions I'm using the main branch of my code repository now here's where we need to put in the build command and render.com defaults to yarn if you use yarn you're probably already set up but since I'm using npm there's a change or two we need to make here so instead of yarn build it's going to be npm run build and that goes along with the scripts in our package Json and after that it says the publish directory well that is the build directory for a react app I believe so we can just leave that where it is and we're pretty much ready to go I'll scroll down and we click create static site now this will start to show us how it builds the site and this takes just a little while so once it gets going it shows in progress here and you can watch everything that's happening here on the server and this will take a while so what I'm going to do is go ahead and jump to the end but you can set and watch the entire thing for your application if you want to okay I'm back and you can see it says your site is live and it did take a few minutes compared to where we were and that's okay even after it says your site is live you might give it just a little bit of time and that's fine but let's scroll the window back up and it gives us our URL right here which is Tech notes Dot onrender.com and we can copy it or I can just right click and open in a new tab once we do that we've got our Dandy repairs web page and the whole app is not going to work just the public pages will for now we haven't even deployed the back in so we can see this we can go to the login at least look at the page so it is deployed it's just not going to work yet now we need to make a few settings changes to the back end code and deploy it now I've got the backend code base open and I'm of course I have The Lesson 12 code once again so let's just change this to lesson 13 and save that file but now let's jump to our allowed Origins and if I remember right that's in the config directory and there we go aloud origins.js we want to make some changes here here now if Dan D our stakeholder had a URL like the dndrepairshop.com of course that's what we would use and it would probably have the three W's and then not have the three W's as well so we would want to provide both of those if it was available both ways however that's not what we have today what we have was our Tech notes then dot onrender.com so we'll go ahead and remove the Dandy repair shop URL and we can also remove localhost we do not want anybody else to be able to access this application from The Local Host Dev environment on their computer so we'll also save that now our allowed Origins is really just one origin for this deployment after that let's look at the cores options and this is a decision that needs to be made here and do you want to leave the origin in or essentially if it does not have an origin is what I should say if do you want to leave that in or not because that will leave it accessible to an application like Postman something that's running from the desktop that does not have an origin URL so you need to make that decision whether you want that in there or not for today for me I'm just going to leave this in here but you might want to remove it for a deployment especially if you were doing this for for a customer okay after that the only other thing I want to highlight is we do have the dot EnV file that should not be pushed to GitHub you do never you never want to share your environment variables on GitHub so that should be listed in your git ignore file dot EnV should definitely be in a DOT get ignore file before we do anything about pushing the code to GitHub okay now that I've gone over that let's go ahead and open up a terminal window again and I'm going to initialize a git repository so get the knit and once we have that initialized I'll get add and Dot just to add all of the code and then git commit Dash M and here I'm going to say ready to deploy back end and now that I've committed all of the code we're ready to go back to GitHub in our browser so let's do that and we're here at the tech notes repository now let's create another new repository for the back end code so I can go to my repositories and there it has the new Button as well so I'll create a new one and I'm going to call this Tech notes Dash API and now that that repository name is available we'll scroll down and create that Repository shouldn't take long we once again get the code that we need to run from the command line to push our code to GitHub so I'm going to copy that go back to vs code and NBS code I'm going to expand the terminal just so I can see everything and when I right click puts all three lines here inside of the terminal I just need to press enter once and it's going to push my code to GitHub and it should be complete we'll go back to Chrome and let's see if we have the code inside of GitHub now at the tech notes Dash API there it is and now we should be able to find it inside of our render.com account when we click new so let's click new and now this will be a web service this is going to be a node.js rest API and you can see we have Tech notes Dash API available right here so we will connect and now let's provide a name here and I will just say Tech notes Dash API as well looks like the node environment that seems fine your region may be different than mine the branch will be Main and now we have a build command to put in and for our node project here this will be npm install so this will install all of the dependencies that that are needed and then we have a script here and instead of saying node server.js we can just say npm start because we have the start script in our package Json from there let's scroll down and you can see it has the current free plan highlighted and that's exactly what we want so let's just create a web service once we do this we'll be able to enter in our environment variables and so as this deploys we can see it's in progress let's click environment over here and we can add environment variables you could also browse to your dot EnV file and they will accept it that way but I'm going to add them over here and there's one extra one that we need to add and that is the node version that we want to use so I'm going to say node underscore version here I'm going to put 16.16.0 because that's the one we're using after that we need to go ahead and paste in the other environment variables we have and that includes the database URI that also includes the access token secret so I'll bring that over and then we can add one more and that is going to be the refresh token secret now I will go ahead and cut away to enter my values so you don't see those and you can enter your values and come back okay my values are now entered and I want to click save changes and so those changes have now been saved let's look at the events tab here and you can see the deployment is changed because the environment was updated so this is the deploy we want to watch right here so I'll click deploy once again this takes a while this takes longer than the react app on the front end so we'll just want to watch this and of course you can watch the entire thing I'm going to cut away and come back okay I am back and it has completed and we can see the last few messages and that did take several minutes it says build successful but even after that it was deploying and then it detected the node version that we put in with the environment variable and it started the service within PM start and then we start to see things that we would normally see in the console as well so let's scroll back up and let's look at the log which would be the console for node.js and you can see the last several messages were also logged here in this console okay now that we've got that you still might want to give it a minute or two after it says it is up and running to go ahead and propagate out everywhere but then we could go ahead and right click and we should see our splash page that we created if we launch this and right now we still don't have the CSS and if I reload there we go we've got the CSS now so it was just getting ready to share everything I don't like that full white page I like the darker page myself okay so now we know our Tech notes API is up and running and that means our front end should now be ready to interact with mongodb and the back end that we have so let's hit the employee log again and we'll go ahead and enter in Dandy our stakeholder and I'll enter in his password if you have a different user you can do that and I'm going to tab on down and say trust this device as well and then sign in we've got our spinner I Want to Say Never As far as saving the password for this but everything looks like it's working as it should let's see if we can see the tech notes we got those right away because we prefetched that data we didn't even have to see a spinner to wait that's great now we can see the edit note it seems to be working fine so let's go back to the user list you can see Dave is inactive on the user list and it has a different color rather than active and everything seems to be working good here as well we went to that edit user page already so that's great we could of course enter in a new note or try a new user all of those things but we've tested that out already we won't spend time on that during the video everything seems to be good for the application and it's nice and fast I'm going to go ahead and log out make sure that works too everything is good here and with the deployment in place we can bring up our user stories I'm keeping track of this back in the front end code repository by the way and we have officially replaced the current sticky note system and of course we'd want to confirm that with our stakeholder we did provide easy navigation and we had display current user in assigned role that was in place for a little while already we had notes can be deleted by managers or admins and that was definitely true we saw the trash can there available for DND anyone can create a note and we had confirmed that with the employee account Joe that we had created employees can only View and edit their assigned notes that was true for Joe as well but managers and admins can view edit delete do everything they should with the notes and that is also true only managers and admins can see the user settings so we could check that off only managers and admins can create new users we can check that off and desktop mode is most important and that's essentially what we looked at with full screen but it should be available in mobile let's go into Chrome and we've got the web app open I'll open up Dev tools and I need to click away yeah Chrome has been a little buggy for me lately on the dev tools I don't think that's anything to do with our app here we see see it in an iPhone 6 7 and 8 and now let's go ahead and look at maybe an iPad if it fits in there yes it looks great there too let's check maybe just an iPhone 6 and of course the smallest would even be an sc it looks like everything's fitting let's give one that's decent sized here let's get to 75 percent maybe and then let's try the login oh once again I'll log in as Mark the manager sign in we've got a little bit of a wait and now we're logged in and we can view the tech notes and of course we don't see as many columns on the smaller Mobile screen after that we can view yes we can edit the note let's go to users the same here everything looks good there's our test user yes everything is working and looking good in Mobile I think success so we can go back and check off our last item you might have noticed that I'm getting some console log messages as we run the app and of course when you deploy you probably want to go through your code and remove all of those I did not do that and that's just because it's tutorial mode I leave a lot of those things in there to help out viewers and students but you probably would want to remove all of the console log statements and notes like that before you deploy your application as well hey success we have checked off all the user stories and our app is functioning for for our stakeholder that's great now what happens usually after you deploy an app and you meet all of those expectations or hopefully do they will want additional features now don't just say okay and do those of course that's scope creep that makes the project continue to go on especially if you're a freelance developer you've given your bid and you have met every expectation along the way so you need to charge for those additional Services don't sell yourself short and a couple of things I could think of that might be wanted one would be an archive for old tickets so that ticket list did not continue to grow and grow and you might want to be able to search that archive as well they might eventually want this to tie into some Financial or billing software where they could bill each ticket directly from this application and then also they might want to save drafts of notes as they edit a note say their token expires it's been a week and they forgot to log back in during that week well they'll get a notice they won't be able to save that draft so that's something else I would suggest and you may think of many more things that you could add to this application again just remember to don't say okay and just add the extra features without charging more don't sell yourself short on your effort congratulations though you have completed the myrn stack project remember to keep striving for Progress over Perfection and a little progress every day will go a very long way please give this video a like if it's helped you and thank you for watching and subscribing you're helping my channel grow have a great day and let's write more code together very soon
Info
Channel: Dave Gray
Views: 389,879
Rating: undefined out of 5
Keywords: mern stack full tutorial, mern stack, mern stack full course, mern stack tutorial, mern stack course, mern tutorial, mern course, mern complete course, mern complete project, mern complete tutorial, full stack tutorial, full stack course, full course, complete full stack course, fullstack course, full stack, fullstack, mern project, mern stack project, complete mern project, complete mern stack project, complete mern course, complete mern tutorial, full mern course, mern, js
Id: CvCiNeLnZ00
Channel Id: undefined
Length: 470min 56sec (28256 seconds)
Published: Tue Sep 27 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.