I built a pizza tracker with Laravel, React, and Inertia | Full Stack Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
so the other day I ordered dinner and for those who don't know Domino's has a Pizza Tracker app on their website it looks like this and it lets you see where your order's at in the pizza making process and I was thinking to myself I wonder how this works I did some research and I found a ton of posts and comments saying that this was basically just a timer and that it actually doesn't reflect where your order is currently at however I found a couple posts that suggest that is completely false so I try to build it and this is what I came up with so here's my Pizza Tracker and we have our five steps and if I go behind the scenes and change it from baking to checking we can see here that it'll actually update in real time so what does it take to make this well let's get cooking so we're going to use three different Technologies to build this we're going to use laravel as our backend API react as our front-end framework and inertia as the glue between the two it'll act like a client-side framework but you can use your server-side code to manage it and I'll explain a little bit more about that as we go so first things first let's get a project started Okay so I'm in this directory let's go ahead and start a new laravel project by using composer create project laravel laravel and the current directory just a quick note I'm going to start from scratch for this demo but if you want to see just the public facing tracker part feel free to skip ahead using the chapters in the video description and once that's finished up I'm just going to go ahead and quickly edit our EnV file and I'm going to change the database connection to sqlite this will mean I don't have to set up a database locally and I can just use SQL Lite so now I want to run the default migrations that come with laravel so we can use PHP Artisan migrate Force which will create that sqlite database in our local environment and run those migrations okay let's clear this out and the next thing that I want to do is I want to immediately install a starter kit for laravel so there are a couple that exist and I'm going to go with the simplest one which is breeze so composer require a level Breeze and the dev flag included in that and not only will this provide for us a starting point for authentication so logging in and registering for our application but it'll also provide a starting point for inertia and react and I'll show you that in a second so if we go ahead and run PHP Artisan Breeze install It'll ask us what stack we want to use for our application so let's go ahead and choose react with inertia would I like to add in the optional features dark mode server-side rendering or typescript I'm going to keep all these blank right now so we'll have it be as simple as possible and we'll go ahead and use pests for testing and this will run through the installation process it'll run a couple composer commands which we can see now and then once that's done it will start running some npm commands as well and now it's going to run Veet build and the breeze scaffolding has been set up successfully so our application is scaffold is good to go and we can actually check it out if we go ahead and run PHP Artisan serve and then I'm going to go ahead and open up another Tab and I'm going to run npm run Dev which will give us a v a hot reload server to look at our application through so if we go ahead and open up localhost 8000 we can see our application up and ready and we can log in or register with it as well right out of the box with laravel Breeze I'm going to go ahead and register for an account so I can see the authenticated section as well okay so I registered and I'm automatically brought into this dashboard section which only authenticated users can view I also have out of the box a little section to update my profile information or delete my account and let's go ahead and open up our source code and take a look at that we have our controllers here which we got a profile controller from Breeze we have this whole auth controller section also from Breeze which gives us the ability to register users verify their email addresses and just a bunch of boilerplate for authentication that we don't have to write ourselves but the interesting part is if we open up our resources folder here let me go to our views we only have two of them we have this welcome view which is what you would normally see whenever the application boots up in its landing page to begin with and we have this app blade file and it has a couple different blade directives in here so we have some of these script directives routes V react refresh Veet scripts inertia head and then we have this at inertia directive down here this is the entry point for applications components so just like if you were creating a react app out of the box normally or a view app you'd usually have some kind of entry point div like with an IDF app and this would be the ax this point for the rest of your single page application but instead inertia uses something that's particular to each framework for laravel that is this inertia blade directive speaking of views though where is the rest of our application where are our pages that contain this dashboard content or our profile page as well like where does that reside so if we go back to our resources folder and go to the JS folder we can see we have a lot more than what normally comes with laravel so we have an app jsx file we have a Pages layouts and components directories as well and all of these are used to build out our application so it starts with a page so if we open up this dashboard jsx file here we can see that we're using a react functional component called dashboard and it has an auth prop passed into it but okay how does this component get injected into the dashboard view that we see here well that's kind of where the beauty of inertia comes in at is it uses your backend framework's flow already so in laravel if you weren't using a single page application if we were just using blade we'd have a route and we can see that if we go to our routes web file and we'd call it something like dashboard and here it is here but instead of normally returning something like view dashboard where it would correspond to a dashboard blade file we use this inertia render method and then pass in a component name so this component lies up with this react component here and so what happens is whenever somebody views this dashboard route initially this inertia render method will return back a compiled view consisting of this app blade file and then the injected component as well as the data required from it automatically serialize inside of the markup so if we go back to our dashboard page let's go ahead and open up the source for it you can see down here we have a div with an ID of app and we have a data page attribute associated with it with a pretty large Json string attached to it but what happens is whenever this is finally rendered up the client hydrates this and creates the view that you are seeing here but that changes for subsequent Point visits so on the initial load like I said so let's go ahead and refresh this we see that we're doing a full page refresh we're getting this dashboard view as a block of HTML but if we go ahead and visit another page like let's say our profile we can see that it was an asynchronous visit like a single page application so if we scroll down here we can actually see the call to the profile route and the response background was a Json object containing the component that's used to render this page as well as the props object for that page but you don't have to have a separate API and make calls to get user information like you would in a traditional single page application you can use your backend Frameworks routing and pass in props like you normally would to blade or whatever the rails equivalent is and on the back end this looks like a typical laravel application so we have a route here that just returns instead of a view inertia render and that's what all of our profile routes do as well if we go to this profile controller here we can see that these these are just returning inertia render and anything that's passed in like you normally would for a blade template gets put into the props section of this component so if we go to the profile edit component we can see here that we have three props auth must verify email and Status so auth is passed in automatically but the must verify email and Status are passed in with these array Keys here so yeah inertia is a really cool way of building single page applications without the redundancy that you would normally have having to write both an API and the front-end routing logic at the same time so okay let's let's continue on and build our application so let's get out of everything that we have here our folders and just go back to the beginning so we're making pizzas and we want to show somebody what their current order's status is so the first thing that we should do is create that model that's going to hold the data for us so that pizza model so if I go ahead and open up a terminal I can run PHP artisan make model and we'll call it pizza and we'll pass in the migration flag as well to get us a migration file that we can use to create that table so the first thing let's go ahead and open up that create pizzas table migration and talk about what we're going to need here to store this pizza data how about a foreign ID for the user model so that way we can have some kind of ownership between a pizza and a person who's making it how about a string for the size a string for the crust type uh Json array of the different toppings that can be used for a pizza and then a string for the current status of it so this looks pretty good we can go ahead and exit this file and if we open up our terminal again we can run PHP Artisan migrate to put that table into our database so now that we have our database table actually set up I think the best thing to do next would be to create a factory so that we can actually populate the database with some fake data I don't know why I keep closing this but let's go ahead and open up the terminal again and we'll run PHP artisan make Factory Pizza Factory and pass in the model flag of pizza so it created our file for us now let's go ahead and open that up and if we scroll down here to the definition remembering again we have a user ID which is our user foreign key we have a size crust toppings nope and Status okay the easiest way that I do for factories like this is I know that I'm going to create 10 test users in my database so I'm just going to use Rand 1 through 10 and pick out a random user ID between those two integers ideally not the greatest way to do this but this will work in a pinch and it works for this test application and so for our sizes we can use laravel's array random method and we can pick out a random value from an array of possibilities and then likewise for the crust we're also going to use array random the toppings we'll get to that in a little bit that's going to be an array but I'd like it to have some kind of variability in it so we'll we'll tackle that in a second and the status is also pretty simple we'll also just use a random amount of values now normally whenever a factories ran just like saving a model in the database any other way it'll have an auto incrementing integer ID but I don't want to have any small number ones because it just doesn't look good on the back end so instead I want to create the ID itself and I want to have some kind of Randomness thrown in here so we're going to use Rand again and I'll give it a value anywhere between one one one one one and 99999 there will always be a five digit random ID associated with a particular model okay so for the toppings I want to have a list of choices and then I want to have an array that's given to this model based on like one to four of those choices so let's go ahead and create some basic topping choices here in an array now what I want to do is have a final toppings array and put in some kind of random amount of these choices in this array so I think the best way to do this I'm just going to create a basic for Loop and then we will add to our toppings array a random selection from our topping choices now because we're pulling this out randomly each time there could be duplicate values in this so in order to combat that I'm going to run array unique on those toppings oop I missed the I here so this will get us a unique array of hopefully one to four toppings to use for our pizza and then we'll replace that attribute with the value from that array so our Factory looks good but we have to have a way to use it and so that's where our database Cedar class will come in here so like I said earlier I want to create 10 different users in our application at least so here's that user Factory creating 10 of them and then let's go ahead and also create uh 10 not 10 let's do 20 fake Pizza models as well opening up our terminal PHP artisan DB seed and uh oh we are getting an array to string conversion I know why that is so let's go ahead and exit out of this and the problem with that is if we look at the create pizzas migration that we just did our toppings are stored as a Json string but we are passing them through to the database as an array and we can combat this by opening up our pizza model so while we're here let's go ahead and make a couple of changes to this first of all let's set the protected guarded attribute to an empty array this means that no attributes coming in will be guarded we can pass in whatever data attributes that we want whenever we're saving a model and then we have a relationship between users and pizzas so we can go ahead and add that in here too public function user return this belongs to the user class and then to combat that Json issue we can say protected casts is equal to an array and this takes a associative array where the key is a database column or attribute so we have our toppings column and then the value for that is how you want that to be casted in laravel this essentially means that it'll do some kind of calculations or Transformations between the data that's actually residing in the database and how it's presented in your application so if we say that this is casted as an array what that means is that the data will have the value of an array in the back end code base in laravel but whenever it's put into the database it is serialized as Json so let's go ahead and try to run that DBC again PHP Artisan DBC our database was seated and everything is fine so now I think it's time to create an area in the dashboard to actually look at those so let's exit out of what we have here now and let's go ahead and open up our routes web file so we have this whole middleware auth group already and that is perfect so let's go ahead and create a new route and we'll just call it pizzas and it'll use a new controller so I'll keep that blank for now and we'll give it a name of pizza's index now let's go ahead and create that controller so in our terminal PHP artisan make controller Pizza controller and so now we can provide that controller here and we'll use the index method to get all the pizzas let's go ahead and open up that pizza controller and create that method and let's talk about what needs to be returned here because if we just go ahead and return Pizza all we can go ahead and view this in our local environment so if we go ahead and open up this view instead of dashboard we type in pizzas we can see here that we have a Json object of 20 pizzas but that's not what I want to see I want to see a view like our dashboard but full of pizzas in like a table so we're going to need that inertia render that we had seen earlier and we're going to need to create a component to hold this information so let's go ahead and create a variable out of these pizzas here because we're going to need to pass that in and then we can just return inertia inertia render and then a component name now because we might have more than one screen for this I think it's good to keep this in its own folder so let's call it component pizzas all and we don't need to specify any kind of file suffix for this component just the name and then we need to pass in any props along with it so for us that is the pizzas and now if we go ahead and try to run this we get a blank screen we don't get any kind of error that the component doesn't exist until we inspect our console then we can see that we have a uncut exception down here that the page wasn't found pizzas all.jsx now right now there's no Artisan command to do this automatically so what we'll have to do is go to our resources folder the Pages directory and create that jsx file automatically so pizzas all.jsx and let's scaffold out a basic react functional component so this is the most basic component that we could create and if we go ahead and save this we can see in the browser that it is displaying the information that we want the problem is though is that we want to be part of the dashboard and we also want information passed through to this to display on the front end so we can go ahead and add both of those in here with our props so we have off automatically injected so we can get the user's information but we also have our pizzas prop that we passed in through the controller earlier and now we need to make it part of the dashboard well if we look at the dashboard component we can see that it is nested inside of this authenticated layout component here so let's go ahead and just copy this and use it for our other section so now if we go back we can see that we have a page in the dashboard and it says all pizzas but we still have this your logged in section down here which will update with a table in a little bit one thing though is that we don't have a navigation to this section yet so let's go ahead and create one of those real quick and because we're using Breeze that's actually already included in here if we look at the layouts section for the authenticated layout component and we scroll down we can see that we have a nav link component as well that's going to our dashboard now if we go ahead and follow this component we can see here that it is using a link component coming from inertia's react library and the reason for that over something just like a basic ahref is because the link component is the heart of how react uses its routing system so whenever one of these links is clicked it intercepts that URL that you're trying to go to and makes that request asynchronously to give that kind of single page application functionality so let's go back to authenticated layout and we'll create a new link we'll just copy this one down here for our pizzas section so we'll just call it pizzas the route we're going to is pizza's index and we want it to be active if the route is currently at any pizzas uh endpoint or any pizzas named route and now you might be noticing that we are using a laravel named route inside of a react component using this route method and it's because we're using a package called Ziggy which is automatically inserted into a lot of these laravel starter kits that use inertia it's by Titan and it basically lets you use your laravel named routes inside of JavaScript so you can use it for typescript you can use it for View and react applications and it's really cool it lets you use named routes just like you would inside of laravel but inside of any JavaScript application let's go ahead and save this and we can see that back in our dashboard we have a now active route under pizzas and we can go back and forth between our dashboard and pizzas and everything is working perfectly smoothly the next thing that we need to do though is actually scaffold out this table down here where I want to list all of the information for each of our models so let's exit out of what we have here and we'll just focus on this pizzas all component right now so I have this table component that I pulled from flow byte I'll link it in the description and it basically gives us access to four props that we can use to create a table using tailwind and then go through and map each item to a row in the table so now back in our main component I can get rid of this your logged in section here and I can use that table component and then pass in some of these props so our items are our pizzas columns we'll need to create the primary name for the ID I'll call that order number and then we need an action as well which I don't have yet so let's go ahead and fill some of these in so we have the items coming in that is the pizzas prop that we pass in from the actual controller here which again gets to us from this eloquent method no API calls and no fetch requests but we need to create a list of columns that we want displayed in this table from that data let's go ahead and create a const columns array and we'll pull in size and status so now let's provide the columns attribute our columns array now for the action this is a link that should be at the end of every row of the table and usually this is like a an edit the model or view more details about it for our case I want to be able to go in and edit the status of each of these orders so we'll call this pizzas edit we'll create a route called pizzas edit let's go ahead and just create a placeholder for that now so we'll create a route that gets us to a particular model using that route model binding from laravel and this will go to our edit method inside of our pizza controller and we'll call this pizza's edit and while I'm here we'll also go ahead and create a patch method for whenever that data will be saved and we'll call that pizzas update so I think we have all of our pieces together now let's see what this looks like on the front end okay so we have the size the status and the order number for all of our different models if we go ahead and view details for these oh we get a pop-up that says the pizza controller edit method does not exist inside of our controller file this is something else that's pretty cool about inertia is that because we're using these link components inside of here it pops up any errors inside of this model view here instead of forcing a Reload of the page you're trying to go to so you can easily exit out of here and be in the same state that you were just in something feels like it's missing from here though and I would like to see the username of the person who is currently associated with the user who's associated with each order so let's go back in here and I could do something like where is it columns I could do something like I don't know user here but the problem with that is that there is no user attribute inside of our model I could pull one in by saying pizza with user and then get but that'll add in a ton of information underneath the user to pull in the whole user model for each Pizza model but I'd like it to just be a single extra attribute called like Chef or something and we can actually do that if we open up our pizza model we can create a new section called appends protected appends and that takes an array as well of computed properties things that are generated from data that's in the database but are not physically stored in it and so what I mean by that is if we have in a pens called Chef then we need to create a function down here that generates this value that is attached to each Pizza model so if I create a public function called the get Chef attribute so I can return this user name which will return just the name of the user Association attached to this particular model and that will automatically append it inside of each model whenever they're returned back to the front end so without having to use a width or anything like that every Pizza model will have an Associated chef with it which is just the name of the attached user model and we can see that if we go ahead and early return all these pizza models in the browser we can see that we have a chef attribute now with just the name underneath of it but there is a problem that you might notice and that's we're getting a user object attached as well for each of these which is something we didn't want in the first place that's the whole reason why we added this Chef attribute here and the reason for that is because we need that attached user model to get the name laravel automatically appends it inside of each model anyway but we can hide that pretty easily if you want to by creating a protected hidden attribute on the model as well and then adding in the attributes that you don't want to be displayed whenever this data is returned back so we can hide the user attribute and it'll still use the data associated with it that's pulled in but the actual model will be hidden from the data so refreshing back in our browser we see that we have each of these models has a chef associated with it but that user Association that whole user object is gone now so okay let's go back to our controller remove this early return have everything back the way it was and I didn't type hint this either so this is an inertia response we're getting back and okay let's go ahead and see what this looks like now oh we'll change this and the all will changes from user to Chef and now if we refresh our front end perfect so we see our order our size our chef and our status for each of our pizzas that are in our database so what's next well we need a way to edit each of these so we can change the status from something like prepping to baking or baking to checking so we want to have this view details functionality added in so if you remember let's exit out of some of the stuff that we don't need right now we added in both an edit and an update route to our main application routes file but we didn't add the methods in the controller so let's go ahead and do that now let's have a public function edit and because we're using route model binding we are automatically getting this pizza model associated with the URL that's visited so we don't have to use like pizza find from the ID we are automatically getting a whole object back that is stored inside this pizza variable and we want to render out another component to display some kind of edit page so we'll return an inertia render method again this time we'll call this pizzas edit and we'll pass in a pizza prop which is associated with the model that we are currently visiting and like before this returns back an inertia response and then let's go ahead and add in the scaffold for our update function as well it's a public function update again we are pulling in the pizza automatically with route model binding but this time we need the request object as well because we'll have to be pulling in some kind of Saved form data in order to update that model so we'll keep this here for now okay so we need to create this form this edit form for each of these pizzas so let's tackle that next pieces folder let's create a new file and we'll call this edit jsx and this needs to be a basic form and like our main pieces dashboard view this is also going to be extending that authenticated layout component so we'll add in our user from the auth prop and then we will go ahead and change the title of the page to reflect the uniqueness of each model so we're using the ID here and let's go ahead and update the title of each of the pages as well using that same syntax then we need some basic scaffolding that's available on the rest of the pages as well so now if we go back to our dashboard we can click on one of these view details buttons and it'll take us to a page associated with that particular order so perfect this is working exactly as we expected it to but the problem though is that we need a form here so instead of actually dumping everything into this section here I'm going to abstract that out into a component of its own kind of like the profiles section does down here so we have this partials folder inside that has different form components that are used for the edit page so I'm going to create a new component called how about update pizza order form so I went ahead and scaffolded out most of the markup but let's quickly go through a little bit about what this component does so again react functional component here called update pizza order form and we have a pizza and class name prop that's getting passed in through us so the section starts out we give the class name the same classing that gets passed in and then we have a header section here that shows we're looking for order information and some display flavor text as well so all this is pretty boilerplate and then we're using just a plain form element here so we have a form that has a class name associated with it and then inside of this form we have different sections for each of the different attributes associated with the pizza model so we have the size which is a text input we have the crust another text input toppings another text input and then the status which is a select and we also have an error down here because the select input is the only one that I want to be editable on this the other three inputs I I want them to be disabled I just want them to be read only so that somebody can glance at an order and see what an information is associated with it and now these components came with laravel Breeze automatically and they're styled nicely using Tailwind CSS and are basically just boilerplate that kind of abstracts out a lot of the markup from creating forms so there's not a whole lot of functionality Behind These but what we need to do now is we need to pass in values into each of these components so in the text input for the size we need the pizza's size attribute we can do the same thing for each of these so for crust the value is pizza crust for the toppings it's pizza toppings and because it's an array we'll use join and we'll have it joined by a comma and a space and then the status needs a set of options as well as a value so the value is pizza status but we don't have any options associated with this select input yet so let's go ahead and create those we'll call these just status options and it'll be an array of all the options associated with each particular order so now we can use that status options objects inside of our select input and let's go back to our main edit page and implement this form so we can see it on the front end so we have update pizza order form and we pass in the pizza prop that we are getting from our pizza controller and then this also wants a class name which we'll just do as Max with extra large so now let's go ahead and see if we can see this on the front end okay so we have our form here we can scroll down and we see we have the size the crust and the toppings which are all disabled and can't be edited but the status here we have the different options and it's already selected the one that is currently associated with our particular order we have our save changes button down here as well the problem though is that this form as it stands is not functional if we go ahead and try to save that nothing happens because we have no action or method associated with this form but we don't want it to be submitted using the typical browser submission we want to do it asynchronously so that we maintain the spa appearance of our application and we're using inertia so we want to do it the inertia way and so in order to do that we use the on submit method for this form and then we pass in a function that will be fired whenever this forms submission starts so we'll just call this submit and let's go ahead and scroll up here and above our status options let's create a new constant called submit and it is a function that takes in the event and we'll call prevent default on that so that the submission doesn't actually go through to the browser it doesn't it doesn't fire off the way that it's supposed to and instead what we need to do is we need to move all of the data that's associated inside of the form to the pizzas update Route that we had created earlier now at the top of your head you might reach for something like fetch grab all the data inside of this component and then pass it through that but inertia has a really really easy way to do this because it has a built-in way to work with forms and that has something called the use form method so what we need to do first is pass in a bunch of initial values for the form attributes that are going to be used below so if we look down at the form that we had created again we have size we have the crust we have toppings and we have a status so these are the default initial values we need to do for this use form method so we have size and we need to give it a default initial value volume so that is just the pizza size the the prop that we had passed in we're using that as the initial value likewise for crust for toppings it's that array that is joined together like we did down below and then for status Pizza status now what does this give back to us when we use this well it gives us back a bunch of different attributes depending on how you want to use this in your component so we get back a data object and a set data method and these work just like reacts state so data is associated with the current data set that is part of these initial values and then set data allows us to change those values and keep the reactivity associated with them to use in other parts of the component or application we also have different methods associated with how we want this form to be used in the component so we have put get post delete but the one that we're looking for is patch remember in our routes web file we're using the patch method here to send those updates over to the controller so we're going to match that by using the patch method in here we can have an errors bag that gives us any errors associated with this form we have a processing Boolean that determines whether or not the form is currently in the middle of processing data and we have a recently successful Boolean as well which gives us back a True Value if the form was recently submitted successfully and I'll show you how we're going to use each one of these below so first off for the submission this is really easy all we do is we call it a patch method and pass in a URL to it so for us we're using that route object because we're using Ziggy so we have access to the named laravel routes and for us that's pizzas update and we just pass in the additional value that's needed for that which is the ID of the pizza so Pizza ID and that is it whenever the form is submitted this single line here will take all of the data associated with this form that is reactive and send it to this route with this method associated with it so let's go ahead and continue downward and for each of the different inputs instead of calling the pizza size attribute we're going to call the data size attribute so that way we're using the dynamic data from that use form method from inertia in each of our inputs so again data cross data toppings and we don't need this join method because that was being used in our initial data set above and data status so now back in our front end we can see that everything has remained basically the same but it's the reactivity behind the scenes that we've made adjustments to so if I wanted to I should be able to change this from prepping to baking and submit the form oh except whenever I change this we can see it goes right back to prepping that's really weird well it's because we are updating the data or attempting to update the data from this form but the client has no way of updating that data it's using the constant state that is in the data attribute from inertia and that's where we're going to use that set data method so on the select input whenever there's a change so on change we want to take that event and we want to set the data of status to the Target value of that event so whenever this select input has been changed we're going to take that value and we're going to set the data attribute for status to whatever it was changed to so now if we go back to our front end and we change the status to something like baking we can see that data was automatically changed to the associated status now we can go ahead and try to save this but remember we didn't do anything inside of our controller we have an empty update method down here so let's add some functionality to this and all we need to do is we are updating one attribute in here which is the status remember we don't want to change anything else inside this pizza model for right now so we can just update the status to whatever the request status attribute is that comes through and that's it we shouldn't return anything from here unless there is an error the front end will just assume this went through fine and that recently successful attribute will be true on our form so how do we use that well back in our update pizza order form section underneath the save changes button I'm going to go ahead and use this transition class from the react headless UI Library so this will show only if recently successful is true so what this means is that whenever the form is saved we should see a small flash of this saved text down here for a few seconds before it fades back away and so let's go scroll down here change this to baking and hit save and yeah we saw save flash up and then disappear but you can see that whenever we save this form it pops back up to the top here and we don't really want that we want it to stay wherever the user had scrolled to this isn't navigating us away or anything so we should say at the same scroll Point as we were before and in order to make that happen all I need to do is go up to the submit method up here and when I'm using this patch method I can just pass in a object consisting of options and the only one I'm looking for is The Preserve scroll option set to true so what that will do is that whenever this form is submitted it'll remember wherever we are scrolled to and maintain that same position so now if I go back and I update this to checking and I hit save we can see that we didn't pop back to the top of the page we remain in the same location all right and the last thing that I want to do with these options that we got from this use for method is I want to have a place to show errors and use this processing Boolean as well so if we scroll down here I have a section for errors already with this input error class and I can just pass in a message attribute to it and it'll be the errors object and for the processing Boolean usually what you want to have happen with forms is that you want to disable the submission button whenever the form is processing so we can give this disabled attribute the processing Boolean and so the primary button for the form that saves the changes for will be disabled whenever the form is actually processing so it's good for preventing things from being submitted as the form is already submitting all right I think our back end is looking good at this point so we gave our users the ability to have a view of all of these orders be able to click in the details for them and then adjust the status of each order and all this leads us to being able to display this on a nice front end so let's go ahead and get right into that so like with every other route I'm going to start with our routes web file I'm going to create a route that is public to have a user be able to look at their order and see what the current status of it is so let's go ahead and create a route get and we'll have it be order and then the pizza object underneath that order and we'll have this go to a new class that is separate from our class that handles all of the back end Pizza methods so we'll keep this blank for now and we'll call this uh public pizzas show let's go ahead and create that controller class PHP artisan make controller and we'll call this public Pizza controller okay and that's the name that we will use inside of our array here so public Pizza controller class and we'll call it the show method so let's go ahead and open up that class and create the method and because again we're using route model binding we automatically get access to the pizza object associated with this order so if I return that pizza object just like before if we go ahead and take this order we'll open up a new tab and if we go to localhost order and then our order number we see that we get all the data associated with that particular pizza but again like everything else we don't want to display just the raw data we want to return a component so we return inertia render and then the component name so this one I will keep underneath all of our other Pizza components so we'll do pizzas and we'll just call this show and then for the props we'll pass in the pizza just like we did for our edit component now let's just type in the return send inertia response and go ahead and create this component show.jsx underneath the pieces folder in our Pages directory so unlike all of our other components we don't have an auth prop being passed in here because this isn't a route that's underneath the auth group so the only prop that we have passing in here is the pizza and let's go ahead and just make sure everything is working as expected so if we go ahead and pass in the ID we should see this in the front end now and yep we do so we see the order number and the text that we had passed in but we need to create a nice display to actually show the order process now unlike the last couple of components that we created I'm not going to be extending any of the other layouts that we have so it's not going to look at the dashboard and it's also not going to look at the welcome screen either this will just be a blank page showing our pizza status tracker so let's start out with a nice couple of wrapper divs and give this a logo so now on the front end we have this here we have our dice logo for dice's pizza and speaking of which if we go back here we see that we don't have a title for the page in the tab so let's change that underneath the parent tag of our component we can use the head attribute that we get from inertia and provide a title we'll just call this order number and then plus the pizza ID so now going back we see that we have that in the title okay so we have our logo now what do we need next we need to display the actual status of the pizza in order to do that though I think that'll be best abstracted out to another component in this partials directory so let's go ahead and create one we'll call this pizzastatus.jsx and I don't know what we're going to be using in this for props yet so we'll just leave this blank but we will include it here on the front end and then underneath the status I'm thinking that we also have another div that has some kind of text in here that shows what the last status of the pizza is and how long ago it happened so maybe we include the chef who created it so we have that Chef attribute for the user's name and we can say they started whatever the status of the order is so Pizza status to lower case so if it's oh Andrew started checking your order Andrew started baking your order so Andrew started blank your order and then we should have some kind of time element too so Pizza uh we'll call this like last updated and for this we'll wrap this in a span that's underlined and semi-bold now this last updated attribute we don't have yet that's another appends that I think we should add to the pizza model so inside of the appends array let's also add last updated and I want this to be like I don't know like six minutes ago or 12 hours ago or whatever and so in order to do that we can actually uh well first we'll create the attribute model so get last updated attribute and this will be returning back a string we're going to return back this so we get the pizza model and let's get the updated ad uh timestamp and by default the timestamps from a laravel model the updated out and the created ad are carbon objects so they use the carbon PHP library and so we can use methods on there to manipulate the data that comes out so we can call diff for humans on it and that will actually give us a difference between the current time and whatever the time underneath the updated attribute is currently at so that'll give us exactly what we're looking for and then we can go ahead and use that in the component okay so let's go ahead and see what this looks like so far okay so we see that we have our chef's name and they started baking my order an hour ago so that lines up perfectly with the last time that this order was updated but we don't have our status tracker up here yet so let's go ahead and create that so let's create a div with a nice border around it and I need to go through each of the statuses and set a class depending on whether or not the current object has that status associated with it or if it has already passed that status so what I mean by that is let's let's start out with an array of our possible statuses and then we need to create a div for each of these statuses so let's go ahead and map those out to a status and an index and we'll return back a div with the key set to the index and we need a specific class name generated per div because if they were all the same name they're all going to have the same style but that's not what I want I want each div to be different depending on what the current status of the order is and then inside of these let's display a number for each of the statuses this is going to be set to the index plus one because we start out with a zero index but I want the first number to be one and then we just display the status underneath of that so okay what we need to do is we need to start generating this class name for each of these divs so let's base it on a method instead so this will be unique per of these five status divs we'll call this method get class and it'll take in that status and that index and for now let's just return a list of the same classes so if we go ahead and replace the class name with this function so get class and we pass in the status and index to it what does this look like on the front end okay well we're getting somewhere so we see we have each of these five divs broken up we can kind of see the the text underneath of them if I highlight it but right now it's because there is no background on each of them so we need to start working on what each of these looks like so let's set this string of classes I want this to be I want this to be kind of like the base of each of these sections so we can call this base classes and then I'm going to add on specific classes depending on what the status is that's being passed to me and what the status of the actual Pizza is coming in as well so that should probably be our prop I don't need the whole pizza object I just need this status associated with it so we'll call this current status that's that's the prop that's passed in and I can reflect that in our show component as well so current status is pizza status so now let's go through and think about the different classes that are going to be used whenever this method is called on each of those five divs so okay first we need to denote what the active status is so to do that we can say all right if the status that's being passed to us is the exact same as the current status then we can go ahead and return base classes and we'll add in some styles that are associated with an active status state so how about a red gradient and a bit of a pop out with this scale here now if the status has already passed through so if it's if it's in the middle we need the two before that what styles are those going to have and how do we find them well we can say if the statuses index of based on the current status is greater than the current index We're looping over that means that these are below the currently active item so we can return base classes and then some styles that would give an appearance of all right these have finished up so how about a dark blue gradient and the default are the remaining statuses the ones that are after the current active item so again we can return base classes and then tack on a style associated with that so I think for that we can do a light blue gradient so let's go ahead and see what this looks like now on the front end okay that's looking pretty good so we see these two here have already finished up we have an active class in the middle and we have these two that have yet to start but we do have some slight adjustments we need to make so this needs to be rounded over here and this needs to be rounded over here and this border needs to drop off as well as this border here for the active state so let's go back and rethink some of our conditionals here so for the first one that's pretty easy if the index is the first index then we need to add to the base classes to round that out now I feel like in my comments people are going to be saying if you just use vanilla CSS as would not be an issue but I like my life difficult and I like Tailwind so that's what I'm using here and that's why we have to go through these conditionals to conditionally build the style for each div there also might be an easier way to do this with Tailwind but again just making my life more difficult we can see that we have the left now rounded out we need to replicate that on the right hand side so instead of it being the first index we need to say all right if the current index is the same as the length of the statuses minus one which would be the last index of this then base classes needs to equal base classes replace border R2 with rounded are full the reason that we're using replace here instead of just adding on to this like here is we also need to get rid of the border that was on this right side here so it's it's kind of getting rid of both of these things at once and so the only thing left that we need to adjust is the border on the active status section so let's head on to the current status conditional and we can just call Base classes replace like we did above except we're replacing border R2 with nothing so just get rid of it alright and our front end is looking solid as far as design goes and we're almost done with this the last remaining piece that we need is I want to have this live update so right now if we go back to the order section here this is the same order and we change baking to checking let's go ahead and save that back on the front end we don't see any kind of update until we hit refresh and then we can see both the status itself and the little timer down here has changed but it stays the same it only updates if I refresh and then I get some new data but I want this to happen in near real time so there are a couple ways to do this based on difficulty so if we wanted to do this near Real Time with communication from both the back end and the front end we could use web sockets if you want to just a one-way connection near real time from the back end to the front end we could use something like server sent events but in all honesty because we're using inertia and this doesn't need to be near real time I'm just going to opt for an easy method which is just polling and this can actually be fully implemented with just a couple of lines so normally you might think oh okay well I need to create some kind of interval in my component and then every second or a few moments I need to go and fetch some data from the API and swap it out with what's in here and this is the case but inertia lets you do this really easily and I'm about to show you how so like we said before we need to set an interval in here to pull every x amount of time that we want to so let's create a use effect hook and this is going to create a set interval that will fire off let's do every second you could probably do every five or every 10 seconds but because I'm doing this locally and I'm really not that worried about hitting this endpoint multiple times we're going to do this every second and the dependencies for use effect are empty so that this only runs once and then I'm also going to want to remove this interval whenever the component is navigated away from or destroyed just in case so let's go ahead and say this is const interval and on our destroy return we're going to clear interval interval okay so what do we need to do each second that happens so thinking about it you probably want to be able to fetch the data and then replace what's in the component with the new data and that's the case but believe it or not it's a one line to do this in inertia so all we need to do is use the router object from inertia and call reload and then we pass in an array of options so using the only method which takes an array we call the props that we want to have reloaded in the page and that is it by using router reload and saying all right I only want to reload the pizza prop that is in here so that'll get us the ID the status and the chef and the last updated ad and all the data associated with this particular model this means that every second behind the scenes inertia is going to call the same endpoint that was called to render this component but only get back the data that is needed in this case just the pizza object and then it's going to hot Swap all of the data associated with that prop into the attribute and components below and give us a basically live reload so let's see what this looks like so okay I'm back on the front end and let's go ahead and open up our Dev tools if we go to the network tab here you can see every second we are hitting that end point and if we open it up and look at the response back we can see that we're getting the component back and the only props associated with it now yes we are only using the pizza prop in general but if we had more than one we would only see this object as one being passed through as the response in these API calls so how do we know this is happening in near Real Time with our updates so let's go ahead and open up this in like a split view mode okay so on my left I have the order in the dashboard and on my right I have my view showing my pizza status now let's go ahead and update this to ready and all right we saw that we had an instant save and then we saw on the front end that we had a near real-time update to the ready status and this works backwards as well so if I accidentally mess up the order and drop it on the floor and I need to go back to prepping I can save that and it went back to the prepping status almost immediately and then as each second passes we can see that our time is going up but this data here that's being rendered is from the actual back end of the application it's coming from the database as the source of Truth and isn't just being updated on the front end so yeah now I can go through each of these steps until my pizza is ready and yeah so this is our Pizza Tracker and we created with laravel and react with the help of inertia I hope you enjoyed putting this project together with me let me know in the comments if you have any suggestions for any new topics or projects or any Frameworks or libraries you'd like to see me build something with and as always thanks for watching
Info
Channel: Andrew Schmelyun
Views: 13,623
Rating: undefined out of 5
Keywords: php, laravel, inertia, react, javascript, tailwind, php tutorial, laravel tutorial, inertia.js, inertiajs, inertia laravel, inertia react, inertia tutorial, react tutorial, react laravel, php react, tailwind laravel, full stack laravel, laravel tutorial full stack, full stack php tutorial, full stack app example, build full stack app, pizza tracker
Id: hWFP9DeB7KA
Channel Id: undefined
Length: 59min 14sec (3554 seconds)
Published: Sat Sep 02 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.