تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Restrict Like Toggle Access0:00

Now that we've sold the login logout ui, let's go and complete the implementation of the like puppy toggle. Okay, so the very first thing I don't like at the moment is, as you can see we are logged out here but we can still see the like toggle implementation. And this should be a feature that is only reserved to logged in users because the liked puppies and the short list are going to be specific per User. So it makes no sense to have that functionality if you're not logged in.

So it makes no sense to have that functionality if you're not logged in. So this is the like toggle component which is responsible for the speed of ui. And you can see that it's going to show a heart that is either filled in pink if the Puppy is liked, otherwise it's just an outline light gray. And so instead of completely hiding the like toggle, I think that if you're logged out you should just see the unlike status and maybe not be able to click on it.

Disable Logged-Out Button1:00

that if you're logged out you should just see the unlike status and maybe not be able to click on it. So we should disable the button. So exactly like you've seen in the previous lesson, we are going to use the usePage from Inertia to determine if the User is logged in or not. And then we can do some tweaks to the rendering to just display the gray heart if the User is not logged in. So at the top here I will import usePage from Inertia and then down here

So at the top here I will import usePage from Inertia and then down here after the state, let's grab our oath with const oath = usePage().props and let's also import the sharedData type to pass to the usePage. Alright, so the first thing I can do is disable the button. If we don't have a User so disabled, uh yep that will work like this. We could have done, do we have a oath that User if yes

uh yep that will work like this. We could have done, do we have a oauth that User if yes disabled is false, otherwise it's true. But I kinda like the shorthand here like so and so if we look at the like toggle now the heart should still be here but I should not be able to click on it and yet I'm trying to click but nothing happens because these buttons are now disabled. But if I was logged in, the button would be available. So this is what we want. Very cool.

But if I was logged in, the button would be available. So this is what we want. Very cool. All right, we can keep the unclick logic so far the same for now. We'll tackle this later. And so maybe not the cleanest way but we can check here for the class styles to trigger the liked status, we need to match this condition and have an auth that User. And so if auth that User is null, this is not going

and have an oath that user. And so if oath that user is null, this is not going to be true this. So we are going to have this fallback value. So now because I'm locked out, I'm expecting none of the puppies to have a pink field heart. So let's take a look and yep, indeed all of the puppies have a blank heart which is non clickable. Uh, so this is what I'm expecting. Let's do one more thing. Maybe when we hover the heart we can have this little

Uh, so this is what I'm expecting. Let's do one more thing. Maybe when we hover the heart we can have this little unavailable mouse cursor style. And here I'm not a hundred percent sure if this is the right thing to do in terms of accessibility, but it's going to tell users, hey, you don't have access to this feature. And maybe what you could do is have a little popup that says, Hey, sign up. Log in to be able to like your puppy and shortlist them.

that says, Hey, sign up. Log in to be able to like your puppy and shortlist them. Alright, so let's try that on the button class next to group here. I will go cursor and they should be disabled. Uh, nope. Is it not allowed? Yep. And so now we have this subtle hint that we should log in if we want to be able to use that feature. Alright, and now I'm going to log in here

to be able to use that feature. Alright, and now I'm going to log in here with my accountSimon@laracasts.com. And now this is still not the real deal but I should have these four puppies that I liked and whoops, I've just realized that I've made the disabled cursor for everyone. But it should only be like this for non logged in users. So here because we using Chat CN UI, we could use the CN function

So here because we using chat CN ui, we could use the CN function but we can also just have a template tag like this and then scope this into the oath User question mark and then that would be an empty string. Otherwise we would have cursor not allowed like so. But just know if you prefer here because we're using the starter kit, we have access to CN or CLSX, which is going to let you make that a little bit cleaner so we can have a class of group

or CLSX, which is going to let you make that a little bit cleaner so we can have a class of group and then we can just do oath that user or the opposite and go end, end cursor not allowed. So this is a little bit cleaner to me and also it's not going to leave an empty space in the class attribute in the DOM. And so now the cursor shouldn't be not allowed only if we don't have a user and here because I'm logged in it'll show the normal cursor.

