Build A Ride Share App: Full Stack Tutorial with Laravel and Vue

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey everyone Andrew here have you ever wanted to build a ride share app like uber in this video I'm going to go step by step and show you exactly how to do just that we're going to use two modern and popular Frameworks to build our project laravel and view which are powered by PHP and JavaScript respectively alright let's get started before we actually start writing code though let's take a minute and figure out how a Rideshare app should work first a user needs to authenticate with the application preferably with something simple like their phone number then they should choose whether or not they're looking for a ride or they want to drive and if they're driving they'll be put into a waiting area to wait for a ride request if they're looking for a ride they'll have to enter in their desired destination and then a notification will be sent to any available drivers drivers can either accept or deny the requests and the first one to accept it will be given the trip the passenger gets a confirmation and the driver starts making their way to them they based on the GPS info from their phone's browser once the driver makes it there the passenger gets in the car and the trip starts they are driven to their destination get out and the trip ends the driver gets back into their waiting area and the passenger goes about their day so you can see we have a lot of working parts here some communicating via API calls some real-time events some mapping and so on let's talk about how we're going to break this up because of the complexity of this project it'll be easier to tackle one half first and then the other our back end will handle things like authentication data storage and sending notifications while the front end will handle user input navigating drawing maps and receiving notifications we'll build each one out separately and then connect them together towards the end I think it makes sense to start with the back end first so let's get into it so I have this directory for our code set up and I've already created two folders in it one for the back end and one for the front end again we're keeping these as separate code bases that will tie together in the end so let's go into our backend directory and we're going to create a new laravel project in here using composer so composer create project laravel laravel and the current directory okay this was installed successfully so let's go ahead and open it up in our editor the first thing that we need to do is determine what models are going to be used in this application and that depends on the data structure that we are expecting to use so if we go to app models we can see that laravel by default provides us with a nice user model for users of our application and we will make use of this considering that we are having people log in to this Rideshare app we're going to clean this up a little bit first if we scroll down we'll get rid of this email verified attribute because we will not be using email verification for this user and then if we go to the database folder of our application go to migrations a migration is created for our users table corresponding to the user model that we just looked at we can get rid of the email verified attribute because again we're not going to be using it and instead of an email string here we're going to be using phone because we're going to be authenticating users with this application through their phone number and instead of password where we don't actually prompt the user for providing a password when they're logging in most applications that use phone numbers for logging in will text you some kind of one-time use code that you use instead so let's rename password as login code and it'll be nullable because by default this will not have a value in the user model and after a user successfully logs in we want to remove it as well so it's not always present in the database all right this looks good let's close out of this and we'll think about the other models that we will need in our application so let's open up a terminal and we can use php's Artisan command that comes with laravel to create some new models for us but let's think about the data structure of our application we have users which are authenticated into the application but whenever a user signs in they're going to be prompted if they want to be a driver or a passenger passengers can just be typical users we don't need a new model for that but we should need a new model for drivers because they're going to be holding additional information things like their car year maybe even a driver's license or a rating and sure we could put all these additional columns in the user table but it makes more sense to split that out into a separate model that's just attached to the user as a relationship so let's make a model and we'll call that driver and we can actually pass in the migration flag here so we'll create both the model class as well as the migration class in one command okay perfect now let's create another model and think about what else we need well each time that a passenger requests a ride somewhere we'll need to store that information in the database where they're going where they currently are who's driving them and you know stuff like that so let's create a model for this and we'll call it trip so there'll be multiple trips associated with a passenger or a driver and again we'll create the migration alongside of that and honestly I think that's all we need for this application a user can be a passenger or a driver and a driver holds additional information for those users who are drivers and then trips hold all of the information regarding rides to and from Origins and destinations for both passengers and drivers let's open up each of these migrations that we created and we'll work on the structure for these tables so by default laravel creates an auto incrementing ID and using timestamps it creates two dates one for created at and one for updated ad which automatically are populated whenever a model is created or updated so between these two is where you'll usually add in additional fields or columns for this database table the first thing that we need to add is an association between drivers and users so this can be done with either an unsigned big integer called user ID or in laravel instead what we can do is call table for an id4 and then pass in the model that is a relationship to this particular tables model so we can use the user model class and it's the exact same as what we saw up here with user ID besides just kind of looking better laravel does some stuff behind the scenes where if you use a different column name or a data type for the primary key of this model it'll automatically make that Association when you do this migration so let's get rid of this commented outline and add some more Fields so I said before the driver's table is mainly for storing information about being a driver so that is car information so let's add a few tables for their car we'll give it an integer for the year a string for the make and model how about another string for the color and finally a string for the license plate so that way on the passenger screen they can see all right my driver is coming through with a 2019 Honda Accord it's white and the license plate reads fl1234 everything's looking good for this model we don't need to do anything with the down method here it'll just drop the entire driver's table if the migration is ran in Reverse which is exactly what we want so let's exit this and we'll open up the trips table and just like our driver's table trips are also associated with a user so we can do that for an id4 user class but trips are also associated with a driver so a complete trip has a user which is the passenger and a driver which is the driver so we'll create another for an id4 but this time with the driver class now thinking about this I want to have some kind of state with the trip so I want to know if it has started yet I want to know if it is currently in progress and I want to know if it's been completed this way you know down the line if I wanted to get all of the trips to have been completed as a passenger I can get that also I only want to send notifications about the trip that I'm currently taking so we'll add a couple Boolean Fields here so let's do one for is started and by default that's going to be false and we'll add another for is complete and that'll also be a default false so so when a trip is created it has not started and is not complete but through a combination of these two flags we can understand what part of the trip our passenger is on speaking of what part a trip is at we also need to know where a trip is taking place so it needs to have both An Origin and a destination and we need to keep that as a pair of coordinates as latitude and longitude now I could create a decimal column for latitude and longitude but I'd need four of them because we're storing both the origin and the destination instead of having all these columns I'm instead just going to store the location data for both of those as a Json object so we'll have a Json object for the origin and it's nullable by default and we'll have another Json object for the destination again nullable now I think this is all I need but I also want to um store the destination's name somewhere in this trip so whatever API I use like Google Maps for instance to pull trip destination off of it will usually provide me a name of like a street corner or a store or business that a user wants to go to and I'd like to store that so that it's displayed on the passenger side whenever they have confirmed their trip so let's create a new string column and we'll call this a destination name and it's nullable because by default it doesn't exist there yet not until a trip has been confirmed by a passenger and I think the last thing that I need to store is one more pair of coordinates specifically the drivers because I want the passenger to see in near real time where their driver is at it'll help them understand how far away they are so they can get ready to leave and it can also show as they're driving to the destination where along the path they're currently at so we'll call this uh driver location simple enough okay and I think that's all we need for our trips table so we can exit this now that we have finished our migrations we need to populate the database with them because right now my database is empty if we open up a terminal we can run PHP artisan migrate which will take all the files in this migrations folder and go one by one adding or adjusting the tables that are present in them in whatever the up methods have so now if we go back to my database we can see that we have all these tables here with the columns present that we had specified in those migration files let's clear out of this and exit the terminal because we don't need that right now and before we start diving further into this I want to make a couple of quick adjustments to the models that we created the trip and the driver so let's start with the driver and we're going to do a few I call these preliminary things whenever I create a new laravel model and the first is that we're going to add a property protected garden and it's set to an empty array the reason that we're doing this is because whenever we create a new model using laravel's what's called Mass assignment if we don't have this attribute in here it will cause an exception to be thrown that the data that we're putting into this model can't be accepted unless it's basically done one by one now alternatively we can specify each individual field that we want to be Mass assigned by using a protected fillable array so we could say Okay I want my you know the year to be fillable and the make and the model and that's fine if you want to specify these out individually but most of the time it's just easier to set the guarded attribute as an empty array that way you're saying all the attributes in the database table for this particular model are Mass assignable and we're going to do the same thing for trip protected Garden is equal to an empty array the next thing that I want to set up is the relationships for each of these models so we talked before let's open up the user one as well so we talked before that a driver is basically just an extension relationship to a user it adds additional attributes and then a trip and a trip is associated with both a driver and a user so let's define these relationships in the code let's start off with the user model so let's scroll down to the bottom here and we will need to add in some public functions for each of the relationships and the function name will be the relationship name so to start out let's do driver so a user can have a driver model associated with it and for that we can do return this as one and pass in the drivers class the reason that we're doing has one here is because it is what's known as a one-to-one relationship a user can only have one driver model associated with it additionally let's scroll down here a little bit more is a user can have multiple trips associated with them so you know I'm not signing into my application just to flag down a ride once so I can do return this has many and then pass in the trip class and now we can go into each of these classes and add in their relationships so let's go with driver I will Define the inverse of the driver relationship that we added here in user and call user for the driver so a driver has a user associated with it and we return that by calling this belongs to the user class and then like our user drivers also have multiple trips associated with them so we can return this as many and the trip class so just like our user a driver can have multiple trips associated with them and then finally the trip model so for this we'll use public function user so a trip has a user associated with it or we return this belongs to the user class then we also need to define the inverse of the driver model so public function driver return this belongs to a driver class all right this all looks good so let's exit these models here so what do we need to do next well we can start building out some of the routes for our application and this is going to be an API so we're just going to focus on the api.php file here this is the API Group of routes that comes with laravel there's also a web dot PHP this is associated more for web facing routes but we're not going to be having any of those so we really don't need to focus on this file at all now you can see here that we already have a route set up for us as an example and it's using this middleware auth sanctum and that's because by default with some of the latest versions of laravel a package called sanctum is included with it if we go to the documentation for this package laravel sanctum it says that it provides a featherweight authentication system for single page applications mobile applications and simple token based apis which that sounds perfect we are building out a separate front end that will be built as a single page application we don't have to add any additional packages for the authentication of our API and we can get rid of this route that we have as an example because we're not going to be using that right now the very first route that we need to do is we need a way for someone coming in to authenticate themselves into this application remember we want to get a phone number from a user and give them authentication to the rest of the application so let's create a route and we're going to be posting to it we'll call it login and we need a controller to go along with this route we can do that by using PHP Artisan in our terminal make controller and we'll call this just login controller so it was created let's go ahead and open that up and you can see it's already been scaffolded out from laravel and we'll save this for later but what this array expects is our login controller class and a name for the method that's called whenever this route is posted to let's just say that we're expecting it on the submit method now going back to our login controller let's create that method so public function submit and here's where we can perform the login now this is a little bit different than a standard login because we're not taking an email address and a password and authenticating a user through that we're instead taking a phone number and then sending out some kind of one-time use code that a user will have to submit with a follow-up request so let's step through here and do some pseudo code and kind of understand all the steps that will be needed in this particular method so the first thing that we need to do is probably validate the phone number and then we need to find or create a user model associated with it send the user a one-time use code and then return back a response that just gives some kind of success message and lets our front end know that we can proceed to the next screen so let's start with validating the phone number we can start that out by in the submit method we can use the request object and pull in the current request that's being sent over if we call the validate method on that we can pass in an array consisting of key value pairs where the key is an attribute and the value are rules that are passed in to perform validation on that attribute so if we're expecting a phone attribute to be passed in that's probably the only thing that will be passed in we can specify a few different rules separated by the pipe character to perform validation on this laravel has quite a few built in and the ones that we'll probably be using are definitely required so if the phone attribute is missing we'll immediately get an error back but with this we could have users passing in you know letters or dashes or any kind of other characters so it also should be numeric and then finally we should do Min 10. so a phone number will be a required attribute that is numeric with a minimum of 10 characters this should be a good Baseline to account for most cases now unfortunately laravel doesn't have a built-in phone number validation rule at least at the recording of this video so okay we have our now validated phone number so past this point we have a request phone attribute that is numeric with a minimum of 10 digits and we'll use that in order to find or create a user model so we'll call user is user first or create and this expects an array of attributes where it'll first try to find a user with these attributes but if it doesn't find one it will create one instead so we need to find a user with the phone number that was posted with this request and if for some reason a user can't be found or created let's go ahead and return a quick response back it'll be a Json response and we'll just give it a message with the value could not process a user with that phone number and it'll return back a 401 error this way our front end can handle you know the edge case that for some reason a user can't be found or created with that phone number that was passed in so now it's time to send our user a code to their phone and laravel again provides a super helpful method with this if we use the user object we can call the notify method on it and this method comes from if we open up the user model this tray at the top notifiable this allows us to easily send notifications via slack email web hooks whatever and in this particular instance we're going to be sending a text message with twilio before we get started too in depth with this let's go back to our code base and we need to do a few more things first so notify expects a class a notification class to be passed into this method here and if we open up at the terminal we can create one of these using PHP artisan so we can say PHP artisan make notification and we need a class name usually the naming convention for this is the action that's being taken for this notification so in our case that is login needs verification so it created our class for us and if we go ahead and open that up we can see that it's scaffolded out a pretty large class here so by default this is a mail notification so this via method here returns back an array of services that this notification will be sent out to our delivery channels is what they're called here and again by default that's just mail and then if we scroll down we see this two mail method which represents the actual notification that's being sent out so it's a mail message class with the line and action and another line and so what happens is that in this via here we have for each of these delivery channels we need a method in this same class to represent the actual message that is being sent out but we're not using email we are again using text messages through twilio by default level doesn't include that functionality with it so we're going to have to go to a third-party package on this site here laravel notificationchannels.com we can browse different channels that are used with laravel notification classes so they are organized by category so we have push or web push Messengers SMS and VOIP to-do list and miscellaneous we're going to be looking under SMS and VOIP specifically twilio we're then given a package readme with a link to the GitHub repo or the package that we need to include this notification in our application so let's go ahead and go to the installation section and we need to just run this compose a require line in our terminal so let's go ahead and copy this over open up our terminal again and paste that in here all right that is good to go and it looks like we need to add some attributes to our EnV file in order to get this fully set up and it looks like it'll be these three here so let's open up our EnV file and we'll just scroll to the bottom and paste these here and go to twilio so we can get these copy over your account Sid as well as your auth token into the spaces listed for auth token and account Sid in your EnV file okay that's all I need to do to set up twilio to send out those notifications now I just need to adjust my notification class in order to send it out through a text message so in this via array that's being returned instead of mail we're going to be calling twilio Channel and we can get rid of the two male function here and instead replace it with public function to twilio it takes a notifiable object as the argument and the notifiable here if we go back to the login controller is this root object that notify is being called on so this is a user model it's this specific user model that has this phone number and that is what is being accessed here in notifiable well what I want to do is send out a text message to this user based on their phone number that gives them some kind of login code right so in order to do that we can return a new twilio SMS message and Tack on this content method that will contain the string being sent out to them let's say uh your and ruber login code is we need to create that code we'll just say login code is a random number between so it's a six digit random number that's our login code so your andruber login code is login code don't share this with anyone okay great but um this the login code needs to be associated with the user as well because when they post back in to verify we need to have something to to compare it with so we need to store this on that user model well we can just call notifiable update which will update that original user model and we have this login code column in the database that we had created through our migration that we can pass this login code into so the code is generated it is saved to the user and then it is sent out to the user via a text message so now the last piece of this is if we go back to our login controller we need to pass in that notification class to the notify method so login needs verification class oh actually it is new login needs verification so it's and it's it's in instantiated object not just the class oh actually before we go to the last section here we need to open up this user model and there is an attribute that we need to change here so by default twilio looks for I think a phone underscore number column on the user model to send that text message to it tries to to find this automatically we have our users phone number saved as a just phone column in the database from our migration I don't want to go back and change the migration because then we have to redo the migrations again and I also don't like phone underscore number we can override this by calling public function route notification for twilio and return back the value that we want this notification from twilio to be sent to so we can just return this phone so the phone attribute of the user model and this will be true for any notification that uses this twilio channel uh as a via method so we have our notification up and running the user is now going to be notified whenever they've posted their phone number to this route now we can just return back a response and let our front end know that everything so far has gone through good so we'll just return a response Json message and we'll just say text message notification set so this could just be like a toast pop-up that happens in the front end or it is just something maybe for the logs that will be seen either way we get back a message that everything so far is good the text message was sent out now we're just waiting for another request to be posted to verify that code and now speaking of verification let's handle that part so let's go back to our API we're going to create a new route it'll be post verify or actually let's do Post login verify since technically it is part of the login controller or login flow and we'll use the same controller the login controller and we'll just call this method verify so let's go now back in the Locking controller and create that public function verify again passing in the requests now this should be just as straightforward as the submit method from earlier so let's start out with pseudocode again let's validate the incoming request find the user is the code provided the same one saved if so return back a auth token and auth token if not return back a message alright so again let's just take this step by step so request validate and an array of attributes we'll expect the same phone number again so required numeric min 10. because you know at this point we don't know who we are validating against we need that phone number to be sent by the front and again and we also need the login code which is required numeric and we can take this validation uh pretty exact by using between and providing A Min and Max which we know because we use these two values to generate the code in the first place so this is between 1 1 1 1 1 1 and 999 999. so now we need to find the user that has both that phone number and that login code so user is user where phone request phone and where login code is request login code and this will be the first user that we find so if the user has been found if there is a user that has that phone number and that login code then the user's phone number has been verified so we can return back an auth token associated with that user because we're using sanctim we can just return the user object and Tack on the create token method to it and this expects a name for the token we're not really displaying that publicly so we can just use the login code as the name of the token and we'll return back the plain text token property of that token object so that way we just we are just getting back a token as the response and then if that user is not found well we need to return some kind of message back to the front end so let's return a response message and we'll just say invalid verification code and it's a 401 again actually before we return back the token we should update that user model and get rid of the login code so that way it just it can't accidentally be used again so we'll set it to null okay so let's let's go ahead and see this in action let's see if our work is paying off so far I'm going to open up a larger terminal and I'm going to use this command line tool httpi which allows me to use one of these two commands HTTP or https to perform requests on different endpoints it's like curl but way nicer first I need to serve this application so PHP Artisans served and I'm using sudo here so I can specify the 80 Port because it just makes things easier okay so we have the server running now let's open up a new tab so we can call HTTP post localhost API login and phone is equal to my phone number and uh oh we're getting back an error let's scroll up to the top and see what the message is field name doesn't have a default value insert into users okay so if we open up our code again and open up our user migration you can see that we have a name column here and by default it is not nullable so it's expecting a value but we are not passing one in let's go ahead and set this to nullable now I don't want to just go ahead and remove that column because I'll probably end up using it whenever a user signs up to be a driver I can commit this change if I open up a terminal and run a PHP Artisan migrate refresh and let's go back into the larger terminal we'll clear this out and try this request one more time and we're getting another error let's scroll up to the top of this one and see we have now field phone doesn't have a default value it's only inserting updated and created at into our users table well if we go to login controller we see that it's trying to push the phone in here let's open up the user model and oh okay I forgot so remember at the beginning we talked about fillable and guarded and so fillable attributes are the only ones that are Mass assignable so right now this is only setting name email and password as mass assignable we're going to need login code we're going to need a phone let's just change this to protected Garden that'll just make life a lot easier and then down here in Hidden we're not going to be using a password but I do want to keep our login code hidden so any requests that come through to grab user information that login code will not be present okay let's try our request one more time clear this out okay we got a notification back and that Ding you heard is the side of my phone getting the text message for the login code let's go ahead and add that in let's go ahead and add in our verify request with that login code and see if it works so now we're posting to login verify the phone number Remains the Same and login code equals six five one three six zero and perfect we have gotten a token back to use in our application so that means our login code was successful I've just out of curiosity I wonder what happens if I try to use it again invalid verification code perfect so the code has already been wiped out we can't use it more than once now let's go ahead and create a route to make use of this auth token and see it in action okay so let's go back into our code base and in our routes API file we're going to create a new route it's a get and we'll call it user and this is going to return back the authenticated user's information so I don't need a whole controller for this instead we'll just use a closure function and I want this to return back the request user object and we can use that illuminate HTTP request class as the function argument and if we try to run this in the terminal so HTTP get localhost API user we we get back nothing right now and so this would be where the body is and we get back an empty response and that's because there is no user associated with our request so in order to get this user object from the request we need to add the middleware auth sanctum into the request and we need to provide it an authorization header containing the token that we created earlier so going back into the terminal we can run the same requests but add in an authorization Bearer header with our token that we created so now we see the body is the user object that is the user associated with the token that we had created earlier now we're going to have multiple routes associated with tokens so instead of tacking on this middleware to each one of them I'm instead of going to create a new route group that will all be under this middleware so we can do route group and it takes an array where we can specify middleware is auth Sanctum and then that accepts a closure as the second argument and our routes underneath that we can get rid of the middleware on this and this works the exact same way okay so that's a great little proof of concept but now we need to add more functionality to our API so we have the ability for users to log in and we know that we can use the token that we get back to get information about that particular user to get data associated with that particular user back so we need to think about what is going to happen in the application what API endpoints are going to be hit that we need to create in this back end well whenever the user signs in for the first time remember they're presented with a screen that allows them to select whether they want to be a driver or a passenger and if they select driver then we need to know if the user is a driver already and if not we need to get information from them to make them a driver so there's two routes right there so we need one to get information about a driver or the user being a driver so let's create a new get route and we'll just call this driver and this will use a controller that we will create in a minute and then we will also use a second route we'll do a post route and this will post to driver and that will update the driver's information so we'll get a driver or we'll update a driver or create one so let's open up our terminal here in the IDE PHP artisan make controller and obviously we'll call this one driver controller so now we can specify that this controller uses the driver controller we just created and we'll call this show or the method show and this method will be update let's go ahead and open up that driver controller and create those two methods so we have a public function show and a public function update and both of these will take a request object because this is wrapped under that auth sanctum middleware we're able to pull out the user with this request which will help us we need to return back the user and Associated driver model now we could just return back the associated driver model we could do return request user driver which will get us the associated driver object but if the user doesn't have a driver associated with them it would just be null and I I really don't like working with either just empty Json objects or null values on the front end I'd rather determine if a attribute on a property is null so instead of just going to return back the request user but I need to know if that driver is part of that user so instead I'm going to create a variable called user and that will hold that request user and I'm going to call the load method on the user and what this does is it takes a relationship as a string so in our case the driver relationship and this determines if there is a driver relationship available on the model uh it's called on there is and it will attempt to load it and inject it as a property onto our user object so coming back if we return this user there will now be a property on this user object called driver which will either be null or it will be the associated driver object with this user so on the front end we can determine if a user's been a driver or not and move on with that information now if they're not we need to get back information from the user and create some kind of driver Association or driver Associated model for them and so for this I'm thinking we have just a simple form year make and model of your car your license plate number and stuff like that so let's validate this request with the information that we expect to get back so we'll get the year first and that is required and it's numeric and we probably want this to be a relatively modern car so let's do values between I don't know uh 2010 and 2023 which is our current year actually some cars could be 2024 models so let's do 2024. so now that we've validated the incoming input we need to grab the user like we did in the previous method so that we can create or update this driver object associated with them so the user is the request user and first let's update the user's object which the only attribute associated with the user in this is the name so we can do user update request only name and now we either need to create or update a driver associated with this user so we can do user driver and remember this gets back if we if we call this as a property on the object this will give us back the driver object from eloquent but if we call it as a method as a function we have access to the eloquence Builder methods so I want to update or create this Associated model and this takes an array consisting of keys and values which we can get from the requests object and the only method and we want the year make model color and license plate that was passed into us and once that happens successfully we want to just like the above method grab that driver object or that drive a relationship now and attach it to the user model and we're going to go ahead and return that whole user object so whenever this endpoint is hit we validate the incoming requests we update the user's name we update or create a driver associated with that user tack it onto the user object and return that whole user object and we can go ahead and test this out in our large terminal so we'll keep that same authorization Bearer token here because we'll need that in order to make this request because again this is under that auth Sanctum middleware so we get the driver we hit enter you can see that we have the user object coming back to us and driver is null that's what we expect there is no driver associated with this now if we instead post to this same route with just an empty body you can see we're getting this redirecting to http localhost and that's because the validation that we set is being hit but this request thinks that we are visiting from a browser and is trying to redirect us back to the previous page instead if we add in an accept application Json header we'll get back Json from the validation so we can see here we have an object consisting of Errors which is itself an object consisting of the different fields that it's expecting to get back so all of these fields are required and they were not sent in with our request so instead let's go ahead and add these fields in to this post request and see what happens okay now so we're getting back that user object again but this time we have a fully filled out driver model which is exactly what we expect and so now even if we get that driver request again the same thing appears which is our user that's authenticated with the token and its attached driver model okay so if we clear this out we've covered two of the three models that we created for this application user and driver so the last one that we need to cover are trips and I think this will be where most of the functionality of this API lies so let's think about the routes that are associated with trips and how that kind of fits into our application so thinking back to how we want this application to work after a user selects that they want to be a passenger instead they put in information about where they want to go and where they currently are so that should be the kind of Genesis of a trip and we'll need a route to capture that information and save it in the database as a model object so let's create a new route it'll be a post route at the trip endpoint and we'll have to create a new controller for this let's go ahead and open up our terminal and like the last controller PHP actually let's clear this out first PHP artisan make controller drip controller that just makes the most sense so now we use that trip controller and we will call this the store method now let's go ahead and open up that controller and create that method public function store add in our request parameter or or argument and we are good to go so we need to validate information again from a request and then create a trip based on that and so we need to again validate and let me open up our trip migration again to see what uh to see what columns our database has that we might need for this so the user we're not going to need that that will be through our authentication token the driver the trip hasn't taken a driver yet hasn't been accepted by a driver so we're not going to need this is started and is complete we are both keeping the default values for those because it hasn't started and it isn't complete yet so it looks like we'll need these three this origin destination and destination name the driver location we don't have a driver again so that can remain null so origin destination and destination name let's go back to our controller and so once these are validated we need to create a trip based off of them and it's a trip for a user who is acting as a passenger so we just use the request user and then the trips method not the object property the method just like we did with the driver earlier and create and we are creating a trip based on [Music] the values that we validated so origin destination and destination name and let's just return back this trip that we created to the client okay so we have the ability to save a trip in the database but we need the ability to get a trip from the database specifically a trip that is associated with the user that's currently authenticated and the reason for that is you know we don't want every user being able to access every trip in the system that would not be secure so let's go back to the routes API file and we're going to add a new route here route get trip and we will call Trip as well in these curly brackets and laravel will automatically inject the appropriate trip model based on the primary key of that model that's added in so we'll use the same trip controller class and this method will just call show so now going back to the chip controller let's exit out of this migration we're not using anymore let's add a new method public function show we'll use our same request object and we will also be using a trip object so this trip model if we just return trip this will return a whole trip model this will return a whole trip model based on whatever the primary key is that is added into this route here so if we do slash trip one it will return the trip that has the primary ID of one but again we don't want to just return this trip we want to validate we need to make sure that the trip is associated with the authenticated user and so we'll need to do this two ways because the trip has a user ID as well as a driver ID associated with it so if the request is coming from the driver or the passenger we should return the trip otherwise we can just return a 404 so to start out with we can say all right if the trip user ID is equal to the request user ID then we can go ahead and return the trip and if the trips driver ID is equal to the request user driver ID then we can also return the trip and otherwise we will return a response back a message that says cannot find this trip and it's a 404. but there is a quick problem and that's with this line here the driver of both the trip and the user could be null because a trip could not have been accepted yet by a driver which means that it wouldn't have a driver associated with it and the requesting user might not have a driver associated with it so before it even gets to this 404 response it'll throw an error out up here so we can combat that by just wrapping this in another conditional and saying all right if the trip has a driver and the request user has a driver then we can check this whole conditional otherwise it just Returns the same 404 down here okay let's keep this going so back in the API let's think about the flow of the application when it corresponds to trips so right now just as an overview we have get a driver's information updated driver's information we have create a trip we have get a trip but we need to create some routes in order to adjust the trip as it proceeds through the different sections the different screens in our front-end application so off the top of my head we need a route for when a driver accepts a trip we need a route when a driver starts a trip we need a route when a driver ends a trip and we want to be able to update the location of the driver in kind of near real time so we'll need another route to you know update that driver's location all right so let's go ahead and add some of these in so we will create all of these as post routes and they're all going to use this trip trip as the base so using the laravel route model binding we will have a trip associated with it just like we did in the trip controllers show method so okay I said trip uh accept and we'll just call this trip controller class accept and let's go ahead and copy this line because we'll use it a few different times so we'll need one two three and four so we have accept start and and the last one updates the location we'll just call it location now you might be asking yourself why why are we splitting these out into four different routes when we could just have one single route that performs an update on the whole model and that's a valid point but the reason I'm splitting this out will become more clear as we flush these out so just bear with me let's go ahead and add these methods into our trip controller class so we have a public function except with our request object as well as our trip object and then again we can copy this for start end and location okay so our accept method is a driver accepts a trip start is a driver has started taking a passenger to their destination end is a driver has ended a trip and location is update the driver's current location so all pretty straightforward the reason that I split these out is that each one of these will have a separate event that gets fired to notify the front end and update that information in real time using websockets again I'll go into more detail as we flesh these out more I just want you to kind of know where we're going right now Remember by default a trip doesn't have a driver associated with it but when it's accepted that means that a driver has taken that trip and so we need to update that trip model with a appropriate driver ID so we can call the update method on our trip model which takes an array of attributes and we can update that driver ID to be our request to be our request user's ID so this request right now is coming from the driver using this application so their token is the one that's associated with this request user and it is their ID that is now associated with this trip as being the driver and then we'll also take note of their current location and we will update that with the request driver location attribute so we are expecting uh a driver location on the request so we'll make that a required attribute okay and after that's done we'll just go ahead and return the trip back to the client except actually let's load in some of these relationships to this trip so I want the driver's information because that way we can provide it to you know the passengers they know all right who is going to be my driver whenever this trip is accepted but not just the car information we'd also like to get the user's name as well but that's stored in the user model instead of loading in the driver and then doing something like trip driver load user because remember the user is a relationship to the driver we can do tripload driver dot user so we'll have a driver object on the trip and then a user object on the driver now let's go down here to this start method so a driver has started taking a passenger to their destination remember back to our migration [Music] is that we have these two Boolean Flags is started and is complete so I want to update our trip model and set is started to true so now this lets our front end know that all right the trip has started a driver has picked up a passenger and we are going to the destination and then just like the above accept method we're going to load in the trips driver and user model relationships and return back the trip for the end method it's almost exactly similar to this except instead of updating is started we're updating is complete pretty basic right all right and finally for the location we are updating the trip one more time and we're setting the driver location to the request driver location attribute and again like the accept method we are expecting that driver location so we need to validate the requests and make sure that the driver location attribute is required like everything else we will load in the driver and user model relationships and return back the trip okay so we just did a whole lot of coding here it seems like it is a lot of copy and pasted functionality in these methods and you know you might be right there's probably a lot that we can condense down here and and refactor to a single method but for this particular use case I like having these split out I like having these all open and individual so we can understand where the flow of our application is is going and what endpoints are being hit as we progress from starting a trip to ending a trip so I hope that makes sense all right so let's go ahead and try to create one of these trips in our large terminal okay so we have the HTTP request and it's being posted to the API trip method so we're creating a new trip we have the authorization Bearer token here and ready so now we can add some data into this looking back in our controller we need an origin a destination and a destination name attributes the origin and the destination are objects again they're Json that has a latitude and longitude associated with it and the destination name is just a string so let's go ahead and add these values into this request and let's start out with the destination name we'll do something like Starbucks and then for the destination itself we're going to use some raw Json let's do a Latitude as some testing values and the longitude some other value and in the origin we'll do the same with it so uh latitude latitude and a longitude all right let's make this request okay so the request went through but it gave an error and if we scroll up to the top here let's see what the message for it is so we have argument one values must be of type array string given all right and I think this is because we are passing in a raw Json string here for both the destination and you know the origin but the database column is set to a Json column so it's expecting a Json object or a PHP array and in order to combat this what we can do is I think we should be able to open up our trip model here and add a new property called protected casts and what this does is it takes values from columns associated with this model and allows us to transform these before they actually reach the database so for the casts for origin we'll set that as an array and we'll do the same for the destination incoming Json strings from our requests should be serialized through PHP and then that is what is passed into the database which stores it as a Json object let's go ahead and add in the rest of the columns that we'll need casts for this model all right let's go ahead and try this request again so let's clear out of this and we'll try it one more time all right well we get another error and it looks like it's different this time field driver ID doesn't have a default value now I could have sworn I made the driver relationship nullable for a trip model let's open up that migration again it looks like I did not so this is a nullable field and we'll have to rerun our migrations again to make that stick so PHP Artisan migrate refresh but I don't want to redo the migrations for everything because I have a user model and token already set up and I really don't want to go through that process again instead I can pass in this path option here and run just a specific migration file okay so it rolled back the migration just for the trips table and then re-ran it for the trips table our user table should be unaffected so let's try that uh request one more time all right perfect we have a trip that was created and returned back to us with all the fields that we passed in now let's go ahead and try to get this trip so let me clear out everything that's in this request here and instead of making a post request we'll make a get request to localhost API trip and remember we need to pass in the primary key ID for this model to get it back so that is one from the above return response all right and we have the whole trip model coming back to us with the now user attribute attached with it now we currently don't have a driver associated with this trip so we have no driver model associated with it coming back but the rest of the information is here and accounted for I think the last thing that we need to do for our back end before it's fully functional is push out events for some of these endpoints so let's go back into our code we'll exit these migrations that we don't need right now and go back to the trip controller so if we scroll down here whenever a trip is accepted by a driver is started by a driver and the driver's location is updated I want to push out an event that can be consumed in real time by the front end so you know if we scroll up here for example whenever a trip is accepted by a driver I want the passenger to get an instant notification letting them know who's coming to pick them up and we can make this happen inside laravel but we need to do two things first the first is that we need to dispatch event classes for each of the events that we want to be pushed out I think it makes sense to push one out for the accept the start the end and the location update so let's start with each of these in order to create an event class we can use Artisan again so we'll open up our terminal and run PHP artisan make event and we'll give these names that are associated with the event that is coming through so for the accept we'll do trip accepted or the start we'll do trip started or the end we will do trip ended and for whenever the location is updated we will do trip location updated so now we have in our app folder we have an events directory now and we have our four events so what exactly do these do well let's go ahead and open up one of these let's open up our trip accepted class and you can see it has a lot of boilerplate that it starts with so we have all of these classes that are coming in as use statements we have a few different traits up here we have a construct method and we have a broadcast on method that returns a new private Channel with a default channel name now events in laravel are used in a couple of different ways they don't necessarily have to be broadcast out to a front end you can use events with listener classes that allow your application to respond to certain events throughout the execution and if you want some examples of those I'll link them down in the description but we're not using events that way we are broadcasting them out to the front end and for that we will be using all of the boilerplate that is currently in here so in the Constructor for this we should pass in something that we want to be passed through to the front end so if a trip is accepted and a an event or piece of data is pushed to the front end what should I receive as my application that I can make use of well I want to know who the driver is for the passenger and I might want to know where the driver is currently at and all that stuff is stored within this trip that we had just accepted so after we load in the driver and user you know we have this object that contains all that information so we should pass that to the front end and so in the Constructor we are going to expect a trip model and okay what do we what do we do with this well we need to create a property on this event class a public trip and then in the Constructor we set that trip to the one that is passed in so we instantiate this attribute with a trip that is is being passed in and okay so why why do we have this property up here what does it do a public property is available on the event model whenever it's pushed through to the front end so after this event is broadcasted to our front end it will have a trip attribute associated with it that is the entire trip model that we are passing through to this event now I know this this might sound a little complicated right now but believe me it should click once you start putting everything together now back in the trip controller all we need to do is get that trip accepted event and call the static dispatch method on it and then the dispatch method takes in whatever arguments our trip accepted model has in the Constructor so that is just our trip model so whenever this event is dispatched it creates a new trip accepted object from this class passes in the trip and the Constructor adds it to the public property up here and then we'll broadcast it out on whatever is returned in this array now for the sake of this demo app I'm not going to use private channels because we'll have to deal with a whole layer of authentication on the front end to connect to it instead I'm just going to push out these events to a public channel that a user on the front end can instantly connect to and to do that I'll remove that private Channel class and we will return a new channel and we will give it a basic name how about just passenger so whenever this event comes through it's broadcasted out on the public passenger channel that our front end can connect to and pull information from actually you know instead of just the passenger Channel this could be confusing if more than one passenger is signed into the app at the same time so instead we should suffix this with something like their ID so how about passenger underscore this user ID and we will get this user object we'll return a private user property up here and we will expect a user to be passed into the Constructor and set this user as user so now if we go back to our trip controller we will dispatch both the trip and the request user object now on the front end the user will know what their ID is so they can easily connect to this channel but I mean so can anybody else we're going for completion here not for security don't judge me if you want to learn more about securing channels and broadcasting with private channels I'll put a link in the description to the larified documentation around that subject Okay so we've done our trip accepted event now we have three more and all these are basically going to use the exact same functionality that this one has so let's just go ahead and open them up and I won't bore you and speed through this part okay so we have all four of these updated and again the reason we don't have one event to handle all of this which we totally could is that I want to have that separation out on the front end so I want to listen for a trip accepted event or a trip ended event I don't want to listen for a single trip event and then determine through like an attribute what are the actual event is splitting this out into separate events themselves makes that distinction a little bit more clear for me and it might not be for you and that's totally okay and we can go ahead and dispatch all the rest of these events with their corresponding methods so down here and start we can say trip started dispatch trip and request user trip ended and finally trip location updated and we are good to go so now I said that there are two parts to this and we've done the first part which is create these events dispatch them out where they need to go and ensure that they are being broadcasted on a specific Channel the other part of this though is we need a package to actually push those events out so they can be consumed by our front end the two most common ones are sockety and laravel websockets both of these are battle tested and production ready but me personally I like using level websockets I have the most experience with it so this is what I'm going to use for this video but the implementation for both is documented well online so you can find solutions to either one if we take a look at the documentation we need to install it and then all we need to do is start it with PHP Artisan websocket serve so let's go ahead and try that out okay so first we'll need to require the package with composer and this finished up pretty fast now we need to run some migrations there is nothing to migrate that's because I didn't publish the vendor first okay now let's migrate migrations have been ran which it looks like this is just a statistics table so I actually don't know if we need that or not but it's good to have next we can publish a configuration file but I don't think that we're going to need to adjust anything in there so we can go ahead and skip that let's head over to this basic usage section and it looks like we have a couple of requirements that we need to use this with Pusher which this is the actual SDK that will be doing the work behind the scenes to take our events and broadcast them out let's go ahead and require this package as well and we need to update the broadcast driver to Pusher in our EnV file let's go ahead and open that up and find broadcast driver and set this to pusher it looks like we need to make some adjustments to the config broadcasting file and ensure that the host and Port is coming from our local machine not from an external service so let's make those adjustments config Broadcasting and if we scroll down to Pusher okay so we need to adjust the host the port and the scheme so let's go ahead and add these values to our EnV file since that's what these options are pulling from anyway so we can scroll down to here we already have some default values Pusher host is one two seven zero zero one or localhost the port is 6001 and the scheme is http now for larified websockets we also need to create values for these up here we're not given these by an external service we have to just create some kind of fake values that we can use in our application we will eventually be tying these to the front end though so make sure that you know what you're setting here or the ID we'll just use pusher for the key we'll use my key and for this secret we'll just use Secret actually for the app ID let's just use laravel instead of pusher okay so this should be everything that we need in order to get level websockets started and we can try that by opening up our terminal and let's see if the PHP art is in websockets serve command works fine all right we have a websocket server on Port 6001 now nothing is going to happen if we push out an event right now and that's because websockets will not actually push out unless there is a client attached to them so right now we really can't test this out we can just hope that it's working as expected we can exit this with Ctrl C and we'll worry about this a little later on when we attach the front end to the back end speaking of which I think our back end is done now so we can close out of this directory and start working on our front end so here we are in the front end directory that we have in our main source folder and we need to get a view project created here so in the terminal all we need to do is run npm init view at latest in the current directory and this will use the create view script in order to scaffold out some kind of skeleton for our project the package name will just do Andrew pair we are not using typescript for this video if you would like to see me do more view typescript Projects please let me know in the comments below node.jsx support we're just doing a straightforward View application we will need a view router though because this will be a single page application and we will also be using Pina for State Management no unit tests right now and no end-to-end testing also we'll skip the eslint for code quality again we're just aiming to get this project out as soon as possible all right the scaffold is done so now we can run npm install okay and then once that finishes up we can run npm run Dev to get vloaded up and our project at the 5173 Port so let's go ahead and open that up in the browser and see what it looks like okay so we have our project loaded up here and the best thing is that since we're using this Dev server with Veet any changes that we make will be compiled immediately and then hot reloaded into our development site so we'll be able to see our development live as it progresses let's go ahead and open up that code base so we'll leave another tab open we have PHP running in one npm running in another with v and so we'll leave this last one to just kind of do any work and that we need to all right so we have a few different directories for our view project we have this main root directory that our application lives in with a vconfig file a readme our package.json and an index.html file now this index file this is the main entry point into our applications this is the main template that's used in our app and then the source code is where all of our view source code lives so we have this main app.view component which is the entry point into the rest of our application so we can see our hello world component with a message here and if we go ahead and change this do something else like welcome to Andrew and save and then go back into the browser you can see we had that change appear in in real time thanks to Veet and hot module reloading and then this main JS file is kind of the starting point for the entire View application so we you know we create the application we import the app and the router from specific areas create the app add in pin your support and then mount it to the app element that we have here but okay let's let's take a look at this assets main CSS file here so it's importing a base CSS which is just kind of some boilerplate from view but the problem is is that for this application I want to use Tailwind CSS I I don't want to use any kind of custom CSS just because again rapid development is really the point of this so let's go ahead and add support for Tailwind let's exit out of this main CSS and Main and app files for now and we will open up a terminal here first we'll install the package and some prerequisites that we'll need npm install capital D which stands for Save Dev if you didn't know so D Tailwind CSS post CSS and Auto prefixer all right once those are installed we can initialize a Tailwind skeleton by doing MPX Tailwind CSS init and P and so this will create both a Tailwind CSS or both a Tailwind config JS file and a post CSS config.js file the post CSS config we won't be really touching it but we will need to make some changes to this Tailwind config file let's exit out of the terminal for right now and what we will need to do is in this content array we will need to add the paths to files that will contain Tailwind code this way whenever we build our project it can go through those files and understand what classes are or aren't being used so we have a smaller output of the compiled CSS now this expects an array of paths so we'll need that index.html file and in the source directory we'll take any directories and we will go through both View and JS files to make sure that there's no Tailwind in them or to make sure that there is Tailwind in them and that should be it for the configuration now the only other piece that we need to do is in this main CSS file we can just get rid of all of this and use the at Tailwind directive to bring in the base components and utilities parts of the framework which means that we can get rid of this base CSS file and we are good to go now in our terminal we may need to end this and recompile it just to make sure that our new dependencies have gone through all right if we go back to the browser we can see it's a little different and that's because I mean none of the CSS that was there that built this whole page was added in so let's get rid of this boilerplate that we have and add in some styles to see if Tailwind support has been added into this project so we can go over to our main app view file and let's get rid of everything that's in here besides the router view actually we'll just get rid of everything that's in between this header tag let's create a div with a Max width of 3XL margin left and right is auto background we'll do green 100 and text centered and then we'll throw an H1 tag in here hello Tailwind so let's see if this works okay perfect yep we see it right here hello Tailwind with this box that is green colored in so exactly what we're expecting okay now that we know that Tailwind is working in our application let's go ahead and clean out some of this skeleton code real quick to get better prepared for actually building out our front end so thinking about how I want to do this I really don't have any components or parts of the application that will be shared throughout multiple screens so I can actually get rid of this header that's here and just half hour app view file be a wrapper for this router view which this view comes from if we open up our router index file this is every component that is in our routes object based on the current path that's in our browser so visiting this root path which is where we are in our browser right now it is rendering out this home view component which is under views home view into this section called router view which is then in turn being rendered out at this div with the IDF app so that's kind of how the flow of this application is currently working so let's clean up some of this here and better prepare ourselves for the views that we're going to be creating so let's get rid of this style block that we have here all of all of this style block that we have down here so we're left just with a script setup and then a template for our router we are also not importing this hello world component or this router link so this is our new app view component let's go ahead and keep this router open since we're going to be adding pages in it as we go along we also have no use for this about path we don't have an about path in our application we're not going to be using that so we'll just keep this home view component and so we can delete this about view component that we have in the views folder and then for the home view we're going to be renaming this as well as creating a different component for this because that's really not what we're going to be using at the root of this project or at the root of this application and so actually let's let's just take a step back and think about the flow of this application and the paths that we're going to need in it so thinking way back to our demo that we had we have a user come into the application and then right away they need to log into it to see the rest of it so we'll need a route that handles logging in after a user is authenticated they're brought to a screen that shows two options whether they want to be a driver or a passenger for that particular session and if they're a driver they need to go to that holding area or have a screen that shows a current route that they're on and then similarly if they're a passenger they need to determine where they want to go if they're currently in a trip they'll have a map shown where they currently are and then finally they will have a kind of finishing screen that shows they have completed their trip and they can go on their way so that's the flow we're kind of thinking of right now and we'll need to implement these is for it as we go along so it makes sense to start with the login portion first and I think that will be our home path so instead of a home view let's go ahead and create a new one and call it login View and open it up so a view component is comprised of three sections we have a script a template and possibly a style section so the script is where the functionality for the component lies the template is where the markup for the component lies and the style is where Styles associated with that particular template lie now in view 3 a component can be comprised of either just template tags or script tags in order to be a component that's the least amount of things they need for our login view we are going to be using both a script and template tags so we can have both markup and functionality convention does dictate the order that those go into and it's usually script template and style tags but my preference kind of Falls in line with the earlier days of view where the template tags come first and the script tags are toward the bottom so that's what I'm going to be using throughout this application but just know you can reverse it or position them in any way you want throughout your component so we'll start with the template tags and this is where our markup will lie for our login View and we will do script setup and the reason that we're using this setup tag is it's kind of just syntactic sugar that allows us to skip a setup method inside of the script tags where we initialize and have to export variables that are used throughout the rest of this component so instead anything that we include in here like if we were just doing a const message this message variable is immediately available to our template but okay let's get rid of this and plan out some of the markup that we'll be using on our main login view page I'm just going to throw a scaffold in here so you don't have to watch me type a bunch of HTML and I will explain it afterwards okay so here we have our markup it's a div with a padding top of 16 messaged into your phone number and then a text input with the name and ID of phone a placeholder and a button to submit your phone number I also added this wrapper div to our main app view file around the router view so that each screen has a Min height a background that's light gray and has centered text with anti-aliasing let's go ahead and see what this looks like in the browser okay so here's our simple login form into your phone number and we can provide a phone number in here now there's two problems with this is that one if we go to try to submit this form it actually submits the form and puts it as a get request up here which isn't what we want we want to submit that form asynchronously using JavaScript so we that we can get information out to continue on with verifying that phone number and the second issue is that someone can put anything they want in here so there's no following a specific format or validation for what comes through here and we need to fix that as well we want phone numbers to be in this format that we see in the placeholder so let's tackle both of those things real quick heading back into our code base let's handle the form input first because that will probably be the easier one for this we are going to use a package called masca here's the repo for it and it Brands itself as a zero dependency input mask for View and vanilla.js if we head over to the documentation we can look at the install section here it is just a single command in npm and then the usage for view is to import vmasca and then add it in as an attribute with a data mask attribute following the convention of the input that we want so let's go ahead and try this out in our code base here we can open up a terminal npm install we want to save it as a Dev dependency and maska all right that was installed so we can clear out of this and exit our terminal and then in our component in the script area down here import vmaska is that what it was lowercase V maska from masca and then in our input up here we can use the V mask attribute and then data maska to provide some kind of template that we want for this input numbers are the number sign and then any other character that we add in here can be used to format this this number input so for a phone number we always want to start with a single digit then in parentheses three digits a space three more digits and then a dash and four digits now I'm formatting this for what I'm familiar with which is North American based phone numbers yours might be a little bit different and so this might change depending on your particular needs let's go ahead and save this and see what it looks like in the browser oh actually I need a dash between V and maska now let's go ahead and see what it looks like Okay so let's just start typing so one and yeah and then it doesn't let me type any further than this and if I try instead to type a character like a letter or a special symbol it doesn't let me continue on at all so exactly what I am looking for now how about submitting this form so in the form element up here we can pass in the v on submit shortcode which is the at symbol and submit and this takes in a function that we can Define that will be fired whenever this form is submitted we'll just call this handle login and then we Define that function down in our script setup area so const handle login is a function and this is the body of that so if we were to just add in something like console log logging in save this go into our browser and submit we can see the form is still trying to submit but on the second time it's not so what what's going on here let's go back into our code and there might be two things that we can do to prevent this the first thing is tacking on this dot prevent to the end of our submit which should prevent any kind of default behavior in the browser from submitting this form and the second might be to just add the same event handler to this button to prevent any similar issues so at submit.prevent handle login now going back to our browser let's try this one more time so continue and the form is submitting or it's firing that function without submitting the actual form so exactly what we want we can get rid of the Mask a tab here and we will actually need to take this phone number this data that we have and submit it to our API that we created now in order to do that we need to store that phone number somewhere in our component and we can do this one of two ways in view we can either create a constant called a phone that is equal to a ref that starts out as null oops I don't want semicolons in here or instead we can create another constant called like data that is equal to a reactive object in view that has a property called phone that starts out as null so what is the difference between these two I'll give a short example so let's start out with the constant phone so if I was to go up to our input type text here for our phone we can use the V model directive and give it the model of phone and then if we scroll down here to the handling of the login let's go ahead and console out that value now we can't just use phone to get the attribute because that will give us the whole ref object back it won't give us the actual value that phone number currently is in order to get that we have to use the value attribute of that object now the other option that we can do is that if we go up here and instead of the v-model phone we use data.phone so the phone attribute of the data object we can just console log out that same value so data.phone we don't need to use a value middleman attribute in order to get that value out and so it's kind of just a matter of personal preference and how you want to organize your components for a component that has just a few uncoupled attributes I would probably stick with using refs for those but because we're going to be storing a couple of different interdependent attributes I'll like wrapping them in a single reactive object because if we need to we can end up passing that whole object around if we need to instead of building a new object out of ref values so let's stick with reactive so we have a reactive data attribute with our phone number that starts out as null now whenever the login happens we need to send that object out to our API to get a text message sent out and a verification code created well how are we going to do that well we can use the fetch Library which is present in JavaScript now but I like using the axios package instead I just find it easy to work with and to customize if we need to so let's go ahead and add that in as a dependency in our terminal npm install oops npm install d axios okay that went through fine and now we can use it by importing it into our component so import axios from axios and we can use it similarly to the fetch Library so instead of the phone number being console logged we can do axios dot post and then provide a route to our API now thinking back on what route that is so first we need a base URL and that will be localhost and I believe that was API login and then the next argument is the object that we're passing in containing our data now we can just use data here because whenever a reactive object is called like this it doesn't return back a reactive object from view it just returns a plain data object back to us so you see here we have just a data object with a phone number that is set to null or whatever the phone number is when the user actually submits this form and actually while we're here let's rename data to be less ambiguous so we'll call this credentials okay so what do we do after this well then we use then which gets a response object back and let's console log out the data from that response and this is this is a happy path response this is what happens if we get a 200 back from the server but if we don't get a 200 back if we get something else if there's a problem then we can use this catch method which will return back an error to us so we can console error out that error and then alert the user to whatever that error's response code was now this error response data is the same object that we will be getting back from a server and thinking back on how we designed the API any kind of bad Pathways that get taken during login or any of the other API routes return a Json object with a message attribute so if I add on that message attribute to the data response it should just alert the user to whatever that message was back from the server oh and one more thing that we need to do is that up here in the v-model data phone we forgot that we changed that to credentials phone okay now let's go ahead and try this out and let's add in my phone number and we get this error back the phone field must be a number and that makes sense because if we think back to the validation that we did on the API request coming in we did set that the phone number field should be numeric coming in so we can either remove that validation requirement from the API or we can change our front end to push out a number without the formatting that we get from this front end section here and so we can handle that either way that we want to but since we're already here working on the front end let's just do that and I I kind of hate doing it this way because then we can't just pass in this whole credentials object really nicely like this we have to build a new object which is kind of why I didn't use refs in the first place but that's fine let's just continue on so we're passing in a phone attribute and that attribute has credentials phone and we are replacing spaces with nothing we are also replacing open parentheses with nothing and we are replacing close parentheses with nothing oh and actually we need to change this to replace all because we could have more than one space in the phone number and is there anything else oh the dash we need to replace the dash with nothing as well now there is probably an easier way to do this we could use regex I am completely unfamiliar with our regex that would replace all these values and then you can also create your own kind of replace array function if you wanted to replace all of these values at once but again quick and dirty method this should get us a phone number that is just a block of digits so let's head back into our browser and see what this looks like okay let's enter in my phone number one more time and hit continue and perfect okay we get a message back from the server text message notification sent that is our response data that we got back and I can see on my phone down here that I actually did get a text message so the connection between our front end and our API is working just as expected if we go to the network tab we can actually see the whole response that we got back from here so we can see the request that we put in and the response that we got back now what we need to do is then move the user to a new text area that lets them add in their verification code that was texted to them and the server should verify that that phone number with that verification code matches up to what's currently in the server so let's tackle that next okay so let's go back into our code what we have to do is essentially copy this form again so that we have another area to handle in the secret code that was texted to us and a separate event handler to verify that code so let's go ahead and do that so we'll take this whole form here copy it we'll paste it underneath this form here and we need a way to differentiate between which one is currently being displayed and we can do that by adding in down here we can add in a ref attribute let's call this uh waiting on verification and so it's a ref and its initial value is false so initially we are not waiting on a verification so we are displaying that text message form and then if we go up here so we can say all right this form is being displayed if we are not waiting on verification otherwise which we can use V else for we have this form being displayed which is our verification form and let's go ahead and make some changes to this so that it's actually a verification form okay so what we've done is we've changed the event handler to handle verification for both the form and the button down here we've also changed the input model from credentials phones to credentials login code so we have a new attribute in that credentials object the mask that we have for the input is now just six numbers because that's what we're expecting back from the code and the button now says verify instead of continue so what will happen is when we scroll down here when we get a response back a successful response back from this post to the API login route we need to switch out those forms and allow for verification so down here we can say all right waiting on verification.value is now set to true so it changes that waiting on verification ref above that we have here to a True Value which will switch out the four markups to our verification form and then down here we have a new method handle verification this is what handles the verification form being submitted with our code from our text message so okay now what do we need to do for this well just like above here we need to make a post request to our API at a route that we already created with the phone number that we have stored as well as the verification code because we need both of those to ensure that the right code was connected to the right phone number so we can go ahead and scaffold this out axios posts to localhost API login verify and we pass in an object that contains the attributes that we want to pass into that route so again we have phone number and we can just take this same line from up here and we'll also include the login code from credentials Dot Login code and okay we get a response back let's console log it out now the response will be getting back should be a authentication token so this should be an all token that we need to store somewhere and again if there is an error we'll catch it console error it out and alert back the response message to the user okay so here's our handle verification method now let's see this all in action okay we are back in the browser starting over again so let's put in my phone number I'm going to hit continue the post went through successfully and now I should be waiting for a text message and I can enter in my verification code all right I got a message my code is 994. 757 now let's hit verify and see what happens okay well we get a 200 response so that's already looking good now let's see what the console has to say okay so this right here is our authentication token that we got back so now we can store this and use it to make authenticated calls in this application so let's add some code to make that happen okay so after the console log we can do local storage which is an API available just in vanilla JavaScript set item and we will set the item token to the Token which is the response data but we need to send the user somewhere after this happens we can't just keep them on the same page so we need to send them to a new page a new view and we can do that with a router helper at the top of this component or the top of the script for this component so we'll handle this after these import statements we can say const router is equal to use router and that's a function and it was automatically imported from The View router package and so now we can use this router object to help programmatically navigate the user through various routes in our application so down here after we set this local storage item we can say router push and in this object that it takes as an argument we can specify the name of the route and we will push them to a route called index which if you remember me talking about it earlier the index route is going to be the area that allows a user to determine whether they're going to be a driver or a passenger it's basically the starting page of this application if they're already logged in or in this case if they have logged in and speaking of already logged in we need to handle that because we don't want people having to log into this application each time they visit we want to be able to determine if a user has already logged in and if so push them onto the index page so we don't have to keep them logging in again and again and we can handle that if we go let's go up here to before these method implementations and we can add a lifecycle route called on mounted and so what this does is it takes a Anonymous function or a closure function as a single argument and it runs this code whenever this particular component is mounted which essentially is basically loaded up for the first time what we should do here is check if our local storage contains so get item that token that we had set earlier for the authentication token and if so we're going to push them to that index route so this handles if the user is already logged in now before we go there's a little bit of refactoring that we can do in here and that's with this phone property that we had set earlier that we're now copying between these two methods here and in all honesty it just bugs me and I want to reduce this down a little bit so I think what I'm going to do is create a computed property to solve this and what a computed property is in view it allows us to generate a reactive property based on the values of other reactive properties inside this component so we can take things like our refs our reactive components and we can create some kind of new attribute or some new variable based on those values and it'll update along with them in real time so what I can essentially do is create a constant we'll call this formatted credentials because that's basically what it is and it is equal to a computed method that takes an anonymous function just like the on mounted method up here does and anything that is returned in here is what this formatted credentials item or object will be and so in our case I want it to be the same as our credentials reactive up here except I want the phone number to be nice and formatted like we have down here so I can just return an object and it'll be phone and the login code which the login code is going to stay the same it is credentials.login code but our phone number is this whole string right here okay so now what I can do is I can replace this object that we have to specify out for each of these axios calls and just call formatted credentials so that shortens this up a bit considerably and this works because the validation that's on this API login route that we have it only checks to make sure that the phone number is there it doesn't care that I'm passing in a login code with a null value that really doesn't matter if we wanted to we could check if this login code was available and then only have this value present if it is but in all honesty it really doesn't matter at this point so this is what I'm going with okay I think the last thing that we need to do now is it create this index route that we have referenced in this component so let's head into our router and we will create a new route we'll give it a path and we'll call it I don't know start that sounds pretty good name is index and component is actually you know what I kind of don't like this index naming convention let's let's call this Landing that sounds good so path Landing name landing and component is landing view which we will create here in a minute and let me just go back to the login view that we have here and I'm going to change these router pushes from index to Landing okay now we can exit our login view we are done with this so far I believe and we can go to views and create a new Landing view here we'll scaffold it out with our template and script setup and then all we need to do is import this okay so let's give this some starting markup real quick okay so I put together this basic layout we have a title that says Andrew bur and I have two buttons one that says start driving and one that says find a ride let's go ahead and see what this looks like in the browser so we visit this Landing route here and we have start driving and find a ride but wait a minute if I go to my storage for my application and go to the local storage section I don't have my token present right now because I never went and logged back in after we did those code adjustments so I I shouldn't be seeing this page we need to create some kind of middleware or guard against a non-authenticated user viewing these Pages because this application should only be used by people who are authenticated into it so let's tackle that before we go on any further so if we go back to this router index file we scroll down to the bottom before this export default we can use that router object and the before each method which hooks into every navigation to and from a route in this application so this takes an anonymous function with the arguments being to and from which correspond to routes that a user is going to and a user is coming from and what we can do here is programmatically navigate the user where we want them to go based on certain attributes that they have inside of this application so just like we did whenever a user would go to the login page and they had a token associated with them and we pushed them to a new route we can do the same thing here so we can check if a user doesn't have that token so if not local storage get item token we need to push them to the login route and have them go through that flow instead so we can just return the name of the route that they need to go to which is the login route so if this conditional is not true if if they do have a token associated with them they will just be able to continue on to wherever they were navigating with originally now this is the bare minimum I will say because ideally we should have some kind of call that goes out to the server here to verify that the token that we are using is actually correct but this is a good immediate check that we don't have to make a server call because if a user doesn't have a token at all we immediately want them to go to this login screen below it though we can add in more conditionals to check for more information so let's do something here like if uh I don't know we'll call a method that we create like check token authenticity I really hope I spelled that right again we'll return back to the login route but before that we will actually remove the token from their local storage because if it's not authentic they don't need to have it in their storage in this way if it was still present they wouldn't be able to actually view the login screen okay so if both of these are false and they're able to pass through this they can go into any page they want to let's go ahead and add in this method that we just created so cons check token authenticity is a function and the body of which we're just going to make an axios get call to localhost API user I think is the route that we created and we need to pass in a configuration object that includes some headers specifically an authorization header that is set to bear and then the local storage get item token actually I'm doing this a little wrong because I completely forgot that axios is an async Library so I don't want to have to create a bunch of promises here that resolved and didn't do an await up here so I'll just call check token authenticity let's remove this down here and what I'll do down here instead is when this resolves if this comes through as any 200 error if this comes through successfully then nothing happens the user is able to pass through and there's no problem but if we catch an error which would most likely mean that the token that we pass through is invalid we want to return back or we want to push the user to that uh login route that we had created earlier and then don't forget before that we actually want to remove that item from their local storage but there is one caveat now that I'm looking at this and that is if a user visits the login page so right now this will kind of form a loop in the browser so if a user visits a login page well they're not going to have a token associated with them and it's going to try to push them to the login page and it'll do it again and again and again so we need to determine if the user is going to the login page and if so let them just be on their way so we can say if two dot name so if the name of the route they are going to is equal to login we can explicitly return true which will allow them to just immediately pass through all right let's let's give this a whirl so let's go into our browser and we can already see where we've been forcefully navigated back to the login route so if we try to visit that Landing route that we had created earlier you can see we're immediately pushed back to the login route but let's go ahead through the whole login flow and see what happens okay so I have my phone number entered in we can hit continue and we are getting some errors in the console cyclic object value and this is happening in the handle login method of our login View so I think this issue stemmed from the fact of using a computed property which I I could have sworn in view two can return just a plain object when using a different method but it seems that in this case it's returning back a whole computed object instead so it's not really working inside of other methods it's still great for displaying filtered items in a template area if we were doing it in our markup up here but for passing those computed properties to other methods it's not really working as I wanted it to so instead what I'm going to do is just convert this to a plain old method so we will call this get formatted credentials and it will just be a method that returns back oops that returns back this object that we expect so now we can just call get formatted credentials instead of the formatted credentials object okay let's go to our browser and see if this is working okay let's go ahead and add in my phone number let's hit continue and our text message was sent so now let's wait and get a response back okay we have six three one three five one verify that and we're in we're in the landing page and if we go ahead and refresh we can see that we are still able to be here because we go to the network we can see that we made a get request to that user endpoint and it came back with a valid response which means that our token is perfectly valid now if I try to go back to the login page at the root you can see that I'm redirected to the landing page and again that verification happened so we are where we should be alright so let's go ahead and decide which of these two paths we're going to go down first start driving or find a ride so from the driving side I think we're going to need the ability for a passenger to create a trip before we can really do anything with that otherwise we'll just be waiting for a ride request that will never come because that hasn't been built yet so I think we'll start with find a ride first okay so let's head back into our code base and we can get rid of this login View and let's go back to our Landing View and we need to create some kind of functionality for this button here for whenever we click to find a ride so whenever we want to start finding a driver let's create a click Handler for this so at click and we'll just call this handle find a ride and we can create that in our script setup down here so const handle find a ride is equal to a function that will do something so okay what do we want this button to do I really don't want to stay on this same page component to handle putting in an address and setting our destination I'd rather a new view handle that so I think all I want this button to do is just push us to that new route and so just like what we did with the middleware stuff that we did earlier I'm going to use a router object so we'll do const router equals use router and we can use router push to push us to a new route when that button is clicked now what that routes name is going to be let's do something called let's do location because ideally that's the first part of finding a ride is setting the location that we want to go to okay and that's that's all we need for this button to have functionality now we do have a problem though and that's this route doesn't exist yet so just like with this Landing route let's go back to our router index file and scroll up to our routes array and let's create this route so we have a path of location a name of location and a component called location view and just like everything else let's create that location view view file we'll start it out with a template and a script setup and then back in our router index file we can import that at the top part here okay now let's go ahead and add in some markup for this page I'm just going to go ahead and paste in a basic template that I have set up so you don't have to watch me fill out a bunch of HTML okay so I put in this markup that we have here we have just like the last page and H1 tag for the heading title where are we going and then a form that has a text input here with a placeholder of my destination and a button down here to find a ride let's head over to the browser and see how this looks alright so let's click find a ride and we are brought to our location page where are we going so ideally what I want to happen is to be able to type in our destination and then click find a ride and that will bring us to a confirmation page with an actual map showing the distance between where we are now and where that destination is that'll help us just get like a confirmation to ensure that you know the where we want to go is where we want to go now there's a lot of ways that I can handle this I can have a user just input an address and hope for the best but I want something that's kind of more friendly to use and so I'm going to reach for a third party service to do this and I'm going to reach for Google maps's autocomplete so here's the documentation page for it it's called Place autocomplete and it's a widget that basically lets you enter in a location so if I wanted to do something like Starbucks we can see it's pulled in an automatic list of addresses and places from whatever area we are currently centered around and so what I want to happen is I want that to work with this box here and take whatever our current location is as the center point and we can type in you know Starbucks here and it'll give me a list of those cafes that are near my area because that's usually how these ride shares work is you're going to a place that is somewhat close to where you are right now now Google Maps or Google Places has their own JavaScript API that I can use to pull this information in but even better is that there is a view package that makes this even easier and it's this here view three Google Maps now there are a few different view packages that add in Google Maps functionality but this is the one that I have found works the best out of the box with the simplest amount of markup and it's easiest to get started with so first we have to go ahead and install this with the npm command and I'm going to adjust this because instead of saving it I want to save it as a Dev dependency so we'll use the capital D flag let's open up a terminal we can clear out what we have in here now and run npm install d view Google Maps all right we have that installed and we can exit our terminal so now if we scroll down here we can see how to configure it and in our main JS file we need to import it use it with app use and the load in an API key so let's go ahead and do these steps let's open up our main JS file import this toward the top actually you know what let's import this by itself because we kind of have main view stuff I don't know accessory view items and then third-party packages I think is a good way of organizing this and we have app use Pena router and we'll have app used down here view Google Maps and then it has an options array which we need a load key for and then a key attribute with our Google Maps API key let me just go ahead and paste mine in here okay let's go back to the documentation and okay we should be able to use these elements anywhere in our components now if we go to read the docs the one that we're looking for is autocomplete so we need to add in a new attribute to that load object that we just created a libraries places so after key libraries places and then we are good to add autocomplete to our components so let's go back into our code base and see if we can get this running let's exit the main View and we can exit The Landing view now you won't need that for a while so let's change this input type text to A gmap autocomplete is that what it is a g map autocomplete okay we don't need type text anymore we can keep the placeholder and let's put this all on a new line and what was it Place underscore change and let's set this to handle location changed and we'll go ahead and create that event too oh we have a problem here now this also this expects a closing tag okay let's add in that handle location changed function and we should be getting some kind of event from from this so let's just console log this out handle location changed and we'll count to log the whole event out so we can see what kind of data we can pull from that because ideally what we're looking for is like a latitude and longitude address maybe a name whatever we can add into the database schema that we had created in our API okay let's go back to our browser and see if this works okay so we're back in the browser now let's go ahead and start adding in some kind of text let's use Starbucks and okay this is awesome so first of all it just kind of knows where I am probably based on my IP address so it's already pulling in locations that are around my area these are the nearest Starbucks to my house and so let's see if I click on one of these okay so we got that handle location change event fired and this returns back an object that has an address a opening hours formatted address geometry which is exactly what we want so we have the location latitude and longitude and we even have we have a name reference URLs vicinity all this good stuff okay now what we need to do is we need to save this somewhere wherever we want our user to go we need to save this and then we hit find a ride we need to be pushed to a new route that will have a map view to confirm that that is the destination that we want to choose now we can't we could do everything on this page but it gets kind of sloppy the whole point of front-end Frameworks like view or react we can split this out to more easily digestible chunks and so that's what we'll do here let's go back into our code and we'll need to add on to this handle location changed method we need to store that location somewhere or at least the data associated with that location and move to the next route so that it can use the location that we had chosen and in order to do this we're going to use the State library that we had installed when we originally built this View application Pinya and if you look in the sidebar here we already have this stores folder opening it up we have a counter store that was created as like a default for this skeleton so we're not going to use this but it's a good idea to show how this works so we can import this counter store into any component or view that we have here and then this count attribute here this count ref will be available to our components and the best thing is that if we update it in one component it's immediately available to any other component that uses it so let's copy this to a new file called location okay perfect and remember I said we don't need this counter store demo so I'm just going to delete it okay let's rename everything in here and clean it up so it's reflective of a location instead of a counter okay so we have export a cons called use location store it defines store called location and right now we're returning nothing because we have no objects in the store defined but let's think about that what do we want to store in here well right now we want to store the destination location that's the location that the user chose in that location view so we can create a constant destination is a reactive view element and it has some properties now we can kind of think of these as properties that would be available in a trip whenever we had created that data table in the API we need a name an address and some geometry which in our case is a latitude and a longitude and so now I can return this destination and it will be available to us whenever we import this store anywhere so then back in the location view here we can say all right const location is equal to use location store all right so well now I need to be able to populate that location store with the information that we got back whenever this handle location change event is fired and so what we can do is we can call location and then dollar sign patch this expects an object consisting of key value pairs of the attributes that we want to update inside of this location store well right now we only have one and that is our destination object so we can say all right location patch destination and then we can pass in the attributes and values that we want to overwrite the default ones that are in here so we need a name which is associated with the event name address is event formatted address and the geometry I unfortunately can't just pull out that whole object from Google Maps as autocomplete I have to generate it here individually so lat is e geometry location lats and it's a function and the same thing with the longitude location LNG okay so now what should happen is if we go back to our browser let's open up the dev tools window and start typing in a destination so we'll use Starbucks again this time we'll go to the one on East Colonial and okay we have the handle location change event that fired but I have no way of knowing what our state is currently and so that's where the vue.js dev tools can come in handy this is available on chromium browsers as well as Firefox let's go ahead and add this in here and we can use this to see if we can check out that state in our application let's go ahead and refresh and pull up our Dev tools again and look at that we have a new tab in here called View and if we go in here we can see this Pinya tab we can see our location store and right now everything in here is empty it is the default state but let's go ahead and run this again our locations State object change specifically the destination object you see here we have the address the geometry and the name all added in as expected so now we need to handle this find a ride button we need to lock in this state well we've already done that so we just need to ensure that this state is set and then pushed the user to a new route where we can use this to draw a map so let's go back into our code one more time and then let's scroll up to our button here and we will add an event handler so on click and this is in a form so actually on click prevent let's call this handle select location so our location has been changed and now we have or we are selecting it as our actual location to drive to or to get driven to so const handle location or handle select location is an event and what this will do is we'll need to push ourselves like we usually do so const router is use router and then down here router.push name let's call this map so this will be a map of our origin to our destination but if we do it this way we can get pushed to this route even if we haven't set a location yet but we don't want that to happen we only want the user to be able to go to the next page if they have set a destination in mind so let's set a conditional on this if location destination name does not equal an empty string then we can proceed to the next page otherwise nothing happens when the button is pressed all right let's give this a shot well actually we can't yet because we don't have this route created let's create the route first so back in our routes array you know the drill path map name map and component map view that name could probably use some work but I'm just going to keep it for now and let's create that view file again with the template and script setup and we will need to import this at the top here okay so this looks good let's open up our browser and see if this works as expected okay so the user doesn't have a destination set finding a ride does nothing now let's set a destination we're going to Starbucks on East Colonial find a ride and we were brought to the map page exactly what we expected so that is perfect but we don't have anything here so let's add some markup for this page we can go ahead and exit our location JS and location view for now and let's focus on the map view like with everything that I've done here so far I'm just going to paste in some boilerplate markup to get a basic layout going here all right so here's what I've pasted in again we have a basic layout H1 tag here's your trip and we just have this white box that currently has the text going to my destination in bold letters there's also a button down here that says let's go this will be like a all right confirmation everything looks good let's see if we can get a driver this looks like this in the browser so again here's your trip going to my destination first thing that I want to do let's change at this destination and actually bring in our destination's name so we have that saved in the state you can see here in our view Dev tools Pinya location store we have the name Starbucks so which should say going to Starbucks this is actually pretty straightforward to do so if we go down to our script setup we can import the use location store method from stores location and this at symbol here you might have seen in view applications or react or other JavaScript applications this is essentially a short code for the root of our application so this Source folder up here at the top so this is saying Source folder stores location it's a lot easier than having to add you know a bunch of uh double dots to get a relative file path it's just way easier to reference the application's root and we have const location is equal to use location store you know what we're also going to use at the router in here so let's go ahead and add that in here too we've been using each time to push the user to the next or a different page and I'm sure we'll end up using this here as well okay so now we can use this location object to pull out data from our locations state so if we go up here in these strong tags we can say location all right well what do we have in location right now we only have one object and that was that destination and it has a name attribute so now we see going to Starbucks it automatically pulled out that name from the state and if we wanted to we could go in here and change this because using devtools we can update this state in real time it's a nice little uh handy feature of it and so we see you know it updated in real time so it is pulling from this state that we have here all right well the next part it might be a little tricky what I want to have up here is I want to have a map view we already are pulling in Google Maps Library so I want to use it as much as possible for this application and so we should render out a map that shows my current location and then where my destination is and a path along it showing where my driver is most likely going to take me and so let's add a new div in here and we're going to use the gmap map component and the documentation for this is available on that view three Google Maps package website which I will link in the description below I'm going to set the zoom level to 11. that's a pretty reasonable zoom and we need somewhere to Center this map on and it should be centered on my destination so we can use uh the v-bind shortcode here a colon in front of the center because we're going to be using a dynamic View Property and that's something that's coming from our location store so location destination now we have the geometry object stored which is what this Google Maps Center expect it expects an object with a lat and LNG or longitude keys with values in it associated with the longitude and latitude of a center so we can just use this whole object to provide it with that and then finally let's give it a style we'll make it full width with a height of 256 sounds pretty good and the reason that I'm doing this styling explicitly is that using Tailwind CSS classes with this sometimes doesn't yield the result that I really expect it can sometimes be overwritten by classes that are added in after it's rendered out so adding these like this explicitly seems to help that a bit okay if we go back we don't see anything here right now and if we take a look at our console we can see that we have invalid prop type check failed for prop Zoom expected number got a string okay so this Zoom attribute is actually expecting the number 11 but passed in like this it is getting the string 11. if we bind it with view this now changes to an integer instead of a string and coming back to this we can see that it's working exactly as expected so that that was the issue okay and just to kind of nail the point home why don't we add a marker in here as well so we can use this gmap marker element and we can set the position to the same geometry that we have the center of the map so location destination geometry and then going back we can see that all right we have the pin exactly where our destination is so if we zoom in on it that's exactly where the Starbucks is so perfect but actually thinking back on it remember we don't want to just show where that destination is but remember what we want to show is a path that the user can take from their current location to this destination that they've chosen and in order to do that we will use some other Google Maps functionality and it's going to get a little complicated but I'll try to explain my best along the way and let's see if we can do this what we need to do is whenever this component is mounted whenever it's created and brought into the browser we need to make a call to an external Google service and get what's called a path from two different points point A to point B point B will be our destination point a will be the user's current location which we can get from the browser let's take it one step at a time so the first thing that we can do is let's get the user's current location in order to do all this we'll use this on mounted method from View and this is going to take an anonymous function that anything inside of here will fire whenever this component is mounted for the first time the first thing we should check though is does the user have a location set because if not we need to push them back to that previous location page so they can set one otherwise everything that we do here really doesn't make any sense so let's check for that location name again so if location destination name is a blank you know there's no location name set then we need to push the user back to that location page otherwise we can continue and like I said let's get the user's current location okay well how can we do that we can use the Navigator object and the geolocation property on it if we use the get current position method this is an asynchronous function that will return back the user's current position once it has been resolved and this will initiate a pop-up that allows the user to select whether they allow or block a application to view their exact location now this takes in at least one argument the first one is a callback function that has a single argument Whenever there is a successful retrieval of the user's current location so the user has allowed this application to view their location let's console log that success object out and see what we get now there's also an additional argument that can be passed in and it's another callback function if there's an error so if the user chooses to block this application from using their location we'll see something in there and so if that happens let's console error this error out all right let's head to the browser and see how this looks okay I was forced back to the location page because my destination wasn't set after that hard reset so let's set up Starbucks one more time okay so we can see that we have a new object in the console log and it has a time stamp and some coordinates which are an object that contains where my current location is so we have a latitude and a longitude this is what we want to pull out and Save in this application to use as a reference for the user's current location so back in our app's source code I want to be able to use this function in a couple of different areas and it'll be easier if we refactor this into a method that we can just call from like a Helper and the perfect place for this is our location store so not only can a store and view store data it can also provide methods that we can use to manipulate that data or get new data associated with this store whatever kind of just like makes sense in here and so let's create a new function here and we'll call it get user location it's a method and what does it return well how about a promise now a promise contains another anonymous function with a resolve and a reject argument and these can correspond easily to that Navigator geolocation get current position method because remember we are getting back either a success response or an error response and so these callbacks fit in perfectly with this so now we can use this as an asynchronous function here and this allows us to await for the user's location before we continue on to something else and we can have a one-liner to get that location object back well how do we how do we use this in here I could export this constant from here and and use it in each of these areas that I imported into but I'm just going to have to store this location again and I'm going to store it as an object in this location store so besides the destination let's have an object called current so this is the user's you know current location and this contains just a geometry with a latitude and longitude because you know we don't have a name associated with the user we don't have an address associated with them we just need to know where they are on a map and like everything else we can return the object for that so it's available anywhere we import the location store but I want to update this automatically from like a single method so instead of having to use patch like I did for the destination I just want to call all right let's update the user's location it'll pull in the location from this method up here and whenever it gets back it automatically Updates this object here so we have it available in our store so so let's create it so let's create a method and we'll call it update current location it's an async function and the first thing that we need to do is wait for the user location to the user's location is away get user location and it's it's just as easy as that so now we have access to we go back to our browser to this object here so we have a chords and a time stamp and the chords is where we have our latitude and longitude well we need to update this object here with that new geometry so all we need to do is call current geometry and set it to a new object so the latitude is user location chords latitude and longitude user location You Guessed It chords longitude so now if we export this function as well in our store what we can do is just call await location update current location oh well we're getting an error we're using a weight and a non-asynchronous function that's okay we can just append async to the on mounted Anonymous function in the arguments list so let's see if this works because remember we can look at our state using the view Dev tools so we will have to refresh and that's fine let's add in our Starbucks again and okay so we see here we have a destination we have our address and everything and if we go into current we also have our user's current location so I was able to update it as soon as this component loaded up but what I want is a connection between these two geometries I want a path that exists between these to show where I am now and where I'm going to be and this is where it gets tricky because I'm going to be using a couple of different Google services and apis that are being pulled in through this script that the view3 Google Maps package uses this isn't default functionality that exists in that package it's kind of just it's kind of just thrown together using the Google API services but we'll make it work so the first thing that I need to do is I need to reference this Google Map object because I only need to do this whenever this map has fully loaded I I can't create a path on the map if it doesn't exist or hasn't rendered yet so I need to create a ref object for this and we'll just call this gmap and we will add that ref down here so constant gmap is equal to ref and we'll start it out as null so now after we get the user's location let's draw a path on the map using gmap value so this is the actual element that we are getting now for the Google Map we can use something called map promise which as its name suggests is the promise for the map object and if we tack on the then method this means that the map object has fully loaded so we have access to the Google Maps whole object and we can use that to draw a path on it first we have to create two points though where the user is now and where the user wants to go we'll call the first the current point and we can create that using Google Maps lats LNG and we should be able to pass in just an object consisting of a latitude and longitude so we can use location current geometry and this will create a new Google Maps point class that we can use for manipulating this map and how about a destination point using the same syntax Google Maps lat LNG location destination geometry and we need to create two more temporary variables a direction service which is a new Google Maps directions service and a directions display which actually draws its directions path on the map this is a Google Maps directions renderer class and we're going to pass in an object that consists of a map property to our map object that we get from this promise okay so now that we have created all these variables how do we put them to use well we can call directions service oops I want to call it directions service not Direction service so we can call direction as service route and this expects an object where we have an origin so that is our current point and a destination oops and destination our destination point there's a few things that we can set we can say avoid tolls is false we we don't mind tolls and we also don't mind highways either and for the travel mode we want to set it to driving this is a Rideshare application and while it would be cool you don't want somebody picking us up on a one wheel or a bicycle and so for the travel mode Google Maps travel mode driving okay the second argument for the route method is a result and a status and that's in an anonymous function that we can use to determine if the route was created successfully and if it was so if the status is equal to Google Maps directions status okay we can display this route on our map using our directions display variable directions display set directions to the result and otherwise let's console error out this status that we get back so okay what does this look like let's find out so after putting in our destination we can now see that we are going to Starbucks we have our beginning Point here and our endpoint here labeled A and B if we zoom in we can actually see that we get a driving path from where we are currently starting to where we end up now ideally the user would look at this and say that is perfect that's where I want to go let's go and they continue on to the next step which is waiting for a driver so let's go and do that okay so we have the trip here prepared we can see the line that we're going from point A to point B and now what we need to do is we need to give this button some functionality we need to lock in this trip so when we say let's go we provide these details to any available drivers that are out there right now so if we head back into our code base let's go up to that button all right I haven't created a Handler for it yet so let's go ahead and do that right now so at click we'll call it a handle confirm trip so this is the confirmation that your trip details and everything looks good so we should proceed with it and so we can add that in Above This unmounted method const handle confirm trip is a function and we need to provide it with a body all right well what do we want to do to confirm that trip well we should probably post to the API route that we had created in the back end to store a new trip or this is a perfect opportunity to say all right this particular passenger wants a trip started let's save it in the database so now what we can do is we can call axios we'll import that in here and it was a post request two slash API slash trip well actually to localhost slash API slash trip and we need to provide it with some kind of details here we need to give it an origin a destination and a destination name so the origin is where we are starting off at is where our user's current location is so we can use that location store and grab the current geometry from it because we're storing the origin remember as a Json string or an array of latitude and longitude values so we get that from that geometry object and just like the origin the destination is the same except it's the destination it's the destination geometry that we want and then for the destination we can do location destination and remember we have a name attribute on that object as well so there we go that's what we want to provide this API route and we should get back a response if the happy path is met which then we should push the user to the next screen while they wait for a driver to be found so we'll use router push name and we need to create a name for this next view that doesn't exist yet uh how about trip so this next view will Encompass their entire trip if if this one was the map before this one was a location to get this kind of information for where the user is going the next one is the actual ride to their destination so trip seems appropriate and of course if there's an error let's catch it and dump it out into the console log okay um before we go any further though I have a problem and that is posting to this API route we don't have any authentication associated with it so I need to add an extra object here for headers with our authorization tag but this just I'm going to be making a couple of different endpoint requests throughout this application that are authenticated so do I really want to add in these authorization headers each time I I really don't and also the localhost domain name here that could change depending on where we deploy this application out to or how we stand it up in the local environment so I want that to be adjustable in a single place so for both of these issues I can knock that out by creating a helper to wrap these axios calls in so what I'm going to do is I'm going to create a new folder in our source directory here called helpers and let's create a new file in here called HTTP now what we need to do is create a common axios object that we can import into different view components and use it with things like authorization and a prefixed URL so let's go ahead and create the base method that will be in here we'll just call it http and what is this return well it should return an axios create which will build a new axios object depending on an object of options that we add in as this argument here so let's start out with a blank options object let options equals and actually we will add in headers as one of the attributes here and for right now it's blank so we don't have any headers because there are some axios calls that we're making throughout our application that might not need authorization for instance the login and validation ones that we have at the beginning of the application but if we have a local storage item of token that means that we need to make an authenticated call or at least we can include an authorization header in the call so we can add that on with options headers authorization and it's equal to a bearer token that bears the mark of local storage [Music] get item token all right and then we return that axios create with our options object that we had built and we can export default HTTP so by default we are exporting this method and can use it around these view components that we have well what does that look like let's go try it out well instead of axios posts we can do HTTP post oh but remember we talked about getting rid of this base URL here so let's also add that into our https helper so for the options we can tack in base URL and pass in our localhost URL so now regardless all of these requests are prefixed with this base URL which can be different than the URL that we are deploying this view app to okay so let's get our user ready for their trip by adding in this route that we had created that we're sending them to so back in our router index.js file let's create a new route path is trip same with the name and the component is trip View and let's go ahead and create that component and then import it up here I also went ahead and swapped out all of these relative paths for the ad symbol that we had talked about earlier I forgot to do that originally okay so we have this trip view in here starting out with our template and our script setup now I need to determine what kind of markup to put in here again I have something kind of pre-made for this that I will just paste in here and we can go from there again we have a basic layout like all the other ones have been an H1 tag that says we are waiting on a driver and then down here we have our gmap map ready to go and I'm thinking maybe this could show where I'm at where my driver's at or where my destination's at or some kind of combination of more than one of those things and then down here I put a little area where we have some more information like a message that the user might want to see for what's relevant on the screen so let's see how this looks in the browser well here's our trip that we had earlier so now let's confirm it by clicking let's go and we are in this new area screen right here so we are waiting on a driver and when the driver accepts the trip their info will appear here and if we take a look at our database in this trips table we can see that we have a new trip that was created we have a user associated with it but no driver which is exactly what we want it has not been started it's not complete we have the origin destination and destination name so exactly what we are looking for but now we should take a step back because there's not really much we can do from this point until we have the driver's side of things set up so let's go back to our landing area and we're going to start on these start driving path of things now so when a user clicks I want to be a driver what does that path look like well back in our source code we can leave this trip view in map view for now but we'll keep our routes file open let's go to that Landing view that we created so for our start driving button let's create a new event handler for it so on click handle start driving and we will add in that method down here cons handle start driving is a function and we should probably push the user to a new route like everything else the route that we should create would be like some kind of standby room that we can have the drivers waiting until a trip is available and they can choose to accept it if they want to so I think a good name for this would be something like standby and we'll create that route in a second but remember if we go back into our database we had created this drivers table this gets information from users who want to be drivers but doesn't have it filled up by default while we can't have a driver start driving unless they have the information attached to their user model so I think this is a good area to determine if first a user is already a driver or already has a driver model associated with them and if not we need to gather some more information before pushing them to this standby area so first we should make an API request and determine if a user has a driver associated with them so using that HTTP method that we had created earlier let's get API driver which if you remember should get us a driver model associated with the authenticated user that we're using in this case coming through this HTTP method and what we can do is using that response back we can determine all right if that response has a driver model associated with it then we can push them to that standby route that we were talking about earlier but if not well we need to go to a different route that we can get additional information from them to build that driver model so let's push them to a different route called I don't know driver and then again like always it's good practice to catch any errors that come through and we're just going to put them in the console for now okay so let's go and create these two routes that we have here standby and Driver in our routes index file let's go ahead and create those and we'll create the views files and import these at the top of this component okay so now we have these two views available standby View and Driver view I added in a template and script setup to both of these this one should be for users who are already drivers but we'll start with this one where we'll need to get more information from a user if they are not a driver yet so just like a basic form with the inputs that we find in the database that we had created so year make model color and license plate of their car I'm going to skip a lot of the boilerplate and just add in the markup like I've been doing with most of these views all right so I added in this heading with driver and car details and a basic form that has inputs for each of the items that we need from the driver so we see here we have the full name that again is by default not added in the user model but we should get that for the user being a driver and then we have information about their car the year make the model the color and the license plate number and then at the bottom we have a button that says continue for the users who be on their way so if we go back to the browser let's hit start driving and see what happens okay so an API request was made my user that I'm authenticated with is not a driver and so we were brought to this route and we can go ahead and fill this information in but right now that's not going to do anything because we don't have any functionality associated with this form yet back in our source code let's go ahead and change that so we need an action for the form at submit prevents let's call this just handle save driver and we'll use this same method on the button submit down here just in case the user clicks this instead of submitting the form traditionally through like the enter button okay so now we have both of those things tackled now we need to create that method though const handle save driver is a function what we need to do is create a post request to that driver route to save the driver's information but how do we get that information well first we either have to create a bunch of refs or a single reactive object to store that form data in I'm just going to create a reactive object I'm going to call it driver details and we'll give it some attributes and default values so we'll have name year make model color and license plate okay so now in this handle save driver method we make an HTTP request so we'll post to driver oh sorry API driver with the driver details object that we had created and then if the response is good that means the driver was saved successfully and we now have a driver associated with this user so like we were doing earlier we can push them now to the standby route that we had created but if there's an error let's catch it out and display it in the console okay before we test this out though we need to attach all of these reactive attributes to the form elements above and we do that with a V model so up here at the top we say all right V model is driver details dot name and we do the same for every other form element here so now if we go back to our browser we can fill out this form and hit continue and it will make that request to save our driver's information so let's add some data in here and we can hit continue okay our driver information was saved and we are now in this standby route but I didn't create anything in here so it just looks blank for right now but we can further verify this by going back to the landing page and if we hit start driving it Should Skip that driver route and go right to standby and it did perfect so we now have a driver associated with this user so let's go ahead and build this standby route out now all right let's head back into our source code okay and unlike the other ones I'm not going to paste a markup template in here mostly because we're going to have to kind of build this as we go so let's start out with all the other pages that I have with this padding top of 16 wrapper and an H1 tag the title let's say waiting for ride requests and then maybe display some kind of little I don't know animation down here so let's create a loader component I went ahead and found this one online and just pasted it in here it's a single element with the class of loader and then I have the stylus for it down here as well and it just animates between two different styles back and forth forever so we can go ahead and add that in underneath our waiting for ride request title but first let's give it a wrapper class so it has some spacing between it and we'll add in the loader don't forget though I do need to import this in here though so import loader at components loader.view okay now let's visit our standby route again and okay cool we have a standby view that looks pretty good so we are now waiting for a ride request from one of the users that we were playing around with earlier but okay we need to think about how we're going to handle it from this point on so what we need to do is we need to wait for a websockets event so thinking back to how we designed our API whenever a trip was created or accepted or completed an event was sent out this event was broadcast on a particular Channel as well what we need to do now though is listen for those events here specifically when a trip is created we need to listen for a trip being created event which will get us a trip object and then we can populate this screen here this view with that trip information we'll have the driver so that's me right now be able to either confirm or deny if they want to accept the trip and then from there we can actually go about picking up our passenger so it's a lot of things that we need to do but we'll break it down and take it step by step in order to actually listen to those though we need to implement a third-party library and it's one created by laravel called Echo so if you go to laravel's broadcasting documentation we scroll down here to this receiving broadcast section you can see that we have this installed and instantiated laravel Echo so this is what we want to take a look at so it's a JavaScript library that makes it easy to subscribe to channels and listen for events broadcast by your server-side broadcasting driver so no matter what driver we're using we can use this library to listen on the front end we are using laravel websockets which is a pusher replacement so we're going to install all of these here so let's just go ahead and copy this code and run it in our terminal let's go ahead and just open up a terminal in our IDE and wait for this to finish up all right that is finished and now we can go ahead and use this library or try to use this Library we'll see how this works in our standby View so we need to instantiate this and we want to do this whenever this component is booted up so we'll use that on mounted event again so we can instantiate that Library by saying all right let Echo equals new Echo and it takes an object of properties that act as options there's a few that we'll need to set here in order to get this working right so we'll need to set broadcaster to Pusher because remember we're using laravel websockets as a pusher replacement the key will need to use the same value that we have in the back end EnV file that we had set earlier so let's go ahead and see what that was we need to set a cluster as just mt1 at default value we need to set WS host which is the websockets host that is our window location host name because right now we are hosting it at the same domain as this application is being deployed in so localhost and this will keep it in sync if we deploy it out to like example.com so a domain name of our choosing this websockets host will remain the same because we'll just have websockets under a different port and speaking of which wsport that Port is 6001 and force TLS we want this to be false we want to be able to use this with just plain HTTP disable stats I'm going to also set to true we don't need to constantly save statistics with this echo or display them in the console it'll just get messy and then finally we need to set this enabled transports option to an array that consists of both websockets and WSS which is web secure sockets this option allows us to deploy and use this on either insecure HTTP sites or secured https sites and now we can do is we can use this Echo object to subscribe to channels and then listen for events on those channels so in our standby view we need to listen for the trip created event but we need to figure out what channel that is being broadcast on so let me just go back into our API and refresh my memory okay so this was our trip started event this is the one that is broadcast out whenever a trip is created initially and we had broadcasted on this channel passenger underscore with the passenger ID but see we have a problem with this that I didn't think about when I'd created this API is that we don't have a passenger associated with this trip yet well there's there's not a connection between a passenger and a driver so yeah a passenger did create this yet but the driver doesn't know that this needs to be broadcast on a general channel that all available drivers are currently listening to instead of just a single driver and a single passenger so let's change this out to something more generic something just like drivers so this is the driver's Channel and so that way any driver can join and listen to this and then we have our other event slide trip accepted that is a specific channel for a specific passenger that's that should be more applicable for our future use of it so anyway let's get out of this API now and go update our front end okay so Echo Channel and we specify that channel as drivers and then we listen to a particular event so by default the event we're listening for the name is the same as the class created is associated with so for us that would be trip started and then this second argument is a callback function which uses that event to do something for right now let's just console log that event out we'll call it trip created and pass in the event and this way we can see if our work is actually well working let's go back into the browser refresh and take a look at this okay and uh oh we get this error Pusher is not defined that's because if we go back to our source code I forgot that I also need to import pusher from that pusher.js library that we had added in earlier okay now let's try this one more time okay perfect so we are waiting for a ride request the console looks good and if we go into our websockets serve panel in our terminal we can see that we have a message all right we got a connection from the front end so we are now subscribing to the channel drivers so now we should be able to push events to this Channel and get them back from the front end so let's open up another window and I'm going to pretend to be a passenger with the same user okay so let's find a ride where are we going this time let's go to Park Ave CDs find a ride let's go and now waiting on a driver now that event should have been pushed out to the events server and then dispatch to the channels who were listening on that event and well it nothing's there wait a minute I I think I messed something up here yeah so going back into the back end code here I didn't realize that the trip started event that I had created is for when a trip starts so after I pick up a passenger so yeah I want to go back to how this was set up before I'm missing an event in here that I should have created and that's one for when a trip is created to alert drivers that hey this trip is available if you want to pick it up and so let's go ahead and create that now in our back end that's my fault I'll just copy this trip ended event here as trip created all right let me update some of the names around here and then the channel we will update to drivers so that is what we originally wanted to send out the trip created event to and now the last thing that I need to do is actually dispatch that event where it needs to be so that is in our trip store method let's go to that and let's go ahead and create the trip first so trip equals this and we'll return the trip and between the two let's do trip created dispatch with the trip and the request user okay so now that we have our event firing the way it should be let's exit out of the back end we're going to need to make an update on the front end now though and so in this Echo Channel drivers instead of listening for trip started we need to listen for trip created and let's go ahead and try this out one more time all right so find a ride destination Park Ave CDs let's go okay and going back to our other tab we see that we have in the console a trip created object and if we open this up we have a trip model associated with it with all of the attributes that we expect to come out of it so perfect exactly what we are looking for and we can see in the log for the websockets the serve event we have the message that was sent out with the entire Json string associated with that model so now we need to make some use of this let's go back into our source code so what I'm thinking is whenever a trip is coming through we should display a map that shows where that trip is headed or at least what the destination is and then allow the driver to either accept or deny that trip we should grab that trip information though that we saw come through the console log and hold it somewhere because in case the driver accepts that trip we can just keep that same information for any following screens and in order to do this I'm going to implement another Pinya store so like our location JS store let's create a different one for a trip and we'll just call it trip okay so remember we need to export cons use tripstore and that is equal to this Define store method in Pinya it's named trip and returns back this Anonymous function which itself returns back an object of items that we will be using in here to Define this store now let's go ahead and look at that object that came through one more time to see what we'll need to pull out of this to save okay well we'll need an ID in case we need to make future calls to this store we'll keep the destination in the origin objects that'll be handy the name as well we can show that as a display and uh maybe the user ID to just in case okay so let's do cons ID is equal to ref starting out as null same with the user ID and then we'll create our Origins and destinations are reactive objects with both latitude and longitude set to nulls and what was the other thing oh uh destination name is a ref that is set to an empty string right now so now let's go ahead and return these items so ID user ID origin destination and destination name now let's put this new store to use first of all let's get rid of some of these open tabs that we're not using right now and go back to our standby view let's import our use Trip store and initialize it with the cons trip is equal to use Trip store so what I want to do is I want to store all of those attributes coming from this trip created event that match up to the ones that I had just created in the store and in order to do that we can use that patch method again so we can say all right trip patch which will fill in all of the similar attributes between this event and the trip store and I can just call that on this event trip object because that was the model that held all those attributes now what I want to do is whenever also this trip comes through I want to change this message up here that's waiting for ride request so let's go ahead and add in a new ref here so we'll call this title and by default it is this waiting for ride requests and then I can swap this out for the title and then down here whenever this trip patch is created let's update that titles value to ride requested okay the final piece that I want to do though is whenever this ride is requested remember I wanted to show instead of the loader some kind of map with the details of the trip and in all honesty what I probably will just do is copy the directions map that we had whenever the user verifies and confirms their trip from a passenger perspective so what was that in map view uh yeah yeah this whole section down here where it builds a route out I'm just going to copy this and paste it in my standby View and wrap it up in some kind of wrapper so let me just go ahead and do that all right so I added in this wrapper div here and I have this map element I have a message of where the user is going to and I created these two buttons here we scroll over to decline and accept the trip that was presented now what I need to do though is I only want to display this if a trip has come through and I only want to display the loader If a driver is waiting for a trip so let's go ahead and add in a conditional in here using VF so we can say okay if there is no trip ID yet because by default the trip ID is set to a null ref so if there's no trip ID then we're just displaying the loader but else which we can use V else for we're going to display this whole map and card area down here and we can populate this we can say going to because we now have a trip object we know that a trip object has come through from the server so we can say okay we're going to trip destination name and then for the map we can use a center right over the trips destination object so this is a pair of latitude and longitudes so it fits perfectly in with this Google Map plugin so now if I go ahead and refresh and try to get a trip coming through so in the background I did another trip for the same location and we can see here it came through in the console we have our trip object and if I close out of here we can see the message was changed to write requested and the name of the destination is displayed as well the destination itself is actually centered right in this map and if we zoom in we can see here Park Ave CDs which is where I want to go is perfectly centered in the map I said before though that I wanted to add in the whole directions aspect of it and show where the passenger currently is and the whole trip I mean as a driver I have no idea if the user is going at five miles on the street or 500 so it makes way more sense to see the entire trip so going back into the source code let's go ahead and add that in and again we're just going to pull from this same map view component here ideally I'd refactor this out into its own component or its own functionality that I can Import in but I think this is the only two places that I'll use it so for the sake of time I'm just going to copy and paste it now I don't want to initialize the map directions in this unmounted method like I had before so I'm going to give it its own function let's call it init map directions and we'll paste this in here and instead of all of these location references we're going to be using trip okay so now to actually run this let's go ahead and whenever a drip created event comes through after this let's set off that init map directions function all right now let's see if this works and we're getting this error gmap not defined and oh that's because I added a ref up here for gmap and it's what I'm using to reference in this init map directions function but I'd never created an actual ref for it so let's create one now all right let's try this one more time and we have another error gmap value is null so I think what's happening is that we have this kind of race condition going on so whenever this event is fired off and we patch in the trip we're initializing the map directions immediately but there might be some sort of delay between the trip being patched and that function being called so this div VLS doesn't display the map yet and initialize it until maybe just a little bit later and so in order to combat this let's just add a timeout for this init map directions function so we can say all right set timeout for the init map directions function and we'll wait like two seconds that should be plenty of time and we have to move the geometry attributes because the trip origin and destinations if we go to the trip JS store it's just an object for origin and destination there is no geometry attribute and let's clean this up so instead of current point this is origin point and we'll copy that same name here to origin point all right that looks good let's save this and see if it works in the browser so yeah all right after a couple seconds it showed the full path for our ride requested and now we can either accept or decline this if we accept it we should be making our way to our passenger if we decline it though what I want to do is basically just wipe out everything about this trip on my local end and then go back to that standby loading area so let's focus on that first because it's the easier path to kind of go on so all right this button is up here that's the first one let's create a new click Handler and we'll call it decline trip and then let's go ahead and create that method for it and actually let's call this I like prefixing my button clicks with handle so handle decline trip and we'll copy that back into the button up here okay so what do we need to do well we need to remove everything that's associated with this trip store and kind of start over from its defaults again so what I could do is call Trip patch and provide an object where I specify that the ID is null the user ID is null but that that takes up kind of a lot of space and I might want to reset this trip in other components as well so instead what I'm going to do is I'm going to create a method inside of my trip store here and we're going to call this reset so what this does is kind of the same thing but self-contained inside of this store file so we're going to reset all of the values of everything that we have in here that can be specified in external components so all right we start out okay so the ID value reset to null same with the user ID and the origin latitude and longitude both null same with the destination and lastly the destination name now in order to use this we do need to export it like everything else so we can export reset and now in our standby view all we can do is just call Trip reset so now this will reset our trip which means that up here this V4 will be active so it'll show our loader again but we should also update the title to go back to the default as well let's go ahead and call Title value is equal to that okay so we got the decline trip all set now let's work on the accepting a trip again let's create a method for this so click is handle accept trip and we'll create a function for it underneath our decline one handle accept trip is a function and what should be in the body so what do we need to do well let's think back on our API if we take a look at the routes that we have here well we have this route for accepting a trip here and what that does is attach a trip to a particular driver and start some motions for going to the passenger so that's what we'll use so what we should do is we should call an HTTP request on it and create a post to API trip and then provide the trip ID and accept and the body for that needs to consist of just a single attribute the driver's location because we're using the request user or our auth token to pull in that driver's ID and Associate them with this trip but we still need to actually bring in the driver's current location and have that property updated manually well how am I going to get my current location well if you remember back on our location store which I can open up real quick remember that we had created this get user location method and we were using it to update a user's current location we were using this on the passenger side to update their location but if I'm logged in as a driver I can update my location as well and store it in a similar store and then use that in components related to being a driver so let's go ahead and add that in so just like trip is using use Trip store let's import our use location store and initialize it and then let's grab my user's location and store it as soon as this component mounts so a weight location update current location and because we're using a weight here this has to be an async function so now we have access to a location current object which will be my driver's current location so in order to update my driver's location all I need to do is call location current and then provided the geometry okay so that should satisfy all of the needs for that post request so now we should be getting a response back which consists of the trip with the updated attributes now I need a way to determine where I as a driver am going so I need to create kind of like a secondary trip so I saw a map view of where the passenger currently is and where they want to go but now I need to see where I currently am and I'm using the passengers location as my new destination so essentially what's going to happen is now I need to make a new direction to go from my current location to the passenger and then once I'm there we will actually start up there's a trip that's displayed on this screen here to go from where I picked them up to their final destination so in order to make this happen I'm going to use that same location store and I'm going to patch in the destination with the name of just passenger and the geometry as the origin from this response which is actually the trips origin geometry and once that patch is done I want to bring my driver to a new view they are currently on a trip going to the passenger so that is what I want to display so let's push them to a new view called driving and as always we'll catch an air if it occurs and console error it out or air it out to the console okay so let's go ahead and create this view before I go any further I'm just going to exit some of these open windows that I have right now so okay at the bottom of our router index file path driving now name driving and component driving view create the component and see how this is working in our browser okay so we're in our standby let's fire off a new trip okay so we have our ride requested let's decline it okay it cleared out the trip and now we are back on standby let's try that again okay this time we have a new trip now let's accept this all right perfect so now we went to this new route we are now driving to our passenger so it seems like we're getting a little closer to finishing this up so now we're getting right into the heart of the application we are currently driving to our passenger we need a map display to get us there so let's build out this View and don't forget I still know that we need to finish on this view as well but we'll get to that shortly okay so what I want to put here is something similar to this screen I want to have a map area and a little info window down here because right now I need as the driver to know where my passenger is and where I'm going to them so let's go back into the code base and we'll add something like that in our driving view template okay so I just pasted this basic template in here we have the gmap map component and a little area underneath of it showing what the current objective is on this screen so going back to the browser we can see that we have our title still our map area and then going to pick up a passenger what we need to do now though is we need to populate this map with our current location and the passenger's location so what I'm going to do is I'm going to add two points inside this map using the gmap marker component this will allow us to place Google Maps markers at specific points in our map and we can do that with the position attribute so again we need a marker for our current driver position and we also need a marker for our passengers position so we'll create two of these inside of our map and we also need to set the center of this map to some kind of coordinate so all these attributes we don't have any values for yet let's go ahead and figure these out and to do that we're going to need the location store because if you remember back in the standby view that we had we had patched a location to both the origin as the driver's current position and the destination as the passenger's current position so we can use both of those values to populate these markers so we'll create a location constant with the use location store method and then we can go ahead and use that location in our positions so for one of these markers location origin geometry and another one location destination geometry for the center of the map I probably want to do something programmatically where I can get the difference between these two markers and maybe have it Center on that I'll have to figure out how to do this for now though let's just set it to one of the locations we'll just do the origin geometry all right let me just make sure okay going in our store location oh that's something I need to change it's not origin it is current location current geometry so that is our current location and the destination that we have is the passengers location because remember right now I'm from my driver's perspective and we just need to set a ref for that gmap that we have by default it's null and that will connect this ref up here all right let's go into the browser and see what this looks like now okay well we see we have one point here which is good and if we zoom out we can see the other point that we have down here problem is we don't know which one is the current and which one is the destination so let's try to change these icons and give some of them some kind of customization okay so for our current location marker we can set this icon attribute to a property that we can create let's call this just current icon and board the destination destination icon now the gmap marker components require a few properties in these icon items so let's create them and populate it so cons current icon is an object and it requires a URL to be set which I'll just paste in this openmoji SVG file and we need to size it with scaled size width is 24 and height is 24. and let's go ahead and do something similar to the destination icon but changing the Emoji out okay let's see what this looks like now all right that's a little bit better so we have a car icon for us driving and we have a cowboy face icon for where our passenger is so here's where we are here is where we need to go two things though one is that like I had said earlier I want this to kind of automatically zoom in on the center between these two points so like right here would be good because when we started this it was zoomed in over here and centered on this icon so we couldn't tell that there was another one over here and then second is having these icons as they are really doesn't help me navigate to where the passenger is so what I'd like to do is every few seconds update my current position as I'm driving to this to this passenger's location so let's add both of those things in what we need to do is we need to update this Center dynamically using some Google Maps classes that we can access from the libraries that were pulled in kind of like our other components that we've done earlier in order to do that we need to hook into the gmap lifecycle event whenever it's booted up just like we had done before so scrolling down to the end of our script here let's do on mounted and whenever this is fired let's wait for that Google map to finish loading via that map promise property we get a map object back and we're going to use this to create a dynamic bound of latitude and longitude which should also dynamically zoom in this map as well okay well what do we need to do we need to create two points objects so we'll call this origin point and destination point we also need to create a bounds object so lat LNG bounds now for each of these points we need to call the extends method on that lat LNG bounds object so lat LNG bounds extend extend origin point and lat LNG bounds extend destination point and then finally the last thing that we need to do is we need to fit our map in the bounds that we had created so just map object fit bounds lat LNG bounds now let's go ahead in our browser and see how this looks all right and there we go so we can see the center of our map is like right here and it's kind of between both points that we have so both points are fitting inside of the bounds that we had created and are both viewable on the map so we got one part out of the way the next part that we need to do is we need to update this map as I move and drive towards my passenger I'm going to refactor out what I just created into its own method because I'll be calling this each time that we update this map with my new position so let's just refactor this out into its own method we'll call it update map bounds and it will require that map object as a parameter okay so now on mounts it initially I want to update the map bounds and then every I don't know five seconds we can set an interval and what I want to do is update the driver's current position and also update the map bounds which it'll automatically take in that new information because we're using the location store so update map bounds with that map object and I like I said every five seconds sounds pretty good so 5000 milliseconds but I need to update my driver's current position first so like we did with previous components my location state has that update current location method in it so I can just call await location update current location which will update the state with my user's current location I'm using a weight so I need to use an asynchronous method for our set interval okay well what does this look like now as you can see that every five seconds or so my driver location is updating I have it set to a random position so it's going to be kind of weird but we can see that every five seconds it is updating appropriately it's moving the marker and also the map Center and zoom is updating in response to that change in position so that both icons are always on the screen at the same time centered directly between them so this is exactly what we are looking for the only problem with this though is it's only updating from my perspective it's only updating from my view but whenever we go back to this passenger perspective and finish this screen I want to show my passenger where their driver currently is on their way to them so kind of have the same screen on their side in order to make that work I need to constantly be updating that driver location attribute in the database which also fires off an event now we have an endpoint for that which is perfect so all I need to do is inside of this set interval is I need to update the driver's position in the database as well and so we can do that by calling that API method instead of doing that in here that I'm going to be factored out into its own method and we'll call it a broadcast driver location so up here cons broadcasts driver location is a function and let's make that API call so HTTP post slash API trip and I need that trip ID which will pull in from our store in a minute and it was location I believe and so we just need to populate one attribute for it and that was the driver location and that is my location's current geometry because remember we had just updated that with this await location update current location method down here so then for the response that I get back we don't need to do anything for that at all because that is basically just syncing everything with the database side of things and the event that gets sent out is more for the passenger if there's an error though we'll catch it as usual and console error it out okay now we just need to get this trip ID and we can do that by pulling in the store up here like we use for the location store so constrip is equal to use Trip store now good practice though is that I want to remove that interval that we had set every five seconds whenever this component is unmounted so we can use this on unmounted Hook from View and we can create oh up here a ref so we'll call this interval ref and we can set that interval ref for our set interval object down here so interval ref value is equal to this set interval here and then on the unmounted hook on unmounted we can clear interval the interval ref value and then we can set that interval ref value again to know all right this is looking good now up here if we go back into the template I created this little gray area down here and what I want to use that for is a way of giving control to the driver to set where their trip is currently with some kind of state what this means is I want to give our driver the ability to say okay they have made it to the passenger and instead of relying on how close in proximity they are or anything like that the driver will have a button that says I've picked up the passenger let's start the trip and then likewise whenever we get to the destination there'll be a button that says I've made it to the destination let's complete the trip so let's add those buttons in okay so I have one for complete trip and one for passenger picked up now I don't want these to display at the same time I only need to display these one at a time depending on what the state of the trip is so remember if we go back into our database we can see we have these columns for is started and is complete and these are states regarding whether or not the trip is started or has been completed yet the one we're looking for is this is started column because that implies that the passenger has been picked up and we are going and we are going to their destination so I want to show this complete button only if VF the trip is marked is started otherwise I want to display this passenger picked up button which should fire off that the trip has started so now you can see here we only have this one passenger picked up button so whenever we click this that signifies all right we've picked up the passenger let's drive to their destination and so at that point we should switch the map over from being going to this passenger to going to the destination that they had originally set before we continue with that though let's switch gears back to this screen here which is what the passenger will be looking at as they're waiting for a driver to accept their trip because you have a few events that have been kicked off from the server that we should focus on and allow those to be seen before we move on any further all right well we have this screen here and this should populate whenever a driver accepts a trip with the driver's information so we know who's picking us up if we go ahead and head back into our source code we can get rid of everything that we have open right now we'll keep our router index file open as we've had it and this view was the trip view I believe yeah when a driver accepts the trip their info will appear here okay so we need to make a few adjustments to this screen to get what we want the first thing that we should do is include where we are on a Google map uh so we have some kind of reference and for that let's set a default of the gmap map component that we have added in here let's set the center to my current location's geometry and in order to get that we'll have to pull in that location store and we might as well also pull in the trip store as well okay now that we have this over the center let's also create a pin where our user is and we'll use the same icon that we had in the driver view as well okay now we have to wait and react for an event coming through the websockets to determine that a driver has accepted our trip and in order to do that we can use a similar setup that we had for the standby view on the driver's side of things so we take a look at that component again we need Echo and Pusher and then what we need to do is on the on mounted method we need to create a new Echo object listen on a channel and respond to that event coming through so let's get this set up in the trip view component and I'll just copy what we have here so far all right we put this in the on mounted method now our Channel and listen is going to change and we'll take a look at that in a minute but the echo object will stay the same we'll have to import Echo and pusher all right let's go and decide what this Channel and event we're listening to is okay so I went ahead and opened up our back end here if we go to this trip controller accept method that's when a driver accepts a trip we have a trip accepted event that gets dispatched where is this being dispatched two all right it's being dispatched to the channel passenger underscore and then my user ID now this is a slight problem though because if we look back at the controller all right when it gets accepted we're dispatching this with trip which is correct but then we're dispatching it with the requested user so the user who's authenticated into this but the problem is that's the driver and the channel passenger with the driver's ID really doesn't make that much sense because I don't have that yet the only time that I have that is after the trip gets accepted so what I need here is the passenger's ID which is what I had thought to reference to begin with so I need to change this inside the trip controller so instead of the request user that gets passed through here it needs to be the trips user so just trip user because also remember if we go into the trip model that we had created and scroll down we have a user property that belongs to the user class so that's who created the trip okay this makes more sense so now if we go back to the front end code we're listening on the channel passenger underscore and then the ID of the user who created the trip which is me so that would just be trip dot user ID because remember we have our whole trip object available to us from the trip store and then instead of trip created we are listening for a trip accepted okay now we need to change a few things in here so let's get rid of this and decide what we are changing whenever that trip accepted event comes through so scrolling up to the top well we have this waiting on the driver message which we can refactor into a message property or we'll do title so let's create that down here cons title is ref waiting on a driver and let's also create a message and that will be the information down here at the bottom so like whenever a driver accepts the trip and this little message here what do we want it to say afterwards so then we'll replace that with just message okay so now let's change these titles and this message whenever we have a driver who came through so now title value is equal to uh how about a driver is on the way and title message let's provide some details about that driver and actually the trip driver name um and actually the trip driver name is not an attribute that's available thinking back on it if we go ahead and look in the database if you look at drivers we have the year make model color license plate but the the name is under the user attribute here so we actually need trip driver user username and we get all this information well we should get all of this information from the event that comes back from trip accepted and actually we need to patch the entire trip store with the event that comes back to us so now this should give us access to that driver object okay well now that we have everything put together let's go ahead and see if this works so I went ahead and created a new trip we can see my little icon here as a passenger is waiting for a driver and now if we go to my driver view we have a ride requested so let's go ahead and hit accept on this okay so now I'm waiting to drive to that passenger and if we go to my passenger side view it still says waiting on a driver what's going on here so it looks like the event never fired and it's because this channel is being set to null so this this trip user ID isn't available if I take a look back in our map view in this handle confirmed trip method that we have here it's because I realize I never put in the patch for the trip store in this as well so once this trip comes back from the API we need to be storing this in the front end so I can reference it in later views and I never did that so let's fix this real quick so we'll import the use Trip store and then create that store here and then let's reference that in the response we get back from the API trip endpoint so all we need to do is trip patch response data okay let's try this one more time okay so now I'm waiting on a driver again and a driver sees that a red has been requested so let's accept it I'm now driving to my passenger and the user sees that a driver is on the way so this message has been changed but down here we're still seeing this same message that's not good all right let's debug this trip driver is undefined so that relationship isn't being included in the request coming back for some reason let's head into the back end and see if we can fix this okay so here's our API code now let's go to the trip controller and find the accept method start and accept okay well we're loading in driver user for this and all of these methods actually so I don't know why the driver isn't coming through unless in the trip store I don't have a driver object associate I don't I don't have a driver object associated with a driver coming through from the API so let's go ahead and change that so how about const driver is a reactive object and what properties do we have that we want to pull into this well let's see we need a an ID a year make model and license plate number and then I also need a user object associated with it as well which has a name and then if we go ahead and reset these values I want to clear these out as well so let's go ahead and do that too in this reset method okay so we nullified all of these values in case we reset this trip again so let's give this another shot okay so now I'm waiting on my driver one more time I get a ride requested as a driver I accept that ride I am driving to my passenger and it looks like we're still not getting that Driver's Info down here because there's a race condition as the patch happens and this message value is trying to be displayed in order to combat that I'm just going to prefix everything down here with the event object that comes through this way we'll at least have all of this information readily available immediately and we can display that on our front end all right one more shot this should be good okay I'm waiting on a driver I have a ride requested let's accept it I'm driving to the passenger and my passenger now sees that a driver is on the way Andrew schmelion is coming in a 2019 White Honda Accord with a license plate Florida one two three okay exactly what I wanted to see this is perfect the next thing that I want to do though is I want to display my driver's position on this map just like I have from the driver's perspective but in Reverse so have the driver sees where they are in relation to the passenger I want me as a passenger to see the driver coming towards me so it'll basically work the exact same way except instead of from the driver's perspective as the location changes around we need to listen for another event and that is the driver's position changing and then update our map depending on that so the first thing to note is that if we go into our database don't forget that we have this driver location column in our trip table so we have that available in our trip store object as driver location so the first thing that we can do is that when we get this trip accepted let's put the driver on the map so in order to do that what we can do is create a new marker here so we'll just copy this same one and its position is related to the current trips driver location and in this icon we will call it the driver icon and let's go ahead and just paste in the same kind of driver icon that I have from the driving view that we had created earlier so that would be this current icon so this is the driver icon okay so we have our driver icon ready now what do we need to do well we need to listen for another event so on that same channel remember we're going to listen for this trip location updated event that gets dispatched out again though we don't need the request user that's doing this we need the trips user so that we can have it dispatched on this passenger Channel okay so listen for trip location updated and we get that event and all we need to do is just patch in that information that's coming back just like the above event into our trip store see the way that this works now is that the user's location has been updated inside of that model and it is getting broadcasts out to us so all we need to do is just insert that new information into our store and Pinya and view will automatically repopulate this map marker with that current trips driver location one more thing before we take a look at this though is that the trip will not always have a driver location associated with it because by default when we first load it up the trip has no driver associated with it so let's only display this map marker if the trip does have a driver location associated with it we need to make sure this driver location property is available on our trip store though because I don't think it is and I am right okay we just have the destination in the origin not the driver location which means that it won't be reactive even though it could be updated by our back end so let's add that in here constant driver location is a reactive object with a lat and longitude just like the other locations and then like everything else when we want to reset it we will reset it down here okay so let's see this in action okay so now I have a drivers on the way and I can see my driver coming slowly toward me but jumping around the map a little bit so just like on the other view here I also want to implement that bounding box functionality so the map automatically moves and Zooms in to wherever my driver is to me as the passenger now you already saw that once so I don't really need to go through each individual step I'm just going to add the code into my trip view component okay so just like the driver's side view from the passengers perspective whenever the driver moves around the map zooms and updates its bounds based on those two points so we have our passenger view looking good now I need to go back to the driver's side view and we need to focus on this passenger picked up button so what we need to do is just fire off an event that says all right the passenger has gotten into the car now we can start going to their destination so let's go back we can exit out of these tabs that we have open I need to open back up that driving view component and it is this button right here passenger picked up so let's create an event handler for this first so at click handle passenger picked up and let's go ahead and create that method so scroll down you have a decent size component here we'll add this here handle passenger picked up is a function and so what do we need to do here well first we need to make a post request to that trip start endpoint that we had created because that's going to signify a trip has started so we can use our little HTTP Helper and we're posting to API trip trip ID start and the body for that is empty so we don't need to add anything else to it we will get a response back though which is our trip objects so as we get this response back let's make some changes to this View if we scroll up here well we're no longer driving to our passengers so maybe we update this message to be more dynamic or this title so let's cut this out we'll call this title and let's create a ref down here and maybe when we start this trip we say all right well now we are traveling to the destination but we need to change that destination because okay for right now as a driver you know my destination point this was this location destination which was pointed to the passengers previous location before I picked them up well we need to change this now and we need to make this the destination of the trip so in order to do that let's patch up our location and we're going to patch up the destination object inside of it the name we're going to set to that response back that we get the destination name and then the geometry for it is the response data destination object so this request is going to get us back a trip object so that trip objects destination and destination name we're going to use that and patch in our location's destination so now from my perspective as a driver the destination shouldn't be set to the user's desired location and then as always we'll catch an error coming back and output it to the console okay let's see how all this works together okay so I have a ride requested let's go ahead and accept it and I'm driving to my passenger now and let's go ahead and say that we have picked them up and now that icon disappeared and it got put back to where the destination that we're traveling to and the map is updating again in real time so we are traveling to this destination now one thing that you can note though is that this button still says passenger picked up we need it to swap to the other button to complete the trip once my passenger has been dropped off so let's find out why that's not working if we scroll up to where that button is we can see if trip is started but we never updated our trip store object so let's scroll down to where we handled the passenger being picked up and then after we do the location patch let's patch the whole trip as well with what we get back from the API so our entire response data object so now that button will say all right after the passenger has been picked up we will need to complete the trip and speaking of completing the trip let's go ahead and add that functionality in now it's basically the exact same that we did for the handle passenger picked up so we can just create a click event handler we'll call this handle complete trip and create a method underneath our other one called handle complete trip again this is just an HTTP post going to API trip ID and I believe the API endpoint was complete uh no it is end foreign okay so again we'll get a response back from that and what should we do for that well let's change our title one more time and we'll say trip completed and we'll catch any errors that come out but we can't just say all right the trip is complete and and leave it at that we need to do something with this data that we get back well we can patch the entire trip store like we did above with that object that we get back from response data and that'll give us access to another Boolean flag that we have on there which is the is underscore complete flag so we can maybe play an animation or something to show the driver that their trip has been completed successfully and then in the background we can like reset all of the data that we have in our trip and location stores and then bring the driver back to their original startup position so they can be ready for the next trip that comes through now if we open up the trip store we already have this reset event but we don't have one for the location store so let's add one in here cons reset is a function and let's clear out everything that we have in here so this will be our reset and then we'll just include that in the export for this store and so now we can use after this gets patched up we can say trip reset location reset and finally let's use the router to push the driver back to their standby route now I don't want this to all happen immediately though so let's set a timeout for this let's wrap all of these in here and we'll give it about three seconds that should be enough to play some kind of nice animation speaking of which the animation let's scroll up into our template and let's see where we can put that so I think a good place for it would be at the same level that this div is so what we can do is we can add a conditional that says all right if the trip is not complete so if not trip is complete then we're going to display all of this down here so our map our buttons and everything else otherwise though let's display this block here and inside of here let's create this little animation component that plays once so in our components how we have this loader view let's let's create a new one we'll call it tada.view and I've pasted in this basic component that I've written and animated with CSS so it just shows this Emoji here and it has a animation that lasts two seconds on it based on these keyframes that I've set down here so ideally what this should do is that as soon as this window becomes available and actually let's add in that ta-da component as soon as this window is rendered out whenever the trip is complete it'll play that animation which lasts two seconds and then there will be about one second of emptiness before the driver is sent back to their standby area ready to start a new trip actually before we go further with this I just realized that I didn't add in those flags to our trip Pina store so let's go ahead and do that so we have cons is started is a ref that's by default false and cons is complete or is completed what was it is complete is complete is also a ref with false let's add these values to the reset down here and then we will add these to the export as well okay let's go ahead and see how all this is working together okay so as a driver I have a new ride that's been requested let's accept it and now I'm driving to my passenger taking a few seconds let's drive to them and I've picked them up so now I'm traveling to their destination and we're traveling and we're driving all the while you see down here the button has been changed to a complete trip so now let's say that we have gone to our destination I'm ready to drop my passenger off so let's complete the trip hey the trip is completed I got a little animation and I'm right back to and it has stopped why has it stopped well the console says oof invalid assignment to cons is to all I completely forgot that in our trip store during these resets I need to use dot value a rookie mistake okay so let's Replay that animation one more time all right so we went from the trip being completed back to the standby so now I'm waiting for another ride to come through as a driver but how does this look from the passenger perspective well nothing's really changed since it said that the driver was on the way there's a couple more events that I should have been listening to so let's go ahead and add these in we can get out of this trip and drive our view and let's open up the trip view which is from the passengers perspective so if we scroll down to the bottom we have the trip location updated but now let's also listen for a different event and if we go to the back end we have this trip started and we also have these trip ended event that we can be responding to so let's add both of those in so trip started and listen trip ended so for the trip started for all these actually let's patch in the trip with the responding model object and let's update some of the information that's on the screen so a driver isn't on the way anymore we can now say that you're on the way to your destination or how about you're on your way and then we can change the message to where we're going so you are headed to uh trip destination name but remember like we did on the driver's side perspective we also should probably change from the passenger's view where their destination currently is so as a passenger I need to now be in the car and the destination needs to be the little cowboy head so how can we do that let's go up here and let's see what we are using so the origin point that is my current location the driver point is the driver location well whenever I get picked up my driver location and my location current are going to be the exact same the driver location is always updated though so it'll be easier if we just swap out the current location with the trip destination so it might be a little confusing because of the nomenclature but this will make recording those a lot easier so all we need to do is patch in this location current with the trips destination geometry so going on the trip started let's patch in the location and we can use geometry I'm sorry it was current geometry is equal to trip destination so now that should put the Cowboy head at the destination that I'm going for and then what happens whenever the trip has ended well let's flash again like a little message on this screen maybe just change the title for a few seconds and then from there the users just go back to the beginning screen so they can be ready for another ride they pick up or if they want to switch to being a driver and like we did on the driver's side of things as well let's reset everything for the passengers stores so we'll create a title that says you've arrived a message a message that says hope you enjoyed your ride with e trip driver username and then we will set a timeout to reset the trip reset the location and send the user back to The Landing View okay now that this is all put together let's see this section in action from the view of the passenger okay so now I'm waiting on a driver and a driver is now on their way they are coming toward me in a white Honda Accord with a license plate fla123 they're close by so maybe they'll pick me up okay now it says that I am on my way I'm headed to apenberries Gardens and we can see that I am here in the car and my destination is up here with the little cowboy hat icon so now we're just waiting for the drive to finish and I guess the drive finished up but I didn't see my message flashing the screen and that's because I set a timeout with no timeout let's set this as 10 seconds that should be enough to read our message and then wait for our return back to the landing page okay let's see that last part in action one more time okay we are on our way to open berries Gardens now let's see what happens when we get there all right you've arrived hope you enjoyed your ride with the driver Andrew schmelian and then after a few seconds we are back to The Landing screen so now we can choose either start driving or find a new ride and start this all over again and well there you have it that's how to build a basic ride sharing application with laravelen View we built a back-end API with laravel using websockets events and notifications and we built a front-end application with View using Tailwind Echo and Google Maps I hope you enjoyed putting this project together with me as much as I enjoyed building it and recording this video now this code was created and meant to show a functioning example but it isn't really fully complete at the moment it was mostly meant to be a demonstration and I think that served that purpose pretty well there's a good amount that can be refactored there's a good amount that can be refactored in this like making a component out of the map elements in the front end or adding some automated tests to our back end there's also a few bugs that might have there's also a few bugs that you might have noticed already but there's also there also might be one or two bugs that you might have noticed salt there also might be one or two bugs that you might have noticed anyway there also might be a few bugs in here that might there also might be a few bugs in here that lead to some unintended behaviors if there's interest in it I will create if there's any interest in it I'll create a follow-up video showing how to fix some of these issues and improve the front end and back end code bases at the same time if there's interest in it I will show a follow video showing how to fix any issues or concerns that you might have as well as improve and refactor the back end and front-end code bases speaking of which feel free to check out that source code the link for it is in the top pinned comment I've also added links to some resources and packages that were used throughout this video in the description as always if you have any questions about this or any other web development topics please feel free to reach out to me on Twitter or in the comments below thanks for watching
Info
Channel: Andrew Schmelyun
Views: 41,585
Rating: undefined out of 5
Keywords: laravel, vue, vuejs, php, javascript, php tutorial, laravel tutorial, vuejs tutorial, fullstack tutorial, full stack tutorial, full stack php app, build an app, ride share app, laravel app tutorial, laravel full stack, laravel full stack tutorial, vuejs full stack tutorial
Id: iFOEU6YNBzw
Channel Id: undefined
Length: 252min 52sec (15172 seconds)
Published: Fri Apr 14 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.