Full Stack Todo List Tutorial using Vue.js & AdonisJs

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey everyone I'm Cody Seibert and welcome to a full-stack tutorial where I'm going to show you how to build a front-end single page application using view Jas and also using view X as our state store and then that's going to connect to a back-end written in Adonis Jas basically to create our REST API and then I'm going to deploy this on digitalocean after we finish and so let me just show you really quick what I'm going to be building basically it's a very simple to-do list application whoo-hoo in the left we have projects so we can click different projects here to change we can create projects edit them and delete them and then for each project we can create different tasks and that also marked them as completed go ahead and delete some edits um or of course you can log out and then you can log back in so a very very simple application hopefully this is a good start just kind of explain the concepts of view in Adana so let's just go ahead and get started building out this application alright so now that we know what we're trying to build let's go ahead and create a new repository so on my github account and click new this is her people who don't know how to create a repo so I'm gonna name the repo view adonis to do go ahead make that MIT and I'll create that repo once my repo was created and I was gonna go ahead and click this clone or download and then copy this to my clipboard then in my terminal of es code I'm going to go into my workspace I'm gonna do git clone and type in that repo URL and go ahead and just CD into that folder in fact I should probably open the folder here in my workspace so for this tutorial I'm going to split it up into two major sections the first section I'm going to focus on building out the rest api using Adonis J s and then the second section I'm going to be connecting to that rest api using view J's for the front end so if you're not really interested in learning how to use a dentist to build a REST API feel free to skip forward to the second section and I'll put a timestamp in the description below so again we're using Adonis J s to build out our REST API and basically that is a label clone an MVC framework for building up websites I'm not going to go into too much detail on the docs or explain all the different features and functionality instead what I want to do is just use it explain the things that I'm doing as I'm doing them and then leave it up to you to learn more about the framework in the future so to start using a donis let's go ahead and go to their website and just look at the installation section basically to get started they say you need to install a global adonis CLI tool which i already have installed so i'm not going to run this command and then after you run the command you can do Adonis help to get an information about what you can run with the CLI let's go ahead and do that so if I do with Donna's - - help it's going to print out all the different commands we can run an Adonis now when you're starting off with a new project the most important command would be obviously is the new command right so we're gonna do ad honest new - - help to get more information on that command if you see here we can pass something called API only and that's kind of what we're gonna be using for this because we don't care about rendering views and stuff on the backend and we're going to be using View j/s on the front end with that being said let's just do ad honest new type in the name of our project and in this case I'm just gonna do server I like to separate my server code from my client code and then I'm going to pass that API only flag and as this is running it's going to create a bunch of different files in our server folder and give us a very bare-bones Adonis setup which we can start running and developing or rest API so now that of the Adonis CLI is done creating a new project let's go ahead and look at a important command that we can use for starting or serving our server so again if we do Adonis - - help it'll tell us all the commands and then notice that there is a serve man which starts our HTTP server well do Adonis serve like a knife and help and we have additional options that we can use in the most important one is - - dev to start a local dev server so I'm going to Adonis serve I can - dev and of course make sure you're in the server folder got the CD into that and I'll rerun that command and after this runs it's going to host a server on port 3 3 3 3 if I go to my terminal or go to my chrome and go to localhost 3 3 3 3 notice that we get a JSON response back from our donna server so we're good to go we have it done is set up and we have it running another cool thing I'll state about this donna surf command is that as you edit your JS files and save them it's going to restart your server for you automatically so it's kind of using like no daman behind the scenes we're just watches your files and restarts them so before we get too much further into this tutorial let's go ahead and commit what we have I want to say initial Adonis setup so at this point let me just go ahead and give a quick overview on some of the files that are generated I'm not gonna go over all these files I'm just going to focus on the ones we need to implement our functionality and then we can kind of cover more as time progresses so the first one we want to cover is inside the Start folder there is a file called a RAL CAS and basically this file is for declaring your routes so I mean it looks very similar to Express or Cola or happy where you have a router object you give it a command such as git postally patch whatever you pass it a URL and then you pass a callback function though nothing too new here second file or folder I want to show is inside the app folder by default we're giving a models folder which has a user J's model so if we look at this basically we're declaring a lucid model which has a hook attached to it so before we create a user model we're going to hash the password and then at the end we just return that model so nothing to do insane here and then inside the hooks folder we have that user J s file which declares that hash password hook go in here basically we say if the user instance has a password attribute we're just gonna hash it and then put it back into the past before we save this model and so for those of you who aren't really familiar with the hell-like or ORM does work typically there's a bunch of hooks that exist around models like before you update them before you create them before you save them that you can kind of attach callback functions to let manipulate your data before it actually hits your database mmm and this thing with like getting data you could do a hook before you fetch the data or app you fetch the data to manipulate the data inside your models so I'm not going to dive too much into hooks or that type of stuff feel free to look at the docs if you want more information but the main takeaway is we have by default a user model so you'll notice here there's no attributes so associated with this user model inside this file and that's because if we go back and look at the database folder there are a migrations folder which has a user J's migration in it so inside here this is where we declare what properties should be associated with the users table so basically when we run our migration scripts it's going to create a user's table it's going to give it a user name email and password and then if we were to roll back our migrations just gonna drop this table alright so another quick quick recap we have a routes file where you declare your routes we have a models folder where you declare your models and then you declare your tables that will be associated with that model in your migration scripts alright so now that we kind of glossed over some of the files and folders that are included in the adonis CLI new projects let's go ahead and get started on trying to implement some functionality so the first thing I want to do with our to-do list tutorial application is I want the ability for users to register new users or new accounts so how would we do this obviously the first thing we want to do is create a new endpoint or new route where they can hit with a post request to create a new account if I go to the Start folder and go back to my routes ijs file inside here we can simply do or route dot post because we're doing a post request and then we can do something like off slash register and some type of callback function and it's I'm just going to return another hello world message just to kind of demonstrate what's going on so if I were to save this file and then go to another app that I have installed a running called postman we can make example requests to our API just to test it out so remember our endpoint is off slash register it needs a post request so if we go to postman which is here this is on the post main app it's really useful for testing your REST API s we type in the location of that URL auth slash register and I tell it to do a post request and I give it to a body in fact I don't think I even need to give it a body so I'll just go go ahead and click send notice that it sends back our hello world message so we created a register endpoint that returns a message awesome first steps are completed so for the second step we instead want to put our callback logic in a controller and not have it all defined in one file of Rous jeaious so if we were to go to our second terminal and remember that we have all these useful commands which we can use to run and create our Adonis app one of the commands is make controller so if I do add honest make controller help get more information on that basically a week and run is honest make controller ass at the name of our controller which in this case I'm just going to say a user and that will create a controller file inside the again make sure I'm in the server folder keep reading to do that well first of all that's going to ask if you want it to be a WebSocket channel or an HTTP request I'm gonna say HTTP request and notice that it's going to create a app dot controllers folder HTTP controllers file here so let's go ahead and look at that file and see what it created is just a simple JavaScript class nothing too special here but what we want to do is we want to define methods in this class so in this case we're going to say register and let's return that hello world message you and then to bind that to one of our out so we simply go back to our routes file and then instead of passing the callback function here we can just say user controller dot register so again let me save that file and go back to my first terminal just to make sure that the server restarted and then if I go back to post man and click send we get that same response back main difference is we're just binding to the controller file and then more specifically to the action or method that's declared inside that controller class so before we get too ahead of ourselves let's go ahead and do a little bit cleanup so first of all I'm gonna remove this get request method because we're not gonna be using that so another cool thing adonus has is you have the ability to group routes with a prefix so let's say I wanted to append slash API in front of all these different routes that I had so if you imagine I had like 10 different routes and I want to app in API to all of them you could do it this way where you have a bunch of copy and paste like URLs with the same prefix or one way to do it is I just simply do route group asset a callback function put my route in and then after the group you just say prefix with API so now when I save that I try to hit the route that we had before it's going to return an error but now I can actually hit it with the API prefix so that's pretty cool and then you know sometimes you want to have different versions so this might be version zero and then down the road a year from now let's say you need a version one that get deployed you just saying change that to be one and then you have all of your different routes for the v1 here let's go ahead and try to get back on track so what were we originally doing we are trying to create a new register in point where we could pass in an email and a password in the payload and then have that created in our database so let me just go ahead and remove b0 because I'm not going to be using that in this tutorial and then if I go to my user controller what we want to do is we want to be able to grab the request body that was sent in so as an example if I were to post some JSON to the endpoint so if you see here we have an email and a password sent we should be able to use that in our controller so the do so let's go ahead and first grab that request object which is available using object deconstruction here and then inside this we can go ahead and pull out the email in the password again using object deconstruction from request all so requests out all is going to grab and merge our query string parameters together with our post to payload body and then we have the ability to grab the properties like so and again we're just going to print these out and just make sure that everything is working as expected so if I do that post request I go back to my terminal I see that testing and the password is printed out to our terminal so we grabbed the parameters or the payload body successfully using something like this the next step - how would we register a user is we need to use the lucid model to create and persist a new user to the database so to get started on that let's go ahead and include that user model and then inside a dantas there's a keyword called use so instead of user and require they recommend you use the keyboard to use and that's just because this the inverse of controller method that they're using allows you to easily mock out and fake these during your testing another cool thing is you can just do the relative you don't have to do like dot slashes your relative paths to your file to get this to work instead we can just do the absolute path so app dot models dot user so that's going to grab the app models dot user file here which is a lucid model and now that we have that model we could simply just do user dot create asset the email ask the password and then of course we also declared something else called a username which we're going to be setting to the password in this case and we need to just at the end return the user so one thing I'll notice or I'll point out is that these are typically async methods so dot create or save or whatnot so in order to successfully use them you need to make sure you put a weight in front and of course in order to use a weight you need to make sure you use the keyword is async in front of your method so now if I say this I should be able to create that user when I do my post request I got a little an error here and the error is saying I don't have sequel 8-3 installed so let's go ahead and do that if I go to my terminal and just install that that will allow us to actually connect to our sequel Lite server because you need to make sure you install the specific driver of the database you're using so if we're using my sequel or Postgres you need to make sure you install it the correct driver and in this case we're using sequel Lite hmm so we should be able to just install that we should be good to go let's try it again and hopefully it works so if I click send we are getting yet another error so let me see what's going on here and one thing I do to kind of debug is I have jsbin loaded up I could have paste the HTML fine here this is saying that there's no such table as users and the reason that this is throwing an error is because we forgot to run our migration scripts so let's move on to yet another topic which is migration so if I open up a new terminal here and do Adonis help you can see what command we have related to migrations if you see here there's five commands for migrations the one we're kind of I'm curious to use would be migrations colon run and that's going to run through your migration scripts and run anything that it hasn't already ran yet so here I'm just into Adonis migration run run that that's going to create our user table in our token table so finally if I were to do a post request on that endpoint we should be able to persist that user and look it did we got our email back we got a password which is hash back we got our username created at updated at and we got an ID so just to verify that this is actually persisted to the database if we try to do this again notice we get an error back if we look at this error it's going to say that a constraint failed there's no unique user email so basically this error is saying that we've already used the email and we can't use it again so we know that is trying to create that same user and put into the database it's throwing an exception and it's sending a 500 status code back with an error message awesome so as a really really quick recap we created a new route which accepts a post request to off the slash register we prefix it with API and we're binding that to the user controller register action or method and inside the user controller we made an async function which takes two requests it takes two parameters or body from the request we use object deconstruction to grab the email and password we create a user using that email and password in setup a username important make sure you use a weight here and make sure you have a sink here we get the user that was created and we return it back to the user and then using postman we saw that when we tried to create a user so if I do testing 2 or 3 it should create a new user with testing 3 and send it back to us well so now that we know how to create new routes and controllers and stuff let's go ahead and try to create a new one called login and what is gonna do it's going to check the see if the email password provide matches what is actually in the database so to do so again we just need to make a new method here inside this controller called async login and that's going to take the request object for now and again we need to grab the email and password from that request I'll just do that and then secondly there's something cool that's already built in to Adonis which is an auth property that's passed in here and basically what auth does is it has a couple of helper function functions on it that allows you to try to authenticate your user so if I were to do kama auth we now have access to that auth controller in the main reason we have access to that is if we look at our app dot J's file here inside the Start folder there's a provider which was declared called the auth provider which gives us access to that off thing our author object this wasn't here we want to be able to do that and then what type of authentication are we actually using so if we were to dive into the config folder here and look at SAS notice that there's a couple of different off types that are kind of built in we have session we have basic auth we have GWT so by default this is using the JWT auth and if we look down at the GWT configuration notice that it's pointing to our user model it's going to automatically try to fetch based on email and password so these are the two columns that it's going to look at and it's going to use the secret key here to define a new JWT token so if you don't really know that much about JWT I suggest you go read up on it I'm not gonna really give you that much of a deep dive on it but just know that this authentication object that we're using it's just going to look at our database and it's going to create a key for us if the user is successfully logged in so doing so let's go back to our controller remember we brought in this off object what we want to do is we want to try to authenticate the user so we're going to say cons token is equal to a weight off dot attempt and then we're going to pass it our email and we're gonna pass it our password and then we're gonna return that token so if this is successful we're gonna get a token send it back to the user if this fails is probably gonna throw an exception and send back an error to the user if I save this file this last part is we need to go to our routes file and we need to declare a new endpoint so that we can actually try to register our login so I'm going to copy and paste this line 19 and instead of register I'm going to do login and then login for action here save the file and now at this point I should be able to try to log in with that same username and password that we just registered with so you remember we registered with testing at gmail.com and that's the password oh if I just copy this payload instead go to my off slash login endpoint and click send we get back a response that has a token in it but for those who don't know what a JWT token is basically it's just a way to cryptographically sign adjacent object if I were to take this token and if I go to jadibooti dot IO I can paste my token into their website and it's going to decode it for me if you notice here after I pasted it in this is the data that's encoded inside of that payload basically just has to use your ID so if you notice here it's a 1 just to kind of further demonstrate that remember we made another account called testing 3 I try to log in with that it's going to give us a different token if I want to code that token inside this website notice that the user ID here is a two so behind-the-scenes adonis the auth module is just going to fetch the user from the database verify that the user name and password match up correctly and then if it does it's going to just encode a token that has a user ID in it so the cool thing about this is I can come into this token and just make random changes to it but if I do to fail the signature that only the surfer knows about so with that being said basically any token that the server assigns and since to the user we know a certainty that no one else can modify that token and send back to us and we can kind of cover an example in a little bit because we're not fully done implementing authentication yet so I'll keep this website up and let's go back to our code and just kind of look at one more thing that we can refactor so another thing I wanted to do is when you register your user you're probably going to need that same token right so what I like to do is instead of just returning the user we created I'm just going to return this dot login and then past the arguments that were passed into this request and in this case we don't really need the user anymore so now that when we register or if we login we pretty much get this payload back every time so if I go back to register and I make a new account testing 100 we get back our halo that has a token in it awesome so we just made a new login method we modified the register method to call a login after we register and then we created the route to allow us to register and login we're making some good progress now we just need to UM move on to creating some new database models before we move on to that let's just go ahead and commit what we have so I'm going to say registration slash login and commit that and then we can start fresh back into this file 17 so since we are planning to make a to-do list application one thing I want to include is a new project model so I plan to separate my data into projects then inside the projects we have tasks so at the Adana CLI and see what commands we can use to try to help us create a new model so I do a Donna's help notice here we have a make model Adonis make model help and basically we just pass the name of the model and then there's also like a controller and migration if you want to create a migration for the model and in this case we do also want a migration so be sure to include this - in so again we wanted a project model so if I say project and then pass - M that's going to create us a project model inside our models folder ruch might be is code and then also we get a migration script old projects so first off let's go to our projects migration and we need to make sure we declare some attributes on our projects before we run our migration scripts so to do so I'm going to look at the users and just kind of copy this one line here and we want our projects folder to have a title that's going to be a 255 max length string and I'm just going to remove the rest because I don't care if it's unique and I don't care if it's null or not second thing I want to do is a project belongs to a user right so inside our migration script if I look at token they have an example of how to do that basically if I copy this line and go back to my project schema but that up here we want to us fill e8 the project to a user so we need to make sure I'd use your ID column exists on the project's able so we're saying yes it's an integer of user ID it's unsigned it references the ID in the users table and then the last part is we need to go into our projects bottle and we need to make sure we declare an association so if we look at the token J s file here I'm sorry the user is file you what we can do to declare associations is simply just copy and paste this project are this tokens method and instead we're gonna name it projects and this is gonna say this that has many app that model that project and this just tells lucid how to look up articular associated records using the project's method so literally inside of our controller we can do user dot projects and that's going to fetch us all the projects associated with that user and then the second thing we want to do is we want to go back into a project model and create a new method called user to declare that Association in the other way so I'm gonna say return this that belongs to app models user and this is just saying that a project that belongs to a user and then a user has many projects so that allows us again to easily look up data both ways depending on what type of lucid model we have instantiated in our code and this will make more sense when we actually start using it so again we created a new model called project which created us a migrations file we declared a title inside that migrations projects table and we also declared a user ID which references the users table and then we declare some associations in our project and a user model so what we want to do is we need to run our migration again so if I do a migration run that's going to only run that project migration script because we've already ran those past two right so now in our database we should have a table called projects and that should be ready to go awesome so the second thing is we need to create a new controller and route so that we can actually create new projects right if I just closed all of these and then we can start doing that remember an Adonis we have a create or a make controller method so here if I do make controller so Adonis and make controller help if they get more information I'm going to pass it the project as a name so that we have a new controller called project and that's going to be an HTTP type of controller an inside of a project controller let's just go ahead and do a index method this method is supposed to do is supposed to return all the projects that are associated with the user and of course we don't have a create method yet so we'll have to make one in a second so in order to do so we're gonna need that off plug-in again and it luckily off has a nice little utility function called it user if I do Const user equals a way to off that get user that's going to fetch us to user which was associated with the JWT token that we passed in so again if I just print out user here and then return I'm random message for now we should be able to create a route which is going to point to that controller so here I can say route to dot and get and that's going to be on projects and that's going to be on project roller dot index the inertia so go ahead and save my server and I should be able to try to hit that projects in point and in this case I'm going to pretend like we didn't pass an authentication token and this should throw an error because we haven't actually passed a JWT token like we said we needed to WC here I expect the token cost user a weight off the docket user and we're actually getting this because I probably forgot to add async so remember make sure you always add async if you're using a weight here and I'll try to hit that endpoint again see what the air is and we get an invalid a JWT token right JWT must be provided so at this point what we want to do is when we declare the route we also want to declare a meadow where function so that we can parse a JWT token from the request so inside of our line 22 where we declare our index we want to make sure that we add a middle where all until it that it's going to be an awful so basically we're going to authenticate the user with that J DBT token before we run our controller here so again if I try to hit that endpoint we're gonna get back an error again Sanjay DBT must be provided so let's go ahead and try to provide that J to be T token so if I go back to login and I just login with our testing at gmail.com user and I grab this token typically the way to pass a JWT token is inside the header you have an authorization key and then you pass it something called bearer and then the token like so and an inside postman what we have is we have environments where we can just set up kind of key value pairs so we can use those in all of our requests so if I look at the environment here I already have one set up called authorization which is set to a token so let's change it to the token I just copied and put bearer in front and this is just the nama clay sure we use because it's a barrier type token go ahead and update that close out of that and then I'm going to make my request and see what happens so this point we get a message back that says hello world and then if we were to leave off this authentication token we're going to get back that same error saying that GWT token was not provided this is also going to check your token to make sure it is valid so if I were to go and try to create and spoof my own token and send it to this endpoint it's not going to work as expected so going back to our code the main thing that we wanted to kind of show is that once we fetch off that get user it prints out that user information here so we have access to user ID inside of this controller if we wanted to use it I'll go ahead and just print that out at the endpoint one more time and notice here it's printing out one because you remember in JWT i/o when I decode this token it's printing out user ID of one and what that does is going to fetch the user from the database using UID and then we have access to that user model here okay so we're almost done with this project index method the next thing we need to do is using that user we need to fetch and return all of the projects that are associated with that user so if I do return a weight user dot projects dot fetch that's going to use our associations to fetch all the projects that are associated with that user if I save this go back in request that endpoint it should return back in mtra because we don't have any projects created yet which leaves us to our next route let's go ahead and create a create in point so if I do a sync create I'm going to take an auth in a request and let's kind of step through what we might want to do right so we're first need to verify that the user as the token passed in so if I go to routes I'm just going to create a new post request to slash projects it's going to call or create action and then again make sure they're authenticated and then we want to grab that user so cost user is equal to a weight off bag get user from the database so we have a lucid model instance we can use we want to grab the title that was passed in in the payload so for example if we were to go back and post a project we're going to pass the title Yolo here and we're going to fetch it from the request here now we want to create a new project but we have an included project yet so first we need to say bring in cost project from app dot models that project and then we need the creative project so project is equal to new project this is going to create us a new instance of our lucid model for the project we want to fill in or set values so one thing I could do is I could do project title is equal to title or something you can also do is project that fill and then pass it an object and that's going to set anything that you pass in so if I were to say name and name exactly and if name actually existed on the database it's going to put name on to that project to but it doesn't so let's just get rid of that and then finally we want to create the project and associate it with the user right so if we do a weight user dot projects dot save and passes the project and then finally we can return that project so recap we created a route for that projects create method we make sure it's authenticated you grab the user we fetch the title from the request we create a project and fill in that title information we associate the project with that user and then we return the project back so let's go ahead and try to hit this endpoint now though I'm gonna click send it works successfully and it returned us the project that it created so it has an ID of one as a user ID of one has the title Yolo and now just to demonstrate if I go back to my projects in point and try to fetch all the projects for my user it's going to return an array with that project created and so I can hit this a couple of times to keep creating projects and then when I try to fetch all the products from a user notice that we have like a 5 over 4 project returned let's just go ahead and commit what we have and then we can kind of just knock out all the remaining project methods okay so the last two methods we're going to create on the project's controller is going to be a create or I'm sorry not create it's gonna be a delete in an update method so let's go back to our routes and let's go ahead and make a new endpoint that takes a delete request and this one is going to actually take a ID so if I do project ID here in fact I'll just keep it ID to keep it generic and then we can call a destroy method and again make sure the user is authenticated before we hit this in point so if we go back to our project controller and then create a async method called destroy it's going to take it off in a request but let's kind of step through what we need to do again we need to fetch the user so whatever user made the request get that user model and then we need to get the project ID that we declared here and the route so to do that in adonis we could also include another property called pram or sorry params and that's going to give us the query parameters and we need the ID so if i do ID is equal to grams done ID or again if we wanted to do object deconstruction we do this after we have the ID we want to fetch the project that's associated with the ID of a Const project equals to a weight project dot find now find is a method that you can use it pass in the IDE that we want to find it's going to return the project model so I'm just going to say find ID that's going to return us the project now at this point we don't want any user to just potentially destroy this model right we want to make sure that the project we fetched actually has access or the user that did call destroy actually has access to the project right so what we can do is we can just say make sure that project user ID is equal to user dot ID before we do anything in this case I'm just gonna say not equal and then if they're not equal to return something to the user so here I'm going to say response dot a return response dot status of 403 basically return a 403 status code which is authentication or authorization error status if the project that we fetch does not match the user that was asked in with the GWT token but if we do have access we're going to not hit that if statement and underneath here we can just say project delete and then we're going to return the project that was deleted let's just go ahead and save this and try to test it out so going back here notice that this user has a bunch of different projects associated with it so let me describe project three and I'm going to go to the delete request and tell it to delete project three so after I run that it's returning the project information that was deleted and if I go back to my get request how to fetch all the projects notice that three does not exist in this list anymore so our delete method is working as expected before we move on something like this is going to be copied and pasted a lot throughout our application so I kind of want to abstract that into a different hope or service or something like that so what we can do is I'm gonna make a new folder inside an app called services and I'm sure there's other ways to do this my heart isn't sure I'm sure you could use like providers as well but for now I'm going to keep it simple but I'm just going to make a new service called authorization service and inside that service I'm just gonna make a class called authorization like a type and that's gonna have a method called verify permission which takes a resource and it takes a user the exact same thing as we did before I say if the resource user ID is not equal to the user ID we're going to throw some new error and in a second I'm going to actually use a real error here now what we can do is back in our project controller we can go to the top and include that so I'm just say offer is a ssin service is equal to use app services authorization service and instead of doing this if statement here I'm just going to say authorization service that verify permission project user so hopefully if everything works out correctly if I were to run this with the delete method and pass it ID 4 it should still delete that resource and in this case I got an exception let's see let's see what that exception was verify permission is not a function so I might have spelled something wrong verify permission authorization service oh I forgot to export at the bottom my bed so make sure at the bottom I'm just going to export a new authorization service here that we can use it open now if I were to hit this end point it delete it deleted this project with an ID of four so everything is still working as expected but if I want to test if I had access to the resource so let me just log in with a different user so if you remember we made a user of testing 3 let me grab a token and update here difficulties deleting this token huh okay so we updated the environment to have a touken protesting three now I want to a delete ID of one in two which if you notice has a user ID of one but the token that I'm set up with is not that correct user so if I go back to delete and try to delete project one we get back an exception and in this case it should be a very generic exception it doesn't say anything but notice that this is actually running now if I were to go here and just print something else and try to delete that again that prints out invalid access so something full and Adonis that I need to point out is that when an exception is thrown in your controller it's going to return that exception to the user so I don't need to have if statements and like specify certain status codes in return instead I could abstract that into an exception again going back to a really useful adonis CLI if I do Adonis help notice that we can make an exception here so I'm gonna do Adonis May exception help information on that this one only takes a name so I'm gonna say let's see authorization actually I'm going to name it's invalid access into valid access and that should make a new exception called invalid access exception inside this exceptions folder so now that we have the invalid access exception we could just write a custom handler function which is going to take in an error as the first argument and then you can have access to the response here and basically we just want to return a response of a 403 status code to the user a return response status of 4-3 and then I'm going to send it back some JSON this as error 'invalid access to resource well so now then I save that so invalid access exception is equal to use app exceptions dots invalid access exception instead of throwing new error we can just throw our new exception here our access the authorization server should be returning that exception and then when this exception fires from Adonis it's going to return a 403 status if I go back and hit that endpoint notice we get a 403 for a bit forbidden and we get invalid access to resource and this kind of helps us clean up our controllers so that we don't have a bunch of if statements to check if something is defined or if a user exists so another exception I want to catch is for whatever reason if let's say Project was not defined so they give us ID of a thousand this is going to be null here which is going to hit this function and probably throw a 500 error right so let's just go ahead an other exception called resource not exist the inside verify permission if we were to just check and say if resource was not defined let's just throw a new invalid our sorry resource not exist exception and there might be a better way to do this that's already like built into the Donna's framework but this seems to work for now and then of course inside of that exception we just copy the handler that we had in our previous exception paste it here and we want this to be a for for and say the resource did not exist oh so I'll save that one I'll go back and I'll try like out of a thousand click send and notice that we get back a four or four not found the resource to not exist that is a really high-level overview of exceptions and how you could handle them to return custom status codes to your requests let's go ahead and commit what we have now and move on to the last one which is going to be update exceptions my code and get back to a nice state just to continue working okay so the last route that we want to add for projects would be an update route so here if I say Ralph dot patch and again that's gonna be Project /id and we're gonna say update that's going to also need the auth middleware but we created our route let's go to our controller and create our action so I'm going to say update auth request params very similar code we could probably pull this out into like helper functions so we don't copy and paste code everywhere but since this is just a simple tutorial well I'm not going to do that again I'm fetching the user from the auth helper function I'm fetching the ID that we want to update I'm fetching the project that we want to update I'm going to verify that we have access to that project and that that project also exists and then finally what we want to do is we want to fill in like we did before in this case I'm going to do merge so project that merge and I'm gonna say merge it with the request of the title the only grab the title that's passed into the quest and then I want to save that the project that's save and then I want to return the project this is kind of a new method that we saw basically it's gonna take from the body of the request just grab me the title so if someone were to pass in a bunch of different properties I just want the title here and then I want to merge that into the project and save it and return at this point let's just go back and fetch all the projects that do exist on this user is remember we deleted a bunch we don't have any so let me just create a new one go back fetch it well so we have a project as ID 5 which belongs to a user 2 let's change the title to Gigi so if I go to my patch in point let me can a patch request to project slash five we want to change the title to Gigi so if I were to send this now this should work okay and it did so we've updated the title to be Gigi if I go back and try to fetch the projects associated with my user the title is down Gigi okay so update is working as expected now so we have our four main crud methods we have create fetch update and destroy we don't necessarily need to show at this point because I don't think we need to fetch a single project in the UI but we could always come back and add that if we need to so let's go ahead and commit that so let's say add update in point then we can move on to our tasks okay so for our tasks we're gonna be we're going to need to create a new model again we can go here and say make model and then we're gonna pass it tasks with - M so it creates our migration scripts and let's move to our migration scripts and just add whatever we need for the the tasks entry so task is going to have a title and it's also going to be associated with a project so I'm just going to copy those and instead of user ID interesting project ID and that's going to be in the table projects refers to ID this looks good and then instead of title I'm just going to say description those tasks should be set up correctly and now I need to go into my models and very similar to how we did before I'm gonna go to our user model I'm going to copy and paste this is a task has many our sorry I project as many tasks so here I'm going to go asks and a project has many tasks inside of our tasks I'm going to say a task has one or belongs to a project go ahead and say that I should be able to run my migration scripts at this point which will create our tasks table and we should be able to actually use our lucid models to start manipulating with that table okay so let me go ahead and just close out of some of these so it's not so overwhelming like a step back what are we doing so we want the ability for users to create new tasks and because of the way a task is set up you can't really have a task unless you have a project in which it associates with so I'm just going to add a new endpoint here called projects of /id slash tasks so a user can post a task to a project and of course here we're going to say tasks controller instead of project controller and that's going to be a crate method and of course we need to make sure we're authenticated here as well so I'll set up let's go to our task controller which you don't have created yet so if I go make controller and then pass that task that'll create us a new controler file or our HTTP requests and inside here we need an async create method and this one's going to be very similar to the project create method so let's probably just go ahead and create our copy and paste all the code that was under our project create method if I go to project I go to create I'm going to copy this code and then of course make sure you include the things up here that you need so we're going to need project and we're probably going to need tasks so I'm gonna include project and task okay so when we create a task remember that in the prams we have that project ID so you know I'll comment this out for now so we can just kind of reference it but first of all yes we're gonna need the user so let's just grab that user Oh why that happen autocomplete and then we need to grab the description from the request so a description of request of all and then we need the project ID Oh ID from prams remember we don't have of--there so let's bring off bring in request let's bring in params we're going to need to fetch the project so cost project is equal to a weight project fine by ID so that will fetch us the project we want to verify that the user has access to the project though I'm just going to go here copy and paste this authorization service stuff you then we verify that the project the user has access to the project so if you remember before when we created a project and we associate it with a user kind of the same deal here so what we need to do is we need to say create a task the mistake Const task is equal to new task instantiate a new Lucid instance model and then I'm going to say task got fill in a pass a description and then I need to associate that task with a project some say wait project got tasks dot save the task and I want to return that task back to the user so nothing nothing new here at all is just kind of a matter of doing a little bit more extra code because we need to grab the project and then we need to associate the task with the project and then all the other stuff we've seen before fetching the user fetching the description from the parameters are the ID from the parameter is the description from the request that's all said and done the past so while we're here let's just go ahead and create an index method so we can fish all the tasks associated with the project so we can easily test and see what's going on so I'm going to add a another route Auld it on the tasks in point and that's going to call the index method and that again is going to be indicated here so going back here I'm going to say make a new method called a sink of index that's going to take off and request you and very similar we need the user we're gonna need Rams as well actually though in fact let me just copy all this and then delete what we don't need we fetch the user we don't need the description doesn't write really creating or updating anything so remove that we don't need to make a new task so remove that you don't need to fetch or associate tasks so remove that cool so we if the user if the project ID we fetch the project you verify you chose access to the project in we just need to return oh wait project tasks dot fetch so returned all the tasks that are associated with a particular project ID assuming that the user has access to that project let's try to test out these two methods and hopefully everything works out you so again let's create a new project just that we have something to work with and then that project ID is a six so if I go to tasks here we want to be able to post a new task to that project ID so I'm going to put project IDs six here I'm going to pass a description of hello make sure my headers are set up and they are so hopefully if I click send this will get added to the database and it did the now project ID of six has a hello task if I do it again I should have two tasks but then to fetch the tasks I'm going to click on the get request URL that I have saved here I'm going to change this to get the project ID of six tasks make sure the header set up and it is but when I click send here I should get two tests back and we do so awesome those two endpoints we just created are now working and really that then it take much time at all to create so we're kind of coming close to wrapping this up so let me just go ahead and commit what we have so let's say tasks index and create and let's move on to the last two things that we need for a task obviously we need to be able to update and delete tasks right so let's go back to here let's make a route dot delete on tasks of ID I'll make that a destroy call and make sure you have middleware and let's just go ahead and make the other one while we're at it here so we need a patch request and we need to be able to update the task so for deleting a task it's going to be very similar to deleting a project so I'm just going to go to the destroy method copy and paste that into my S controller and kind of modify it as needed so here again we fetch the user we need the task ID or we need the project ID I mean actually no we don't we don't need the project ID so this is to be the task ID here we need to fetch the task we need to verify at some point that the project that the task is associated with the user has access to so here we need to say project you our cost project is equal to tasks that project fetch and then we can check that the project the task is associated with the user has access to if they do all we need to do is say a way to test delete and then we can just return that task here so everything here should be okay let's go ahead and implement the last method which is update so just copy and paste some code we're gonna need probably similar code here again we fetch the user with the project ID here or sorry get the task ID fetch the project that's associated with the task verify the users essence to the project and then instead of deleting here we need to do that whole task dot urghhh and we're gonna say requests only and we only care about the description in this case you in fact I forgot to have a completed so when you're in the UI and you're clicking and marking tasks as completed we want to have yet another boolean called completed on that task object so we're going to need to go back to our migration scripts and kind of update that but so let's finish up this task controller really quick and then let's go back to our migration scripts we go to migrations I got a task and here I could just say boolean of beaten hmm so a cool thing you can do in Adonis is if we look at the migrations again there should be a refresh so if I do Adonis migration colon refresh that's going to drop and reset all of my migrations and it's going to rerun them all again so that basically we're creating this completed thing we're adding this completed tea column to our table you can also do a rollbacks if you wanted to or reset our stuff or you precious pretty good because it just rolled back rolls back everything and then reruns them so now our table should have a tasks sorry now our database should have a tasks table with a completed boolean column in addition to the other ones ahead before so at this point since we roll back it probably deleted all of her data so we need to go back and register a user and then we need to fetch this token and update our authorization header here we need to create a project make sure we get that project ID of one let's go ahead and create a task on project 1 that's the projects in the tasks just to make sure that everything is set up as it should be it's a completed null awesome description of hello but we want to test out that we can first of all update that task so this is task of ID one let's just check that we can update the description to patch and completed to pulse so if I send that we're getting back an error so let's go ahead and look at the error here find module controllers tasks controller that's just because it's not tasks controller it should be tasks I named that incorrectly so that's my bad let me save that go back and hit this in point and now we're getting an invalid access to resource or o3 for bin see you [Music] you okay so looking back at the task controller let's look at the update method and figure out why this is saying invalid access and so we're fetching the user getting the ID hitting the task getting the project verifying the user has access to the project so what we could do here just start printing stuff out so project dot new JSON I could do tasks to JSON I also do user dot to Jason and make sure all these kind of line up as we'd expect them to you you um let's pace this and see what's going on Roger got to Jason is not a function okay you you so instead of saying to Jason let's just print these out so we have a task which has an idea of one project idea of one we have a user which has an ID of one and we have a where the project go oh so this will get you every time make sure you always have a weight in front of your acing calls if you don't this is just gonna be a promise and then it never thought nothing's really gonna work as intended let me say that I want to make sure I had that updated correctly as you okay sorry about that one let's see if this will finally work so I think it finally patched that task with description patch two completed false so if I were to go back and try to get that task see that we have completed is zero and patched is the description now and then finally we want to test if we can delete a task so if we go to the delete method and tell it to delete task of ID one look send notice that it returns the task back to us and if we try to fetch it again it's not there so a little bit of hiccups along the way you know stuff I forgot to do in this tutorial but overall I think we're done building out a REST API they didn't take too much time as once you get a couple of routes going it's as simple as copy pasting and changing around and then as time goes on you'll notice that these crud methods are basically the same for every single resource so you could probably create a helper method that decorates these controllers that kind of does this logic for you but for the sake of this tutorial let's not dive into refactoring or do anything like that basically we have a way for users to register log in great projects great tasks update those tasks and projects and delete them and stuff so we're at a good State now that we can commit what we have wrap this up and move on to the View j/s tutorial all right so now we're going to get started in the second section of this tutorial which is the view J as fronting and very similar to the last section I'm kind of just going to rate it as I go and explain what I'm doing if you feel lost at any time feel free to pause and go look up the view documentation so to get started with building out the UI you move over to the view CLI github repo the latest version they have out is view version 3 beta 10 I'm going to install version beta 9 because I'm getting issues with tin but you don't want to use version 3 if you want to use the old you CLI - I'm not sure how how well that will translate to this tutorial so in this tutorial I'm using version 3 if I copy that and go ahead and just paste it in my terminal and put ad version 3 0 0 beta 9 that's going to install the correct you CLI that I need to kind of demo awesome so now that that is completed we can simply run view create and then type the name of the folder or project you want to create so on this click in this case we're going to do client we want to create a client folder that has our stuff and after you do that it's going to kind of walk you through a couple of questions as to what you want to use to set up your project so I'm going to do manual select features just to make sure that we're not instantly something that we don't want so I want the router I want to view X and I'm just using the arrow on my keyboard in the space button to select stuff linter would be nice and CSS preprocessors I guess would be nice I'll hit enter I'm going to say use sass and I'm going to use the Airbnb config this is like the lentor options a slant on save be good enough kada config file I should be okay so after you select all the stuff that you want it's going to go ahead and just create your client folder and initialize all your different view stuff that might take a while because it's probably installing a lot of different packages so now that bat is finally done running we have a view app over here which I'm not going to go through all these files just start developing on it and I'll explain what I'm doing as we go through but before we get started there's a couple of extra dependencies I want to install now so that we don't have to worry about installing them later so if we look at what we currently have we really only have three dependencies view view router view X but there's a couple more that we're going to need so I'm gonna do yarn add and then the first one we're going to need is Axios and that's for doing HTTP requests and whatnot I like having lo - just in case we're going to need beautify and that is a material like framework or library to kind of style your components and build up your app and then two other helpful libraries I uses view X persisted State and that's so I can store my view X state into local storage and load it back when the roam tab opens up and the filing of UX router sync well that's going to go ahead and install all those dependencies and update my package JSON with those now that that's all done like I ran it in the wrong directory so let me just delete these why don't we go into the client directory and rerun that so to start off what I'm going to do is I'm going to open up the source folder and inside here we have a main JSO which is kind of where everything gets initialized and created for view it's also where you need to like include a lot of your dependencies and set them up so I'm going to do that with those dependencies we just Yarn installed so starting off I'm going to include import sink from view ex router or sink I'm going to import it beautify beautify let's see what else we might need I think that's kind of all we need for right now but what we can do is just include both of those or run them so they sync the store with the router view to use beautify you and I think that a good start winters complaining that you should come at the very top because they are actually packages and not from my local files like these are yeah so I'll do em p.m. run serve that's going to open up a browser and point it to your view webpage in just a second so here we go we have our view UI loaded and running and if we hit did everything right we should have those additional plugins like beautify and the view X router sync it's set up and just to verify that I'm going to go to my view plug in here so that's this is a chrome plugin that you can install or using view X and debugging up so as I change routes we should see our route change in our state if you see here we have our routes state here is at that slash a belt and before it was at slash this sink command is working fine a little bit more refactoring I like to put my store in a store folder so I'm gonna say store I'm going to copy that into there but I rename this to index of course if you do that make sure you include it here so instead of actually that should work as is so a little bit more setup I'm going to look at the store I'm going to include that persist state package that we brought in I'm going to say import create persisted state from view X persisted eight that we use it so to use that basically you just need to declare a plugins array for your store so down here I can say plugins an attribute which has a create persistent state object inside that array and save that let's see we're getting a error here something is still trying to load storage is and that's probably in my main [Music] is coming from there okay for whatever reason I need to do /index here typically be imported smart enough to just find the index file I'm not sure why I need to do that but hey we're gonna run into issues as we're making this UI so the more issues that I'd be plugged apparently the better it is for a tutorial so let's go ahead and actually get started on building out some functionality we did some initial setup some of it might have not made too much sense it's kind of boilerplate setup so really don't have to worry about it too much unless you're planning to do the exact same thing that I'm doing with this tutorial so starting off let's go ahead and try to start using beautify to build out some header or something like that at the top it's kind of nice to have a top header up here where we have things we can click so the first thing I'm going to do is just load up the beautify Docs so view 2phi go to their Doc's here we're going to be using this throughout our tutorial to kind of figure out what components we can use to build up our application so first off they say in order to set up your app with beautify you need to make sure that you have everything wrapped in a VF component an example down here it looks like this so if i just go back to my app view which is like the main part of this what I need to do is just inside my template I can say V app and then of course wrap everything in that at that point we should be okay and we're all gonna refactor all this second so since we did this setup let's just go ahead and come out what we have so now so all these files aren't just like green and kind of confusing so I'll say initial view set up go ahead and commit that go back to my tree view so let's get back on track kind of jumping around what we need to do here is we need to build out a beautify top navigation so that we can use it in our application so if we go back to the dock so let's look at the components that they have something called a toolbar Papa click toolbars give us some examples of the toolbars that they have how to use them so I'll click the code to get an example and basically I'm just going to copy and paste this into my app for now for all this stuff we can just kind of for now but we're probably going to get rid of it so if I save this file and go back to my view app notice that the styles are all messed up and that's mainly because I forgot to do an additional step in our setup which was I need to include the beautify CSS so if I go back to that main J's file you need to make sure that we import the beautify projects CSS so I'm going to do import beautify dist beautify that mend CSS go ahead and save this and we're going to run to an error because we haven't included actually this is just a linting error it'll let me go figure out how to fix this this is trailing spaces are not allowed we must have a trailing space somewhere which is right here so I'm going to go ahead and just remove that and save it so that loaded correctly if I go back to my app awesome we have the beautify CSS in the top now except for now the menu is messed up if you look to the example their toolbar has a little hamburger thing that you can click ours just says menu so another thing that we forgot to set up it'd be nice if like there's already project that kind of settle this stuff up for you but I guess there's not so do it by hand so what we need to do at this point is we need to go into the public file and I'm sure you can also import this in Maine but the way I did is I went to the public index.html file and in this file it's just a typical file that you know your app is going to be injected into but we want to include the material icons so if I go up here and just go ahead and just include that link through the material icon style sheet so this is the material icon that we need to include just go ahead and save this at hamburger menu should appear now and it does cool cool cool okay so making some slow and steady progress let's go ahead and try to modify this to customize it to be kind of something we want so first of all I don't want the hamburger menu for now and these links over here need to be something that's actually related to what we're building since we're building a to-do list application really all we need is like a register or logout button and maybe a button to see all your projects or something and then maybe also like a link to see this YouTube video once I host it so let's go back here and let's go to our app view those all these and then in here for our title I want to save you to do but and save that and just see that reflected here awesome I kind of want to add some color to this so I'm just going to say color is equal to green and I want to make it a dark attribute so that the text is white and then I want to say fixed so that it always stays on the top of my browser so you notice here as I scroll down it's still fixed to the top so awesome we have a view of you to do toolbar green fixed go ahead and get rid of that am burger icon I really want that is gone as we need to add a button so we can click our projects LV toolbar items that's going to be a class of hidden for small I should I'm not going to add any class of that buttons and stuff in a V tool bar toolbar items and inside here you add your buttons so say V button close that off and this button is going to say projects they make this one line say that cool so it looks kind of messed up but we're going to fix that in a second button if I were to say make that flat save that that's going to make it a flat button so it looks a little bit better and we also kind of want an icon so I'm going to do V icon you I want to put a playlist ad check economy let me just make this into a new line so let's read well so we have a button that says projects and it has a little icon to the left of it so people can understand that that's like your main view for seeing your projects and to-do list items one thing I want to fix really quick is this margin here that's needs to be added so what I'm going to do is I'm going to go to that title here and I was going to add a class of mr - 4 which means margin-right 4 and that's gonna push that button over to the right some so it looks a little bit cleaner and then later we can come along and add like routing here to the header if we need to but let's finish off with adding a couple of more so we're going to need a register button we're going to need a logout button again button you and I also want to include some icons on those I just like putting icons next to my buttons although I'm not sure if that's good UX or not so for register I'm going to say count box or login I want to do a fingerprint and then for a logout I want to say exit to app and then also I want to add a button that says how this was made just basically there's going to be a link to this YouTube video you awesome so we have a bunch of different buttons and of course as we go on we're gonna hide them show them depending on if the user was logged in or whatnot um one thing I do want to fix really quick is that all these buttons are really close to the text so I'm just gonna add a little bit of margin to all of these buttons here so wherever I see flat I'm just gonna say class of margin right of to save that and notice that all of our buttons actually I think I should have used them padding right so pr2 is a way to add padding the stuff mr2 is a way to add like margin of stuff okay edit it to the wrong stuff yeah my bad my bad I added it to the wrong thing I should have instead added it to the V icons here so if I describe both the icons and just do class of margin right too that she make it look a little bit better so sorry I'm kind of recording this early in the morning I'm still like trying to wake up and I make a lot of mistakes but hopefully I'm still explaining this decently okay so let's move on refactoring this a little bit because you see here this AB dot view file could potentially get pretty big right now I'm already hitting like 30 lines and it's good to kind of D couple your components so it's easier to understand so it would make sense to pull this out into a separate component right because these buttons down here like when we have our content the router view doesn't need to know about the toolbar header so to do that what I'm going to do is I'm gonna first copy and paste this in fact I'm gonna cut it and I'm going to make a new component called bull bar and then I'm gonna scaffold that out and I'm gonna paste that HTML inside of that template you go ahead and save that and then in my app dot view I could just include that toolbar after I import it so here I'm going to go ahead and add a script JavaScript and then I'm going to import you created at slash components slash bullbar vu then in here we want to simply do components and that's going to be an object with the name of our component you my hair says we're missing a semicolon so let's go ahead and : make sure my linting is all working trailing space inside of my HTML so let's fix that really you a missing michael bars in extent okay so all of those are passing now so the last part or step I need to do is once I've imported that toolbar into my app table view you just go up here and simply do the toolbar notice here the toolbar is still displaying if I were to go back to my code and just comment that out to demonstrate the toolbar will disappear all right so the next component a review I want to work on is going to be their register view so that we can actually register users so let's go ahead and get started on that if we go to our toolbar notice that we had a register button if we wanted that to actually do something when we clicked it you could simply add the property to and pass it the URL we want to redirect the user to when they click on the button so I'm going to say to slash register at this point we don't have a register view or route created I'm gonna go my router Nijs file and I'm gonna create one let's go ahead and copy and paste what's there already make this register you register component and again we don't have a register component created so what we need to do is pretend like we have one created in our views folder and I will go here and just go ahead and create a new register dot view file inside of this and go ahead and scaffold that up well so now at this point actually I'm just going to say I'll make this h1 I'm gonna say register just make sure that we can view something but if I go back to my UI I should be able to click on that register and the top nav it's going to redirect us to that register view case it's not let's kind of investigate what's going on [Music] you going back to the toolbar and it's because I put it on the wrong element I should have put it on the button not the V icon so that's my bad let me go back here at it to V button go back register now and notice that it redirects us to a slot register in point you anyway so now that we have the register in point a register route let's go ahead and add a couple things to that view such as you know a login button a user name they can enter in a password form so we don't need the toolbar at this point we're done with the router done with app so inside the register component what we need to do is let's go ahead and make this a if for now we can come back and change that to probably like something that's more layout specific and we need to create let's say a title of h1 so it's going to say register and then we're going to need a input box and using beautify there's one called B text field some say B text field and the properties that you can pass the V text field include the label I'm going to say email and to say the value so we'll leave that blank for now I'm just a label email placeholder equals email and we'll come back in a second and add actual other values to it and of course we need one for password this is going to be a type of password and when I made I'm gonna make it autocomplete equals false are actually equals new password so that Chrome doesn't automatically fill it in with stuff so we have two text fields wave email and password here and then we also need like a register button I'm gonna add a B button and in that be button what we can do is give it a color so I'm gonna say color green I'm going to give it dark so that the text is white inside here we can say register you go ahead and give it an icon since I like to give icons next my buttons so a good icon that we could use here includes a account icon so let's do a count circle save that go back we have a register button here now I so we're making some progress one thing I'll notice is that no I don't want this to expand the entire page with if we were to go back to our component instead of using a div let's do an actual container so I'll say B container and then make sure we update the closing element and then inside the container you can do a B layout rowrr app and again these are just beautify built-in components for layout container I have a layout saying that everything should be in a row and then I'm saying inside that row I want the road to be with of six on a small and then push everything to the right by 3 I'll explain that one second so let me say that and now notice here you have everything kind of centered here so basically we go back to these attributes I told it to give it a width of six basically it's going to divide your page into twelve different columns I'm saying this is going to be six columns of width and then I want to push it over three columns so this is column one two three starts at comma four with the six and then we have column seven eight nine ten eleven twelve you utilize that here if I go and look at this we have a the six columns here and then were pushed over a three if you notice the three is adding a padding right here this should allow us to when we resize the page still going to stay in the center what kind of gives us the benefit of responsive websites without having to do much work but we're not focusing on making a responsive website so let's keep on moving on and try to implement the actual registration login functionality full so now we're getting into the actual logic of this registration page and we need to first start figuring out how to bind stuff to view X so for anyone who's not really familiar with the UX basically it's a place where you have all of your application logic stored in a single place and then your components are going to update that state and fire off actions and mutations to change the state I guess the benefit of that is it's very easy to understand like where all your application is like how does your application change over time well it kind of debug and show you how useful that is in a second but again let's just implement it I'll kind of explain it along the way so we need to first of all go into our store and let's make a new file called authentication be named whatever you want does really matter inside that authentication file we want to export a new object which is going to be like a store module so I'm going to say this is gonna be namespace to true state in here is gonna have some things we can kind of add on to it in a second and before we start adding on to this let's go ahead and make sure that we include that module here in our main store so up here you're able to do modules and include a list of modules here so I want to include a authentication module which of course we have an importer yet some say import Asian from authentication that's basically going to hole in this default object here and put it directly into my modules object here so then I'll be able to access it with my mutations and actions and setters and stuff from my view components again this probably won't make sense until we start using it so just a recap we made a module and we include it in our store so let's go back to our module what do we actually need to store interstate so if we were to look at a register component basically we need to store when they update their email that they're about to submit when they update their password I so two things that we know that we need to keep track of so let's keep track of a register email and beam all by default in register S word that's also in beam all so in order to kind of bind these to change these we need to first make a couple of mutations so if I go here I'm going to add another property called mutations and inside this mutations property we can just define different functions that it will affect our state here so I'm going to say set register email that's going to stake or take a state and also a an email as a payload and then we need the same thing for set register password the state thought register email is email same thing here register password is equal to password you I think this is because um we spun this up using Airbnb easiest excellent and they typically use react but we need to actually be able to do this so let's go to IES Lind file [Music] and let's add some rules so I'm gonna say rules the one that's giving us issues is no pram reassign and I'm going to turn that off for now so that we don't get that error and unfortunately when you change that Uslan file you have to rerun your serve command I think there's a couple of other ones you might a couple of other rules we might add and disable mainly because you know everyone has their own opinions of how their code should look and I have my own or so let's let that reload here well so a little recap we have two properties on our authentication module state called a register email and register password and then we have two mutations which we can use to change those so with that being said how do we actually bind our view component to change those if we go back to our register view file what we need to do is first import our a couple of helper functions from view X so I'm first going to do import map state and I'm going to do map mutations from Buicks and to use these basically you just kind of decorate your component object with following these functions so for an example if we wanted the ability to call set password or set registration email or one of these we need to map the mutations to our object so I'll just say map mutations actually first of all I need to bind that to a method so I'm gonna say methods is an object and then I want to map some mutations to that that's function where I can pass it the module name so I'll think tation and then I pass it the methods I actually wanted to app so this is the first function that we want to map and this is the second function we so basically all this is doing is saying that this component is going to have these two methods that I can call so up here I can call those like whenever I click on register or whenever I change text in here I can simply just call those methods here and then also what we want to do is we want to grab in our computed state values here so that we can set a register email password when that view loads so up here I'm going to say computed which is another property you can use on your view component instead of map mutations I'm going to say map state again pass it the module name we want to map and then pass it our state that we want to map in in this case I'm going to say register email and register password you all right so if everything worked well I should be able to start using these so the first thing I want to do is I want to go up here and I want to bind the value of my text fields to its corresponding state value so I'm gonna say value is equal to register email you - buying this text field - whatever the state value is down here and I wanted the same thing for a register password so I'm gonna go down here and say bind this to register password and let's just demonstrate what we are actually doing here so if I go back to this view the register view notice that email and password are not set to anything and that's because in our state I go to the authentication module actually clear on my localstorage I think it has stuff okay so in our thent ocation module we have a register email and register password state and those are both null but if I come back to here and say hello and this changes the world and save this notice that when this page refreshes I think it's because I'm using : one second that kind of show you what I'm doing I need to actually disable this plug-in because this is trying to load my state from the store which is not what we want to do to be able to demonstrate this sometimes I hate me it's Lent there we go sorry about that basically I change this to initial state of these two properties to be hello world and notice that our inputs are set to those now I'm gonna keep this plugin disabled for right now so it doesn't cause more issues back into enable in a second so again if I change the and a do to the end of it when this page loads this input is going to fetch that value from the store and just populate it so that's kind of the first step we bound these text fields to the state now the second part is we need to bind what happens when we input into this in update our store so if I do at input so basically whenever someone changed the values of this text field is just call set register email down here and then same thing for the password let's say set register password so now when I type you'll notice that it's firing off a view X mutation down here authentication slash set register email and as that's changing it's updating our state but and another cool thing I can show is we can travel back in time to all the different values of our state so if I wanted to go back to my app first loaded notice that it's going to load my initial store values here and that's reflected in our UI and that kind of I can kind of step through what happened over time with my component and this is really useful for debugging and understanding what's going on with your application let's go back to our code and try to figure out what else is remaining so we had the ability to type into the email and password we're updating our store with the corresponding values now what we want to do is when the user clicks register we want to fire off a view X action to kind of hit that register in point we're created on our previous tutorial section so on this button I'm going to add an @ click call back register method which we have an included yet so if I go down here now and just pretend that the authentication has a register action we say map actions identification bring in that register action and of course we are missing this so we need to put it up here if we go back to our authentication module we need to just simply add in actions and say register is going to take um [Music] his register need there do object construction and just grab the commit function and also grab the state so now we're getting into doing actual HTTP requests to our server which is running so in this particular case we want to grab the register email and password and we want to do a post request to our register endpoint so before we get too far ahead of ourselves I want to make a new component called HTTP ijs so I'm going to do HTTP j/s and inside here we're going to export a function which is going to return a new Axios object so I'm saying co-create and we haven't included that so let's just do that really quick we also probably want the store because I'm going to put the base URL in the store you and before we go further with implementing this go to our store and just add a a Cu RL and set that equal to API I think I should slash API so in this HTTP file we're going to create an access object and we're going to set the base URL let me say base URL is equal to store dot state base URL you and then we want to say give it a timeout of like one second so if request doesn't finish in a second time it out hmm and that should be good for right now should we had our semicolons this is another one I do not like so I'm going to disable that style I go back to my es Lintz just get rid of that make sure you reset that you can now go into our authentication action that we're trying to create import this HTTP function so if we can create an Axios module so up here I'm going to import HTTP from HTTP now we have the ability to call that function so here I'm just gonna say returned HTTP POST the reason we can call that post is because on this Axios object it has different methods such as get post patch put delete stuff like that and we want to make a post request to our auth slash register in point and then we need to pass it some data in the body payload I'm going to say email is equal to state dot register email and then password is equal to state that register password I'm going to make it so the moment we call this action I just want to reset my username and password back to but it was so I'm gonna say commit set registration actually um we need commit at this point so let me just save that show you what happens when we run this method so remember we already bound this register button to make send off an action event so if I click it or actually getting an error now so let's see those localhost:8080 /ss register is not found in the main issue here is if you remember we are hosting our API import 3 333 this is trying to make a request to e2 80 another cool thing you can do is we just want to pretend that the API and the UI are going to be hosted on the same port same domain under a proxy so if we go back to our main folder where we have our client folder I can make a new file called view dock config is an inside here if I just export an object that has dev server has a property and I tell it to proxy slash API I can give it a target until a to point to my adonis server on port 3 3 3 3 goes off all the and I think I might need to restart my server this is basically just doing a proxy whenever I do a request to slash API it's going to point to a different port on this machine and you config dodge is is automatically kind of loaded in we are using the view CLI so let's go back to our UI when that refreshes let's click the register button again you to register here so if you see here we try to make a request to 8080 slash a P I such office' register the request payload is this hello yo password is world and the server did not respond within a second but let's just see if that was a fluke and it doesn't seem like it was so let's look at her server maybe her server is actually crashing for some reason let me go to my server folder and go to my controller or I'm trying to register and let me just make sure I'm hitting this so say console dot log hello world you so we are hitting this end point I think it's just taking a little bit longer than a second to register our user so let's go back to our HTTP change this time out to five seconds instead and let's try to hit at end point again you and we're getting the error I guess saying that the user already exists and it does I'll do hello with an exclamation mark try to register that user instead [Music] okay this one actually works so we got back that token which we're gonna need the store in our store at some point but right now you saw there's no cuz I'm feedback for the user when we registered and what we want to do is a store the token in the store and then we want to redirect the user to a different view go back to this get rid of the hello world and just start that hmm go back to review CLI Oh some these files okay so first thing we wanted to do is we said we wanted to store the token inside the store so if I do a dot then you can grab data that's returned from the Axios request and then inside this data we could simply do commit set token data token of course we don't have a commit our mutation called set token so let's add one will say set token we get the state we get to token and we need to set state that token is equal to token and we also don't have a token define our state so let's go up here and say token is equal to null and also let's make sure we include commits up here so we can run the command so let's try this see what happens if we were to register with a new user that we haven't done before a click register notice that it fires off the set token mutation and now in our state we have a token set so that's step one step two is we need to change our router location so we need to first import that router so import router from dot dot slash router just to import this file here and then if you want to dynamically change the route that wrong we do router dot push I'm going to say go to the route let's try registering with yet another one so I'll just say hello click register and notice that it redirected us when we successfully logged in so a couple of other things we want to do is what if there was a login error right what if the user tried to log in and it was incorrect so we should probably display some sort of registration error on this page so to do that we're going to need yet another store variable called a register error maybe know by default we want a mutation to be able to set register error you you and then in a registered IBEW file we want to add a new alert probably add it right above the register button so I'll say be alert and that component and I'm gonna give it a couple of properties so I give it type of error and I want to give it a value of error I shall say register error so basically if register error is defined it should show up this alert and notice register error we haven't brought in so we need to go back down here to methods and make sure we map the state here I'm going to map the register error states and I also want to just go ahead and say actually we don't need to map any mutations here so right now that's not going to show up regardless because we don't have a way to actually check or we don't have anything setting register error so let's go back to our action and what we want to do in our action is if there is some type of error so if I do dot catch I want to the register error isms they commit that register error I want to say invalid registration formation and of course you can get more specific I think you could probably catch the actual error and do something with it actually instead I'm gonna say an error has occurred of trying you all righty so fully this works if we go back and try to register this exact same user that should already exist in the database you get an error back and right now the error is not displaying anything so to debug this let's look we sent off a mutation to set register error that changed our authentication modules register error store State or whatever is called state to a string before whatever reason we're not displaying that in our alert oh this is because I forgot to actually render the X so if you read through the beautified docks alert this value is just going to display it if this is true or defined and then not display it if it's false but you actually need to render something inside here so make sure you do the mustache and it'll bar stuff to register to display your text cool so now says an error has occurred trying to create your account if I try to create it again with something that doesn't have an error it's going to redirect us and then one thing I'm going to do is every time we try to register I'm just going to commit null by reset that back to nothing from our registration error well so I think we're like most of being done if not we are done with this register view I think the last thing I want to do is once you're registered I want to hide a couple of these things in the top toolbar and if you're not logged in I want to show them so let's add something new that we haven't seen yet called a get er to our authentication module so I'm going to say get errs and it'd be another property and inside here I'm gonna say is logged in as a function takes the state I believe and what we're going to do here is basically just return true or false depending on if the token set so if the token is set is gonna be true or logged in if it's not it's going to be false and now that we've done that we can actually go back to our full bar component and hide these different buttons toupee on April logged in or not so let's go ahead and import on that map hitters function so it's a import object each instruction of math and getters from view X and here I'm going to say computed is equal to map getters of the authentication module and then I want to say is logged in you so that will basically grab us that getter function and we can call it up here to display and hide different things so if we are logged in we want to display logout maybe if we are logged in you this should always be displayed register and login should not be displayed so I'm gonna go ahead and just hide those two buttons there say if we're not logged in you can display those you up here we probably only wanted to splay this if we're logged in so let's go ahead and save that and see what happens all right so right now token is null so we're not logged in but if I were to register with something new such as like hello world 999 when we log in we now get that projects button to show up we get that logout button the show up alright so let's go ahead and commit what we have for now and then move on so since we're here messing with the toolbar let's just go ahead and make the logout button actually log us out so what is logging out basically in our sense of our application is just going to be setting that token to null right so if we go back to our tent ocation remember we have a set token mutation which we can call so if I just go to the toolbar I want to make sure I'm at that mutation I'll say methods is equal to a patient's acid pass it that function that we want to be able to use you and then now that we have that function could simply go up here to logout and if we click that button I want to set token to null so if you go back here it refresh the page okay so notice here when I click log out register went away or sorry the project's button went away and the logout button went away now our show to register and login and we can also check the store notice that token is set to null now I think what we also want to do though is we want to redirect the user to the login page whenever we click logout so maybe instead of mapping a mutation we could either create an action or we could just create e a logout functionality here so I think it'd be better to just create an action called logout so if we go back to authentication make a new action called logout that only needs a commit basically we need the same thing so commit set token to null and then we needed a router dot push slash login I don't think we have a route for login yet but we will create that in a second but going back to the toolbar instead of doing map mutations I'm going to say map actions and I'm going to bring out the logout action I'm just going to call log out here so let's just make some user and log them in and now that we click logout it should redirect us to login which we don't have a really of you created for that yet but we can do that in a second well so what we haven't implemented yet is the ability for a user to login so let's go ahead and try to do that now let's go back to our just commit log out here it to further if I go to my view I'm gonna make a new component called login and I'm just going to copy and paste from register because it's gonna be basically the same thing with different mutations and actions oops login so copies the register component and made a login view here if I go to router let's go ahead and make a a login route and inside the login route let's just do login here this is all showing up all right so now we have login instead of register for the button we need to say login so I'm gonna go down here to the button to say fingerprint I say login see that and that's good to go um instead of register error I'm gonna rename all everywhere I see register to login so actually suited me a me um just do this manually I don't mess up the realization hmm so register should become log in register should become login [Music] all right so none of these states mutations or actions that actually exists on the authentication so let's go ahead and add those to so I'm going to say set a register email password in email or error and say login hmm actions instead of a register action we also need a login action sets login error you know login you same functionality basically in fact we could probably abstract this to a function since this is very very similar but to keep it simple I'm just going to repeat myself you notice here the same same method we're basically changing the URL and we're changing the error and the parameters that we're sitting in so we could just make a helper function up here that does a kind of shared code between register and login but that's another abstraction which kind of makes stuff a little bit harder to understand we just want to quickly look at code so let's not worry about that right now so again we have a login action which should work now it tries to log into that login endpoint with the login email login password there's an error will display and the alert if not we're going to push the token or set the token and then we redirect to the home page and now we just need the mutations for those three store and values that we added so I'm gonna say sets set login and then here I'm just going to say state login all right so let's see if this works so first I'm I'm gonna make testing at gmail.com password 1 2 3 4 5 6 I'm gonna register and this failed because I think that user Ortiz sure does so I'll do testing one then just for that I'm going to log out and make sure that login works as this was testing one but a log in with that same username and password and at worked as well awesome so we have register and we have login working we have logout working we're hiding and showing different buttons based on the token being set um let's go ahead and what we have for this login functionality and then we can move on to something else so let's move on to actually displaying the ability to like add projects and add tasks and stuff like that so the first thing we need to start out with is kind of like a projects panel so if we go to the main view here or home view this is kind of what we're looking at right here so I'm going to actually rename this to projects and in my router I'm just going to go ahead and change that to well instead of home I'm going to say projects I'm gonna change that the projects projects go ahead and get rid of all this stuff back in it or stuff in in a second you all right so on this project page the first thing I want to kind of display is a panel on the left the title that says projects and then inside that panel I want to display a list of my projects and then an input box at the bottom so we can create a new project so first thing is the whole idea of a panel is something that we're going to be using throughout the application so if we go to our components folder and just make a new one called panel that view go ahead and scaffold that out you all I want to do here is I'm going to make a if give us some classes which are kind of pre built in to beautify so I'm gonna say white right I'm say white and elevation of two and that's just going to make a raised white panel and inside that raised white panel or card I mean I want to declare a toolbar make sure that it is flat I'm gonna say dents I'm gonna say dark and I'm gonna say color of then inside that toolbar I want to say be little bar title it's going to be equal to whatever the user passed in a property so I'm gonna say title is something that a user can pass into this component and down here of course we're going to need props I say title is going to be a string and inside the title actually I think that's good enough for the title underneath the tool bar what we want to do is create something called a slot so I'm going to say div class of time left for padding right for heading top of to padding bottom of two and inside of that div I'm just going to add a slot no one passes anything MSA knows lock on mind all right so now we have a panel which we can kind of use throughout our application and then of course we need to define it as a global I'm going to say here I'm going to say view component own int dot annal is equal to panel and of course make sure you bring that in and all bring that in that view you so almost done in the projects out view file now we could just simply do panel here and I'm going to pass it title is equal to projects so now when we save this we should see a panel that is defined here so we have projects here with no slot content defined and if we wanted to make something render here we just simply pass it in here so I'm going to say each one esteem you notice that that title will then render here and we can render Road whatever we want inside of this you well so we made a shared component or a global component called panel which we can use throughout our application um let's go ahead and do some layout here so that's not right next to the side of it so instead of using a div home I'm just going to do a V container so V container BAM I'm going to leave that out for now back in the container we want to be layout you laya of course we want AV flex and this flex is going to be I'm going to say small of four so it's going to be four columns and then inside there I'm going to put our panel all right so now we have a panel to the left called projects and let's just go ahead and create one for now just so we kinda have a better visualization of what we're doing on the right so 8 plus 4 is 12 and this one is going to be called tasks projects and tasks you awesome and let's just add a little bit of padding to that glass is evil Oh again what I said we're doing is we're just going to render out a text field here where we can add a new project and then we're going to need to render out a list of those projects mmm so before we get too ahead of ourselves let's make a new component called projects view you it might be a little confusing because we have a vehicle projects and we have a component called projects so I need to rename this the project view or something but I'll just I'll keep it as is and see how confusing it is so inside here let's just go ahead and import projects from you that Onan slash projects dot view [Music] I'll say components is equal to projects and go ahead and just instead of doing this panel here I'm going to just render that projects thing we're going to start defining and then I'll put the panel inside the projects you see intere because it does not sound like all right so now we have this kind of refactor so it's just is simply going to be projects and this will probably just say tasks in a bit and in our projects panel what we want to do is we want to list out text field so can create or we can create a record right here I'm going to say textfield and we just want to kind of like allow the user to type in the new name of their project so I'm gonna say C leaseholder is going to be I project need not save this and make sure everything is correctly alright so we have a text field called my project name and then we also need like a Smit button so I'm gonna say B button you going to have a create on it in fact let's just do a little bit of flex grid stuff so we can lay it out okay I'm going to say inside here it's going to be the B layout and of course we need to be flexible wrap you this is basically so we can have a button on the right feel on them so just do this put the text field in the v8 a small eight the button well of course I like adding icons to my button so let's just add a V icon here you it adds circle leave that awesome and of course we should do a little bit of margin right [Music] and we can fix the style and stuff in a second so let's see the button it probably also be color of green let's give it a virgin top of two [Music] it just moves down a little bit let's give it dark and see what happened all right so we have a crate button now that looks a little bit nicer it's a little bit down further line up with this [Music] so similar to what we did at the login and register we need to listen to when the keys change on the text field and then update the store and of course we also need to set the value to something that's coming from that store so if I were to go back to my store let's just assume that we have another module called Project CAS just to simply copy and paste what we have here you you I mean needing to reuse that like HTTP stuff so let's just do actions ITER's State and stuff so we're just good to go now and of course in the main index on Jays file we need to include that so let's include that projects module here and now we should be able to use that in our view application so first thing is I'm going to create something in our state called new project aim gonna be null and then I need a new mutation to set that new project name that's going to be state and named Oh state that new project name is able to name so then here of course we need to bind value I'm going to be new project name we need to make sure we include those who import map mutations app state from UX we're gonna say map state projects now because we're using the projects module and we need a new project and then for methods you mutations set new project name you again when we do inputs we just need to pass set new project name ISIL is verify that this is working as expected so I'm gonna type hello that's sending off the mutations for set project name and we're seeing that update get reflected here in the view X state so I guess the last step is we just need to send off in action to the backend to actually create this project name once we click that submit button so if we go back to the projects module alright so let me just copy and paste one of the actions here that we have a good starting point I'm going to say create project commit a state that's going to do an HTTP request to projects it's going to a post request and then we're going to pass the title the state dot new project name in fact I probably should call that new project title so let us be refactor that but anyway once that's successful what we're going to do is you're just going to MIT end project ADA let's not worry about errors right now and then we'd have a projects array here we should probably loop over at some point so what we need to do is in the mutations make a new one called project I'm going to say eight dot project stop push project so we can keep track of the new projects we create and then of course we need to set the project knee successful to go back to also set new project name say null so I think we're almost done with this but the only thing we're missing is the hole header if I go back to HTTP here I need to make sure I add a header so I'm gonna say headers is equal to authorization that's gonna be bearer I grab from the store be token from that authentication module that we have hmm all right so we did a lot of stuff let's just check to see what errors we may have so I type in a new product name called hello world and then when I click create we forgot to bind the create project go back here in for map actions we need to make sure we include that method click this just need to make sure we call it let's try again create sending-off and request to API slash projects rating a 401 unauthorized let's look at the network tab and see what's going on here and saying my JWT is malformed you so let's look at the headers and for some reason the token is not on the headers so let's go back to http that I maybe spell something headers authorization error date ostentation hmm maybe it's just gonna refresh the page correctly so let me just do a hard refresh here hello world like create you oh okay so the issue is is we're not even logged in so I don't think we should be showing this view if we're not logged in so there may be a different way and I'll probably look this up to see if there's a different way to redirect but we try to hit the projects page here are the project view without being logged in Gosei mounted is a function and then when we're mounted just check to see if the token we don't have so I need to do computed app state indication actually no map eaters is fogged in [Music] so if we're not logged in go ahead and redirect to the login page you map inners is not defined ever have to import it so after Gators from the UX what happens here all right so now it's gonna make me a log in every time I type hello world here now great that going to app in the project so now I have a project so right here it created the project successfully in our back-end the only thing we need to do now is just kind of display it in a list let's visualize that really quickly inside of my projects panel up here I'm just going to creative I'm just going to loop over my project so v4 project in projects and make sure you map the project state some state projects we could simply just render out the project title here if we want it to oh I need to be bind is going to be project like to return that one I don't like this insolent so I'm going to just plus one let's read set to my serve you [Music] see absolutely abortion before sandy at the top it's only logged get login now my awesome project my clique creates notice that the project is now rendered because we did a b4 so I'm making some progress let me just go ahead and commit what we have and we I can create more logic in a second you so the next thing we want to do is when the projects component is mounted we want to fetch all the projects that the user has and just render it in this list here because if I were to not restart this page or refresh this page and log back in notice that we did create projects on that user but there's nothing that's showing up so let's move back to that project stop view file and let's also open up the project store in let's create a new action called fetch projects Big D can take the commit function in the state and what we're gonna do here is just return and the same thing that we did before on second all right so we're gonna do an HTTP method so we create that object and we're gonna do a get request on projects and of course we don't need to pass it any parameters so it should just return everything that is attached step projects and once we get our project data back actually we don't need state here we're gonna do a new commit called set projects and the back ends going to return an array so data is going to be an array of projects already so if we're doing a commit action we need to make sure we create that mutation I'm going to go down here and say is that project state projects and then I'm just going to simply overwrite state thought projects is equal to projects as an empty right here so we should be good to go we save this and now we should be able to map those actions and call that when our projects on it is melted you so let's go to our projects component since I'm in the project view right now and what we want to do is when this component is mounted we are going to fish the projects so I simply just need to go up here at a mounted function call to say this dot fish projects as simple as that it's going to run that action which is going to commit that projects data and we should see that reflected so I'm going to log in we see that it called set projects here which the pale turned was an array of two projects so Jaques is set on the state here so projects and then inside projects we have another attribute called projects might be a little confusing but hey it works and then you see that those are rendered up here and we can also go to our network tab and see that we made a request to our projects endpoint at API slash projects look at the response and we have two projects returned so pretty straightforward as to how to fetch projects and how to create projects now the two other pieces of functionality we kind of need for projects is we need to be able to edit this title and we need to be able to delete the project so what I'm going to do is I'm going to try to add a button here which is like a pencil button and when you click it it's going to make this become a text field so that we can edit it as needed so let's go back to our project stop view file and find where we are rendering that project title which is here on line seven hmmm so instead of rendering bat let's just go ahead and make an icon is going to be a pencil we'll find out in a second I have to do a little bit of layout /v flex to get this to work out correctly in fact I should say edit not pencil so save that we have pencils next to our text now which is step in the right direction we want to make sure that the layout is set up correctly so let's just go ahead and do a V layout here you and in heroes do we flex and we want this to be analyst to say if you fix a nine and the rest could be a three let's make the title be on the left and we can make that edit button be on the right you mmm okay so making some progress let's align the text to the left so on the the Flex here I can say class let's say text X X s left and that's a built in class for beautified to kind of align stuff to the left all of my text will be aligned to the left now I just add a little bit of margin to the bottom of these so let's see each div I'm into a class of margin bottom of to see if that's enough looks a little bit better and of course I'm going to say that this is a project down here I'm going to make a new style I'll dot project and that's going to say margin art that's going to be font size of 18 pixels see that's big enough it's okay be something bigger like 24 and then I think I want to add a little bit of space above this so if we go to the panel I'm going to say class is adding top of four and see if that pushes it down but then on the wrong thing you so I'm just going to do margin-top of you here instead there we go that looks a little and then this is going to give it a little bit of margin too the margin top of four just to push that whole thing down get a little bit of space all right so again what we're trying to do is when we click on this edit button we want to change this to a V text field so that we can edit the hello world project title so if I go back to where we are rendering that title out here hmm we're gonna kind of have two things that need to interchange depending on if the project is an edit mode or if it's not in edit mode you so let's just pretend that project has an is edit mode boolean so I'm gonna do a span and say B if project dot is edit mode we're going to display something which is going to be the project title otherwise we're going to display a V text field e text field again we do the opposite of that and you probably use a switch case as well I think you has a switch case support so I say if it's not in edit mode we're simply not going to display the text field you okay then inside this text field we're going to do value is going to be equal to project on title back to this save this and make sure this is displaying correctly of and extra space you I think I have these swaps so that needs to be if it is edit mode in this if it's not- mode hmm okay so you saw it was displaying a textfield before and that was just because I had the boolean swapped so now if I click on this icon what we want to do is change the project's is edit mode boolean to true down here for the button I'm going to say at click that edit mode and pass it the project here you so let's go and actually ten like we have a mutation that we can call so here we're gonna map mutations and call set edit mode and that needs to be true actually so wherever I called set edit mode let's just say that's going to be a value of true I always keep like that so set edit mode and if I go to projects and go to my mutations let's just add another one called set edit mode state and that's going to be project then inside here we're going to do project dot is edit mode is equaled you let's see if that actually changes our state as we click things like this the edit mode is set down here and his MANET mode is edit mode is set to true and the issue that we're having here is nothing is being reflected in our state and that's because is edit mode doesn't actually exist on the project so this is kind of a nuance in regards to using view where the UI is only going to bind the stuff that actually exists so what we need to do instead is if we go back instead of doing project on is edit mode true we need the first import view you and then down here instead of just doing this we need to save you a set project is edit mode and then we need the passage through in the make sure that it binds correctly to that boolean once we set it but oh this music of all right so if I go back look this notice that it changes to the text field and right now we don't have a way to go back because we don't have like a cancel button or a check button so let's kind of add that so let's go back to our project stop view and I'm going to add a check down here you the same same ideas gonna have a check icon when you click it it's gonna call unset edit mode so we're going to assume that we have an unset at it mode we're going to go to our down here and at this point it's probably safe to assume that edit mode is defined on the project because it can't be true unless you set it so I should be able to do project out is that it Modi's equal to false but just in case let's just keep it as is like this go back we should have a checkbox that shows up of course we need to probably do a B if to display it and hide it anything so if I click on it B pencil but going to edit mode if I click on the check it goes back to non edit mode let's make sure we toggle those correctly going back here let's find that check icon I created and I'm gonna say V if project dot is edit mode its false and then for this one the edit mode is true we want to display a check so now we can toggle between them pretty awesome so let's go down to the style and let's just do I think we want to make it so when we hover over this we have a cursor so is this actually old class of icons so if we go to our style and say icon cursor is a pointer just so we get some feedback as a user when we hover over stuff we probably also want to say icon hover background actually has to be color of make it gray I guess short color was before so now it's a little bit darker when we hover over it oh so we're kind of getting closer to implementing this edit functionality so now if we were to change the value of hello world to what is up of them like that notice that nothing changes because we haven't actually bound to the input call back on the project edit so we need to go back and go here and say add a new mutation called set project title state project actually this is going to be a message so I'm gonna say project title and then project that title is equal to title mutation we can set the title and if we go back to our projects view we again need to make sure we grab that mutation so I'm going to go ahead and grab that set project title from the project's module and then when we change the value of this let me say at input I want to go ahead and just call set project title I want to pass it the event I don't know if I need to do this let me just try this so set project title and then take a object object is going to have the project so I'm gonna say project and then also the title is going to be equal to the event you you I think I'm I'm beginning some type of air Lindt air or something this is not single lime you oh you know what I'm doing wrong I have I'm updating the wrong thing hold on inputs declared twice on this I'm updating the wrong text field so if I go up here to the text field we're supposed to be updating let me just add input to that so now we're calling set project title with the project and then the event which is going to be in the text we may need to verify this in a second but let's see what happens if we run this so login and I'm going to go ahead and try to edit this by adding an exclamation mark it dispatched that mutation and we have the payload we have the project and we also have a new title that we want change it to then if I go into my projects array notice that the corresponding project has the exclamation mark so we're now we're we are reflecting the value of the title successfully the last part is when we check click the check box we want to actually persist so if I go back to that check box here instead of saying unset edit mode I'm just going to say save project you let's go back and pretend like there's an action I'll save edit mode for now now let's just be explicit and call a save project then go back to our actions or our projects module and create an action called say project basically what we want to do is just send off a at request to the endpoint that we have so I miss HTTP catch on projects slash project on ID and then this needs to be string interpolation so we can use back ticks okay there you go then of course we need to pass the project that we're trying to save and that should hit the can save and actually persist the project project state to the back end and when we get a response back hush for at this point we really need to do much so we just let's just delete that for now commit what we want to do is actually yes so if I say if successfully what we're going to do is we're going to commit and say unset edit load project all right so it's gonna persist it if it was successfully persisted to the back end we then just just say or unset it from edit mode so it's going back to the normal view let's try doing this and see what happens so I'm going to go to the check pencil add a couple of exclamation marks and click the check box notice that it went back to the normal view instead of the edit mode and they made a network request to project / - we sent the payload of title hello world blah blah blah and we got a response back of the new object so now when i refresh the page and log back in notice that we have that item our that title persistent now well so we're making some good progress we have the ability to create new projects we have the ability to edit projects one thing that we don't have is when I click this edit button it doesn't focus on this automatically so a cool little attribute we can add two V text field is auto focus so let me go and say auto focus here so now whenever we click on that it should automatically focus on there and it did mm-hmm what we also want to do is if we press ENTER on our keyboard it would be nice if it just does that save thing for us you so let's go to text field we're going to say key up enter but basically if the user were to have a key up event on the inner we're just going to say save project and pass it project and this is basically doing the same thing as clicking the check button let's save that and see if that works I'm gonna click a pencil add something click enter notice that that got persisted to Project number three now all right so now we're kind of on the last basically we need to be able to delete a project from that list so you know the drill basically we're gonna have to have a new action called delete project so I'm just gonna copy and paste this all delete project it's going to take a project it's going to make a delete request to project slash ID we don't need the past data then once the project is successfully deleted we want to remove project from our list so we're going to need a new mutation down here I'll remove project and that's just going to splice out the project from the list so I'm gonna say state that projects not splice state that projects dot index of project and then one and this is how you to remove something from an array so just going to find the index where this one exists and just splice it from the array you you so now in order to use that action let's go back to our view component let's go ahead and bring that in and let's go ahead and make a new button our new icon which is going to be a delete icon and we're going to be calling the leap project when we click it so here I'm gonna say delete we only want to show it when we are in edit mode and want to call delete project on that if I go ahead and save that log back in let's see let's click on actually we want to show it all the time I think they've seen me completely so now we always have that trashcan that we when we click it's just going to delete it we go to the network tab notice that made a delete request who project to and if I were to refresh and log back in that project has been deleted from the list and delete everything and see what works one thing I also notice is when I press ENTER on this text field that it does not create the project so let's go ahead and try to implement that as well so very similar to before when we click on create or you enter we want to write the project so here in the text field when we do a key up we just want to say create project give it that function go ahead and save this go back and now when I press ENTER on my keyboard it's going to create it for us what remain a lot of progress let's go ahead and commit what we have this is going to be called editing elite projects all right so before we move on to this tasks panel I want to go ahead and abstract some things that we can reuse components because task is basically going to be very similar to this projects panel so first thing I want to abstract is this bottom create thing or section that we have I want to have a component which has a gray button where I can change this text dynamically through a prop and of course invoke different callback functions depending on what we want so let's start with this right here so if we go back to our project site view file notice that this bottom section here we want this is what we want to kind of abstract into a separate component so down here I'm gonna say a new file called create record view go ahead and scaffold that up and that same layout of code that we had other file and let me just go ahead and that doesn't even just here so say great record you make sure we have the components components and of course we need to import that so you okay so if we wanted to abstract this into a different class basically we just wanted to allow the props to be passed in for setting like placeholder text and we want to emit certain events when things changed so the first thing I can do here or placeholder I'm just going to say this will be placeholder so up here x8 props we have lace holder and then inside projects we just simply pass you place holder is equal whatever I just copied out let's see this was I project is odd or something like that this so this probably won't actually work out of the box as there's gonna be errors so before we make much progress let's just comment out things we don't want so I can show you some progress let's see unfortunately I can't really easily calm down crap so I feel like it cut it out or something all right so different approach let me just go ahead and make placeholder functions and stuff for all this and then we can refactor as is so we're passing in the placeholder text that's awesome what we want to do is when the input text changes on this text field that of calling a function we want to emit on input event now our existing component can just listen to that and call our function as needed so let's go to here we can say on input is equal to that new project name with whatever that was so okay and then when the value is passed they basically we need to have value as a prop to value as a prop and then instead of new project name I'm gonna say value go back to here I'm going to pass a value in and then on key enter instead of doing we just want to say MIT create so then over here we can just listen to the create event and just simply call create project so we have that abstracted into a prop this into a prop and then on inputs we pretty much emit on input with the past event and then for this one when we hit enter we're going to emit a create there might be a shorthand to do this since we're just propping our yep propagating that event up maybe just pass it event or something I'm not sure that'll feel free to comment if there's a better way to do line seven same thing with when we click on the button we want to simply just emit create and luckily our projects component is going to call Cory project on that already these are persistent so we don't need to change those so let's go ahead and save this and see what errors we may have you refresh this page and see if we're getting any type of errors it looks like we're not so the prop is my project is and we're passing that in here a I project name when I type something click create same logic as before so it's sending off that event to create the project let me just refresh the page and to make sure that's all system and working as I did before so if you noticed how easy it was to kind of abstract that little bit of functionality into my own view component and now basically anywhere my app where I want to have something that looks like this I could use it and we're going to be using that in our test panel in just a second and before we move on let me just make sure I aligned something to the right so I'm gonna say text small right this crate button should be as far to the right as possible so for this other piece of functionality which we're going to be using in the test panel basically we want to create a new component I'm going to call that editable record you pull that up and we're going to be doing the pretty much the exact same thing we did before we're going to copy and paste this to editable record bring it in we're gonna find that layout section and just copy and paste that into that editable record there boom we're going to make sure we try to call it here so editable record of course make sure you bring it in inside your components save this and let's see what we should pass to it to make this work so the first thing the UI's gonna be broken since we have to kind of fix all this stuff first first thing we want to do is a profit is check to see if is edit mode or not so we are going to say bind is edit mode and we're going to pass it this is edit mode so that's going to be sending in the project that is edit mode and then down here of course we need to define a props array and just to find his edit mode you keep on going through and kind of doing the same thing so instead of project title here let's make it a little bit more abstract and that's just going to be title so it all sure that we're passing that in so title is equal to project title hmm so this we can get rid of project that title we don't need we can use title say project I'm gonna instead of doing project here I'm going to call it record so over here I must say record is a prop we pass in and anywhere we see project I'm gonna say record record record get rid of his edit mode it's not as edit mode you the inputs I'm going to say emit input and pass it the event here and then what we need to do in the file above is just listen to on input and we're going to call that same functionality so set project title this needs to be removed see okay let's just look through this really quick and see if we're maybe missing anything mm-hmm this add text right to this because I noticed in the UI I wasn't already onto the right you right so for these events this app shot component editable record should have no idea if it's a project or task or whatever so instead we need to say omit on edit and then of course in here we need to say on edits dispatch that mutation same thing for this instead we're to say omit unsaved basically when they click the Save button to bind to that callback so unsaved make sure we call that previous method we were doing before and then of course getting kind of tedious so I'm gonna say on deletes make sure that we find it and I should say project four although so if you notice here basically this component has absolutely no knowledge about if it's a project or not actually this one used to be emit on save save project right so you see no instance of project anywhere and basically this is just a very abstract component which which takes in props and emits events when certain things happen which the project's component is kind of responsible for changing and dispatching the actions are emanating mutations so let's see what potentially is still broken in the UI so first of all it looks like none of the titles are showing up so we have title here down to project title idle should be rendered here that should only edit our render when is not edit mode so that's probably the issue let me just refresh the page and see what errors we have it looks like that might be working now so sit out and see if it's still working as it did before refresh the page so we have now to abstract components which we can use in this task panel to basically edit tasks delete tasks save tasks and create new tasks and all we have to do is pass in certain props to do so so let's just go ahead and commit what we have I'm gonna say editable records and create records okay so now for the kind of the last part of this tutorial let's go ahead and finish out the implementation of that asks panel so if I go back to my projects out view view let's assume we have one called tasks here have a new component called tasks I'm going to create that and make sure that exists in my components and then I'm going to make a new component called tasks that view athol that up I'm this it's going to be very similar to projects top view the other one so let me go to this see what we got so similarly we're going to need a panel but it's going to have a title of asks boom that seems like that's working fine and inside that tasks panel we're gonna do something very similar where we're going to be looping over tasks some say and brought our tests and tasks or a V for tasks and task I'm going to get the ID for the key is to make sure that we grab this but we're going to do a little bit smaller a font size so I'm going to eat instead for a task and then here I can just say tasks our description for now let's see what it has no matching for some reason it's not Muslim enough Luke it's working fine now so let me just refresh the page in case we're getting in Severus our beer method task is not defined on the end but it's okay all righty so now let's try to implementing the store so notice before we had a projects in the store let's go and create something for the tasks so in the store I'm going to add a new one called tasks ojs and I'm just gonna copy and paste projects and kind of bring it down we have a good starting point let me do all this okay okay so I created our tests module make sure we include it here I'm going to say tasks and make sure you include that module in your main store object so for the first thing we're doing we just want to rent her over the tasks right which that should be set up ready to go um actually it's not set up because we forgot to map the actions so here I'm going to go over and I'm going to copy this we're going to be using a lot of the same map actions mutations in state and what we want to do is inside of the computed we want to call map state going to take tasks and that's going to take asks this is obviously going to throw an error because we're going to use so let me just give her those for now you so no more errors anymore you all right so the first thing we want to do is if we go back to this component here and we click on one of these we want to make sure that we set the current project that we're trying to edit so going back to our project module let's go ahead and say make a new mutation called set current project and state that project just to keep track of what project were kind of a clicked on that current project instead of just project you okay so then in our projects on view when we click on one of these editable records so on click we want to call set current project is equal to project of course we haven't brought that in so let's go and grab that mutation you and then for editable record we don't have an on-click callback yet so let's go here and let's go back to our title and basically if someone clicks it I want to call on click I want to emit on click you so that we can keep track of what we have clicked so if I go back to my view debugger and click on some of these notice that the current project is changing as I click different projects here you but we want to take that a step further Sukie set current project should probably an action which fetches the tasks as well so what we can do is in the tasks module let's add a new action called fetch tasks for current project that's gonna be something that has MIT probably going to have root State Shammi call it set tasks for project going to take a project as a second so very similar to before let's just grab the HTTP method here I'm going to just copy and paste that so we have something to work with you so that's going to fetch all the tasks for this project ID that we're passing in for the action and I'm say set tasks is equal to data and of course make sure that we have a mutation called set tasks state tasks this the RM say state task is equal to tasks and then now when we actually click on a task we like the projects when we call set current project what we want to do instead is make a new method called set current project I'm sure I'm gonna call it current project clicked call it project click sorry I might change my mind a lot so what we want to do here I just say this dot set current project or in a passive project then we're gonna say this dot fetch asks for project and then make sure we just map the actions for tasks here fetch asks for project all righty so basically what we should have seen is if we click on that tasks over here we click on a project that mean it should make two mutations so it's going to first call set current project which it is then it should make a request to the tasks which I don't think it did so let's kind of go back and debug why that might not be happening make sure we call it fetch tasks for project an action and we should be able to call it correctly so if I go back here in action here Rajat clicked oh I know why so we made this new function but we didn't actually use it so let's go back up here and call our two clicked when we click on this notice that it makes a request for the tasks this is going to return an empty array because we don't actually have any and that should populate our tasks up here when it actually is defined and we'll see that in a second so let's go and start working on the next piece of functionality which is going to be the create record so if I go back to our task component I'm just going to go ahead and add a create record section well I need to dot dot which is gonna be like a task placeholder they set new tasks when it's the input changes I'm gonna say set new task name the valley is going to be a new task name and create is gonna be create to the task so very similar to the project's but we need to make sure that we bring those in so let's map new task name and four methods let's bring in map action from tasks that's going to be called create task and then we need some mutations for masking mutations that's going to be called set new task name and of course those don't actually exist yet so let's go back to tasks and we need to create one called set new task name state that new task name is equal to new task name and then we need the whole create task here someone's going to copy and paste basically what we have here and then edit it as needed the way we did it with the back end I think we actually need the project so what we can do is pretend like we have the project ID I think it might be that you let me just double-check that I'm doing that right at root state projects that ID so we're basically just grabbing that idea from the root state so we can know what tasks to append it to doing a post requests have the description here we're calling a pin task so make sure we have that asked here so I'm going to say state contests that push tasks you let's see if this is all working you you got a comma here or gods chins yeah let's see how this works my great record is not included so make sure we also did components and then make sure we create record let me just copy and paste that import from the project so oh here should we import that save it also notice here in our tasks panel we have the same pretty much component that we had over here but it has a little bit different placeholder text now if I type in and clean my room at setting new tasks name which is updating our test module new test name here and when I click create an error and that's because let's see I don't think I click the project yet so that's something we need to kind of fix basically we shouldn't show this panel unless the current project is clicked so if I go back to our projects view and I grabbed map state map state and make sure that we are including checked basically we don't want to display this section if we haven't selected a project yet so if it is selected we'll display it otherwise we don't to get that error because there's no way to actually create a task unless you've clicked one yet so let's click on awesome and then let's try to create a task current project is selected of ID of five and now when I click create it should try to make a request to the task endpoint which it did that was successful or return to 200 status and it sent back our task and then we appended it to our tasks array so at this point what do we notice well this is very similar to this over here so let's go ahead and bring in that other component we created and try to reuse it so projects I'm going to bring in editable record Riggin in here make sure you exist in my components mmm and I'm gonna do very very similar logic by just bringing that in so edible record here going to go back to my task component instead of just displaying the description let's display the editable record and instead here when I say task is edit mode ask set task title tasks clicked you actually let's see what happens if I try to comment does it there I don't ask work a set of title we want to do description display clean my room we don't wanna do any logic when we click it so let's just get rid of that but the other logic should say fairly consistent so let me go back and see if I can like to be able to style that task in a second so some things that we don't have yet is we don't have the set edit mode or save task or delete task created and set task description it's not pretty yet so let's just kind of work our way down these inputs and try to create what we need so here I'm going to say a mutation of set task description you that's going to take a ask in a description basically say task description it's a description make sure I rename title description here um set edit mode so I'm gonna go here set edit mode state ask and view dot set this is very similar to how we had it before so let's just go ahead and copy that in so just set edit mode here and then make sure we include view from the up import and we also have save tasks oh let me just copy save project and delete project and just kind of change that as needed into our actions so save ask I'm going to take a task hit tasks test that ID asked and delete tasks ask remove ask you forgot to bring in the unset edit mode so I'm going to do onset at anode be false hey let's see if we're missing anything you're missing removed tasks but we need to make sure we at a state test that by state on tasks index of task 1 all right let's finally we need to bring these in so we have these actions save tasks and delete tasks so let's bring in lead tasks and save task set that task description is tation said edit mode is a mutation and let's see if this works click on this let's see if we can edit the task edited the tasks and saved it over here awesome and then if we try to delete one of these new tasks here make sure that that is working so request failed with 404 that's because we're trying to hit slash task when it needs to be tasks so if I go back to my Elite tasks method I just need to add slash tasks instead that delete that okay so that's basically all working as we did before that's basically working as the project's did over here then we can also just change our projects as needed to fetch different tasks here so I think the last thing I'm going to work on for this tutorial is putting a checkbox here that can mark a task as completed or not so to do that the first thing we want to do is kind of extend the existing editable record module that we have let me commit what we here are some say you and let me get back to Sulekha saying in the editable record we want to be able to include a slot so we can pass in the ability to render stuff to the left of our text fields in title or whatever it may be so what I'm gonna do is going to add a new element called slot basically whatever I pass in inside my projects or tasks component is going to render to the left of this text so an example if I go to tasks and for my editable record if I say I'll do like h1 hello make sure I have the closing tag outside of that save this we should say hello to the left and of course this is just going to be on top right now because we're not floating it to the left Ernie what what we want to do in our case is I just want to make a checkbox following what we've done over here just get an icon but I go and put that inside the slot here going to go ahead and give her that stuff for now and save this and hopefully that is not what we're looking for we're looking for something called a check box so let me oh sorry I forgot to put it underscore here check underscore box all right so when we do that we get a check box but we need to be able to toggle between if it's a checkbox or if it's not filled out so there's another icon that we could use called checkbox outline blank so what we want to do here is basically just render some a different icon depending on if we're completed so I could say task dot completed and do a ternary operator and just simply return check box if we're completed or return check box outlined blank if we are not completed go ahead and save that if we go back notice that these two tasks are not yet completed additionally when we click on these check boxes we want to kind of toggle that completed state so let's just do that let's add a at click and I'll say toggle completed and then that's going to be a method which accepts tasks and of course that doesn't exist here so we need to go back to our tasks I'm going to say that's going to be an action so I'm say talk will completed is an action so we'll go back to our store load up the tasks module I'm going to add a new one called toggle completed and basically what this is going to do is we're going to do a commit to set that to either true or false so I'm gonna say we'll completed um I had to have a different name so I don't think I said that habit of name so I'm gonna do a mutation with the same name for now I don't know that's a good idea but let's just do it and basically task doc completed is going to be equal to a stock completed you I do believe if we go to the console when we try to fetch tasks that completed is indeed a attribute on that task so we should be good we don't need to do view dot set because we're actually handling that on the my sequel databases table so we have a mutation which is going to kind of modify or toggle that completed bullying and what we need to do inside this toggle completed action is simply commit that hmm but after we've admitted that we need to call save tasks here and actually instead of doing an action maybe we should just instead get rid of this action sorry kind of changing up my plans made coding which isn't necessarily bad to do but instead of it being a action let's just make it a mutation and what we can do is when we click on this I'm going to add a method down here called check clicked I think that's what I just had a call and we're simply just gonna say this dot welcome completed tasks and then I'm gonna say this dot save ask past that task at Clifton old I think I could have done this in the action it could just fire an action off of in action from this action but I think it gives us a little bit more flexibility if I don't actually save it when I toggle it but I want the mutation to just toggle the state and then I want the disk component to be responsible for saving it I don't want the action to do both of that so let's see if this works so if I go and click on my project here and I click on this task here first of all it's sending off a request to the network and completed is true if I go to my view X or view / e bugger we see that talk--i completed was fired completed to set the true if I cleared again completed is set to false and it's saving that task so let me just make a couple of ask and make sure that these get persisted when I create them and just refresh the page just to verify that everything is working as before and it is ok so we're basically at the end of our demo I mean I could probably spend more time sprucing up the Styles you know obviously when I hover over this it should be clickable or should have a cursor when I hover over this the text should change um but I guess in terms of this tutorial I don't want to spend too much extra time I'll assume this up I think we covered a lot of good grounds and like examples of how to build up a single page application and connect it to a REST API that we created by hand so that basically wraps up this full stack view and add-on SJS tutorial if you have any feedback or questions feel free to leave them in the comments below or you can message me on Twitter I could always use feedback if this tutorial was too quick or if I was jumping all over the place feel free to tell me so and maybe I'll make another tutorial in the future which isn't so sporadic and on the fly a person like tutorials that are kind of like unplanned so you can kind of see what I'm thinking and how my logic is applied to when I'm making applications and stuff alright so I think that's basically what I'm going to be covering in the full stack tutorial other than deployment which I'll do in a bit one thing I'll change is if you remember if we go back to our store and go to the index I disabled a plugin I'll create create persisted state I'm just gonna re-enable that and kind of explain what this does basically and now when i refresh the page I have to log in one more time but now when i refresh the page it's gonna cache everything that was in my store inside local storage meaning that I don't have to log in again or whatnot so basically exactly how I have my app state before I leave and refresh that's how it's going to load back up so if you notice I clicked on this project and it loaded back up for me so it's very useful in terms of like UX because you don't want to user to have to keep login and over and over again just happy their state stored locally and then once they refresh the page or go back onto the application everything is exactly how it was before so in order to get our single page application deployed out we first need to kind of build it so I'm gonna do in p.m. run build in the client folder and that's going to build our view application into a dist folder and after that's done building what we could simply do is just copy it from the disk folder and put it in our public folder in our server again that's probably not the you know proper or best practice way to do it but that's just one way to deploy your application is super simple so while that's doing that I'm just going to build a new folder called public okay so now that that is done if you look at the disk older here it created a bunch of different files so basically what I'm going to do is just copy the files that are in that folder and put them in my public folder here I just want to make sure that the public folder is not ignored again this this probably isn't the best way you should probably have like a continuous integration continuous deployment system building up and deploying to like a static host like s3 or something but again this is just a quick dirty way to get it deployed so what I'm going to do here is I'm just going to simply add that and commit it my REIT bill and then on our get repo we can simply pull and start our Dona server to have that hosted all right so now for deploying this application first thing I'm going to show you is I have a digitalocean account and I'm gonna create a new droplet go up here and click click droplet create droplet I'm going to give us a list of different OS as we can use so I'm just going to use a boon 2 which is the default I'll just go ahead and say give me a default because only gonna have this hosted for like a minute or a couple of minutes and then when I could click create that's gonna go ahead and just start creating my droplet and then once it's done I'm gonna get an email with the root password that I can use also we have the IP up here that we can use to SSH into the gene so let's give this a second to finish running alright so now that this is done running let's just go ahead and copy that IP address and go over to my terminal I'm gonna do SSH route at that IP address and then I'm going to copy and paste the password that they've emailed to me the root password and then once you first log in for the first time it's going to ask me for that current password again I'm gonna ask you to enter a new password let me that and now we are on the server so the first step is we want to install node let's go ahead and just follow this tutorial where it says you need to curl the setup eight script or run that fetch the necessary things that set up node and then when that's done you need to go ahead and run this second committee that's done going to run install for nodejs all right so now we have note installed and we have NPM installed so before we move on we need to also make sure we install the Adonis CLI so let me just go ahead and copy that run that you basically we need that for running our migration scripts it's installing let's just go ahead and set up next step which is we need to go to our project and go ahead and copy the HTTP link here so I'm going to copy that we're going to clone our project when this is done installing so I'm going to get clone and clone our project now we have our project here SSH into the server folder or I'm going to CD into the server folder in you run NPM install so that I install all of our dependencies we need to Ho stored on a server and while that's installing I'm just going to edit this env file and in order to host our Dona server we need to change a couple thing though first of all the host needs to be a zero zero zero zero or it needs to be eighty and then no D&V needs to be production all the rest you can keep as is so I'm just going to copy this and inside that server folder here I'm going to paste that into that env file save that and now we can run our migration scripts so we're going to do ad honest migration and colon run - - force make sure we run our migration scripts in set up our tables fact it might have already set that up maybe I committed database was committed when I the database file the sequel light was already committed to the repo so that was kind of my bad so technically you don't either run your migration scripts this should have been ignored get ignored but if it wasn't or yeah if it was get ignored you probably have to rerun your migration scripts to set up your C like so now everything at this point is set up let's just try running our server really quick and make sure that it runs using node space server ojs and if everything worked it should say it's hosted on zero zero zero eighty then we can go up here and try to go to local we can try to go that IP address here and see what happens and so our app is now loaded is hosted at this port on all rights hosted at this IP port 80 you can see that our app is running sure that we can actually login let's just click login and see what happens excessively successfully logged us into our app oh so I mean basically you just follow these steps if you wanted to get your app running in production um of course you can use other things like Heroku or cloud compute to deploy your application but that's just this is just one way to do it really quickly and really cheaply because you can have a lot of apps running on the same droplet and this setup wasn't too difficult the final step is we probably want to install a better way to run our server so let's install a tool called PM to globally so you MPM install global km2 and once that's done installing I could just do p.m. to start service and that is going to be a tool which kind of monitors my server and it will restart it if it were to crash for whatever reason that's done installing now I can do p.m. to start River Jas going to spawn APM - Damon on my server so I can hit it again here serious loading fine Oh so that pretty much sums up my full stack you Adonis digitalocean deployment tutorial you have any comments if you want to leave me feedback up how I can make my tutorials better feel free to do so in the comments below I hope this tutorial didn't go too quick and I hope I kind of explain what I was doing in the meantime happy coding and thanks for watching
Info
Channel: freeCodeCamp.org
Views: 54,669
Rating: 4.9781899 out of 5
Keywords: vuejs, vue, adonis, adonisjs, full stack, learning to code, coding, programming, javascript, es6, building a todo list app, vue.js, vuejs tutorial, vue js tutorial, vue js tutorial for beginners, vujs tutorial for beginners, vue 2, vue.js tutorial for beginners, vue framework, vue js 2, vuejs 2 tutorial, javascript tutorial, front end, rest api, api, rest, full stack tutorial, full stack tutorial for beginners, front-end, vue.js tutorial, vue js, vuetify, vuetify tutorial
Id: dfEZlcPvez8
Channel Id: undefined
Length: 228min 57sec (13737 seconds)
Published: Wed May 23 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.