Create Backend Like Route4:40

don't have a User and here because I'm logged in it'll show the normal cursor. Okay, cool. Alright so now we are going to wire this up to work properly with our data in our backend because right now it's making an API call to an external API. So let's start with the endpoint, which is actually just a regular route. It's going to be a PATCH route because we are going to modify an existing record.

It's going to be a patch route because we are going to modify an existing record of the Puppy model. Uh, so let's go set that up in Laravel and then we will do the adjustments in here for the UI to work properly with a new setup in web.php we are, because now we want this functionality for logged in users only. We are going to piggyback in this route group that is guarded by the auth middleware.

We are going to piggyback in this route group that is guarded by the auth middleware. Alright, so like I mentioned, we want a PATCH route to update a record route column, column PATCH. And so for this we are going to go puppies and then dynamicPuppy. And so here we have a dilemma 'cause we could keep just /puppies/{puppyId}. Uh, because it's a PATCH resource, it's kind of clear that we are updating it but we just updating the like status.

Uh, because it's a patch resource, it's kind of clear that we are updating it but we are just updating the like status and what if later on there is an update puppy that lets you change the photo the name. This is going to get confusing. So I think we are going to add a /liked to the URL for this route. So it's a little bit clearer that the intention is really to change the liked status. All right, so let's add /liked.

to change the liked status. All right, so let's add toggleLiked. And here we could have an inline function but I think we are going to create a PuppyController. So let's go PuppyController class. Uh, and we are going to call the method like, so actually I think I'm going to have like here as well for consistency and the name. Yeah, toggleLikeStatus is a little bit more descriptive but I think it's a bit long.

Yeah, toggle like status is a little bit more descriptive but I think it's a bit long. So let's go puppies that like for the right name as well. So obviously we need to create that controller. So let's go php artisan make:controller PuppyController. All right. And in here we are going to have a public function like so we're going to have the request but we also going to have the puppy. And so here we want to use route model binding.

but we also going to have the puppy. And so here we want to use route model binding. So let's type this as a puppy and let's also type hint the request. Alright here the task we're trying to accomplish is to check if the puppy is liked and if it's already liked, well we want to unlike it but if it wasn't liked we want to like it. And so you could think that we need to first check if the puppy is liked.

And so you could think that we need to first check if the puppy is liked and then if yes unlike it and so on. And the way you can check that because we have access to the puppy here is to go puppy and arrow likedBy here, which is the belongsToMany relationship. Remember if I go in the Puppy model, we have this likedBy method and so Laravel being so cool and pragmatic, there is a super handy toggle method on

by method and so Laravel being so cool and pragmatic, there is a super handy toggle method on belongsToMany relationships. So all we have to do is call the toggle method on this puppy likedBy and it's going to take care of checking if it's on or off and switch it. How cool. So here all I have to do is go toggle. And because dislikedBy is an array, we want to toggle the specific array index which belongs

And because dislikedBuy is an array, we want to toggle the specific array index which belongs to the logged in user. And so here we can pass the request userId just like this. So if we had an array of 1, 3, 6 and here the request userID was one, we would end up with three and six, which is precisely what we want to achieve. Okay, let's get rid of all of this because this is basically covering it.

Okay, let's get rid of all of this because this is basically covering it. And then Inertia expects a redirect for all non GET requests. And so we can return redirect here and then we could pass the route name which is home. And so that would work, but because we are already on the home route, we just want to go back to where we were and conveniently enough we can just do return back. Alright, I want you to take a second to appreciate

and conveniently enough we can just do return back. Alright, I want you to take a second to appreciate how elegant this is. We are taking the puppy, we are toggling the like status and we are returning back and now we're going to compare it to what we were doing in the React app where we had to do an asynchronous fetch call to an API externally. And then you're going to see how much nicer the frontend implementation that we're going to do really is.

And then you're going to see how much nicer the frontend implementation that we're going to do really is. Alright, so we have a PuppyController with a like method and then in our web.php we are calling this PuppyController that we need to import and we invoking the like method here whenever we hit with a PATCH method, puppies, puppy like and also note that it has a named route of puppies.like so technically all I have to do from the front end is make a PATCH request.

Switch to Inertia PATCH9:21

so technically all I have to do from the front end is make a PATCH request to this name route. That's all we have to do. So let's go back in the like toggle component. And so this comparison here is sort of the easy part but where the grunt of the work happens in the Vanilla React app is on that onClick event. So it's an async function.

that unclick event. So it's an async function. We set a paintingStage that we control manually and then we await this toggleLikeStatus function And if I go there it's in our queries and this is where we hit the API endpoints. We have to pass the headers, method PATCH and then handle the success or error flow and then the backend is doing the similar work that we've done but we have to make sure the endpoints are

and then the backend is doing the similar work that we've done but we have to make sure the endpoints are matching and we maintain both sides. Alright so check this out, I'm going to completely delete the unclick logic here. Gone. We will lose temporarily the pending state but we'll bring that back. And so I will transform this button here to a Inertia link component. Now this feels a little bit weird to use a link tag,

link component. Now this feels a little bit weird to use a link tag, but Inertia links can have different methods than just get and they will be turned into buttons automatically. So here I can pass the method of, and the one we want is patch and then for the href, because we have a named route in our web.php that we can use Ziggy and go route puppies like So now this link component is going to be a button.

and go route puppies like So now this link component is going to be a button that is going to make a PATCH request to the URL for this like method on the PuppyController. That's pretty simple isn't it? Oh yeah, of course I need to pass the puppy parameter to the Ziggy route. That makes sense. So in the PuppyController you can see that the like function is expecting a puppy. And so Ziggy is clever enough to say Hey, I'm expecting you

that the like function is expecting a puppy. And so Ziggy is clever enough to say Hey, I'm expecting you to pass a puppy here. And so because we receive the puppy here in the like toggle, we can pass that puppy here and I think we can pass the whole puppy but we can also pass just the puppy ID and Laravel should be clever enough to work out which puppy we talking about. Let's try this. Okay, so now if I try to go

to work out which puppy we talking about. Let's try this. Okay, so now if I try to go and like Rex, whoops, it's jumped to the top and it's still not liked but if I refresh the page it is actually liked. So let's try that again. Click we jumped to the top of the page, the state hasn't changed and if I refresh it's working but obviously it's not working as good as we hope. So there's two things that we need to fix.

but obviously it's not working as good as we hope. So there's two things that we need to fix. The first one is we don't want to jump back to the top of the page. Ideally we wanna preserve the scroll position to where we were. And guess what? Inertia's Link component can take a preserveScroll attribute that will do just that. And then the other thing we wanna do is work out why the state of the page is not updating and we have to refresh.

And then the other thing we wanna do is work out why the state of the page is not updating and we have to refresh. But let's start with preserveScroll. So on the Link component here, I can simply pass the preserveScroll attribute, just like that. And so now if I scroll to a very specific position here and I try to like Russ, I've clicked it and the state should have updated but the scroll position hasn't moved.

and the stage should have updated but the scroll position hasn't moved. And if I refresh the page you can see that Russ is liked. Let's do that again. I'll scroll up, I will toggle the like status, it's not gonna work, but if I refresh the page it has changed. Alright, so we fixed up the scroll position change, let's tackle the other problem. And for that one, I have a funny feeling this has nothing to do with Inertia

Remove React Puppy State12:49

And for that one, I have a funny feeling this has nothing to do with Inertia but remember how we were getting the puppies and setting them to state for the whole application. And I think now the state is being taking over what the actual data from Inertia is and so everything is getting confused. So we need to peel back and strip off this puppy state that we passing to the whole application progressively and let Inertia.

and strip off this puppy state that we passing to the whole application progressively and let Inertia and Laravel handle the source of truth which is the data coming from our backend puppies. Alright, so let's investigate. First thing you can see, we don't need setPuppies anymore because we are not calling setPuppies. We also are not going to use this manual pending state either, but I'll keep it just for now because it's used here.

to use this manual pending state either, but I'll keep it just for now because it's used here. Okay, I can also remove the setPuppyType here, which means I can remove the dispatchSetStateAction from react. So we cleaning up a lot of things and so we receive a puppy from the PuppiesList component and if we look at PuppiesList, well now we can not pass the setPuppies anymore, but I feel like this puppy here is coming

well now we can not pass the set puppies anymore, but I feel like this puppy here is coming from the wrong place. The puppy card doesn't need set puppies either, which means I can get rid of that. We cleaning up a lot of codes, but if we keep going back up, we don't need to pass that here, which means we do not need to receive it and we don't need to type it. And you can see we are undoing a whole lot of prop drilling.

and we don't need to type it. And you can see we are undoing a whole lot of prop drilling to pass this state seller because now we don't really need that at all. But now we back up the tree and this is where we receive the puppies. And so now we can go back higher even in the component tree in welcome.tsx page and here once again remove that. But now is the real problem.

and here once again remove that. But now is the real problem. We are receiving puppies but these puppies have been set to state here. And so what this means is now react holds the puppy state in memory and makes the decision of what should be rendered. So we have our inertia route that's giving us some information, but then here we've instructed react to have a puppies state array.

but then here we've instructed React to have a puppies state array and make all the decisions based on the puppy state. We are not using setPuppies anymore. And so the state of the puppies never changes, which is why we have no like toggle changing happening on the front end. So we need to not set the puppies to state uh, and pass directly the puppies from the backend. Remember the Inertia response

and pass directly the puppies from the backend. Remember the inertia response where we pass the puppies on the homepage route, we need to pass that directly to our PuppiesList component. Hopefully that makes sense. And like I said, I will not delete that just yet because every component uses it. But by the end of this course we will have stripped out all of these states. But for now what we want to do

out all of these states. But for now what we want to do is take these puppies this time, these are the puppies coming from the backend, from the inertia response. We pass them there. And so when we receive them here, what we wanna do is instead of setting them to states, we want to pass these pups here directly to our puppies list. So all I have to do is change these to pups.

to our puppies list. So all I have to do is change these to pups. And you know what, instead of calling them pups, I want to call them inertia puppies just to be a little bit more explicit. So I will replace here, here, there and down there inertia puppies. So it's a little bit clearer that these are the puppies coming from our inertia response. So now we have a puppies list that receive the puppies

that these are the puppies coming from our Inertia response. So now we have a puppies list that receive the puppies as the inertia puppies. And so now these puppies get passed down all the way to the likeToggle. And so now a likeToggle puppy is actually the one from Inertia's response. And so hopefully now when we toggle the like status, the page state is actually going to update correctly. This is what I'm hoping. Let's have a look.

the page state is actually going to update correctly. This is what I'm hoping. Let's have a look. Alright, big reveal, let's try to, unlike Luna, ready 3, 2, 1, click and it worked. No scroll change and the like toggle has changed. And so I can now like Leah. let's like all of the puppies because we super excited that we have implemented the feature. Obviously the shortlist doesn't work yet because again it's currently wired up to the state,

Obviously the shortlist doesn't work yet because again it's currently wired up to the state, the puppy state that is not being updated. But what we wanna do is flow these inertia puppies throughout all the applications. And actually you know what, it just hit me that I should be able to already now pass the inertia puppies to the entire app and completely get rid of the puppy state because we do have a shape of puppy data that is exactly

and completely get rid of the puppy state because we do have a shape of puppy data that is exactly what it used to be in the original application. So let's give it a shot. I think we could get away with using just the Inertia puppies and getting completely rid of the application state for the puppies. So we still have to refactor things like the short list that uses setPuppies or the new puppy form that uses setPuppies.

that uses setPuppies or the new puppy form that uses setPuppies before we can delete the state. But let me try to just pass the inertia puppies instead of the puppies here for the short list and for the form as well. And so yeah, nice. Our short list has been updated. So we still cannot remove the puppies from the short list here 'cause we haven't implemented that just yet. But if I was to toggle Bella here,

here 'cause we haven't implemented that just yet. But if I was to toggle Bella here, I think it's going to disappear up there. Let's try and yep, remove Rex, remove Luna and things are starting to look good. Okay? But remember that we have lost our pending states, the loading spinner while the action is being performed here locally. It doesn't really matter because it's so fast. But when this application is deployed to a server,

It doesn't really matter because it's so fast. But when this application is deployed to a server, I think there will be some latency and so we need to bring that back. Now this video is getting a little bit long, so we are going to do the pending state in the next lesson. But before we move on, I want to fix one tiny thing. And you might have noticed it and pointed fingers at me, we are going to fix it. Do you know what I'm talking about? Let me show you.

Fix User-Specific Likes18:46

and pointed fingers at me, we are going to fix it. Do you know what I'm talking about? Let me show you. So I wanna show you a little bug that I've left in the application in the like toggle here. So we've changed all of this and this is working, but in the check here, I always check for the idea of 1 which was a fake User. So that means that if I was logging with any other User, we would have the exact same liked puppies showing then Simons or the User number 1 liked puppies.

we would have the exact same liked puppies showing then Simons or the user number ones liked puppies. And we definitely don't want that. This has to be dynamic based on the id that user that and now this should behave truly dynamically. So let's check the front end. Simon has six liked puppies, but if I log out, whoops, we have another bug. What's going on this time? Ha. Of course we're trying to pass the user id,

What's going on this time? Ha. Of course we're trying to pass the user id, but now that we've logged out, we don't have a user and therefore we can't access the ID property on No. So actually if we check for the oath that user first, it'll fail if there is no user. And so if we go in that order, I think that this is going to work. Yeah, okay, it works. So basically before we were trying to check.

Yeah, okay, it works. So basically before we were trying to check for the oauthUserId first without knowing if there was a user and when there was not like it was the case when I logged out, this would uh, explode. But now we first checking if there's a user. So if we logged out this would be false. And so we'll short circuit that and go directly to the fallback scenario. All right? And so now all the puppies should be grayed out.

and go directly to the fallback scenario. All right? And so now all the puppies should be grayed out and I cannot interact with them. And as you can see it says, Hey, sign in and then you can do this. So let's create an account. This one is going to be gina do kins gina@example.com plus word plus word. And we're going to create an account for Gina, huh?

word plus word. And we're going to create an account for Gina, huh? What's going on? We are logged in with Gina Dawkins who should have zero puppies liked, but the short list is showing six and I have just figured out what's happening. So that's actually pretty interesting and it makes sense because we faced the same problem just before. So can you work out why we are seeing seemingly the six puppies from Simon in uh, Gina's short list?

So can you work out why we are seeing seemingly the six puppies from Simon in uh, Gina's short list? Well, exactly like before, remember I've just fixed a little bug where we were relying on the ID of one instead of the real user id. Well, my guess is exactly the same is happening in the short list to display whatever puppies we want. We look for this condition that it's matching the ID of one in the likedBy.

We look for this condition that it's matching the ID of one in the liked buy. So let's go and see if we can go and fix that. And so exactly like this here. My guess is in the shortList we are doing the exact same check and here it is and that's why it's not working. So I was gonna fix the shortList later, but now I feel obliged to do it in this lesson right here. So let's import usePage from Inertia React, then get the oauth.

So let's import usePage from Inertia, then get the oath. Copilot now completely understands the assignments. And here we are going to check for Oath User, but we're going to have a optional chaining question mark id. And let's pass once again the shared dataType. So it's going to try to use the userId, but if it doesn't exist, it'll not explode. And so now yes, we have a reflective short list.

but if it doesn't exist, it'll not explode. And so now yes, we have a reflective short list that represents the User. So now Gina has three liked puppies, but if I log out and log in right back as Simon now we have different liked puppies and shortlists for every User, which is precisely what we want. Let me one more time like every puppy for no other reason that they are all gorgeous and beautiful.

Let me one more time like every puppy for no other reason that they are all gorgeous and beautiful. And in the next lesson, we are going to wrap up this implementation of the like toggle the like status by bringing back the pending state. So we are going to add a sleep function in the backend to make it intentionally longer so we can see what happens while the operation is happening. I will see you in the next one. Be good until then.

what happens while the operation is happening. I will see you in the next one. Be good until then.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