Shortlist pagination bug0:00
Before we continue, I wanna do a little bit of refactoring because we've added some features, we've moved things around, we've found a couple of bugs. So I think we should go and do a little bit of cleanup. You might remember that we had found a bug with the short list. So here I only have two puppies in my short list, but if I go to the second page, you can see I like four puppies up here. And now it's only showing these four puppies from this page.
you can see I like four puppies up here. And now it's only showing these four puppies from this page that's happening because we're currently passing the paginated puppies to the short list as well. So it can only see whatever puppies are passed to the front end instead of the whole list. And we don't wanna pass all the puppies, the 109 puppies and then filter through them to see which ones are liked. So we sort of really want to pass the users liked puppies to the short list, which is quite different.
Add likedPuppies prop0:57
So we sort of really want to pass the users liked puppies to the shortlist, which is quite different than the setup we have now. So if I go in the PuppyController and we check the index method here, you can see that we are passing the puppies here as well as filters. But the puppies are only the paginated puppies. And so I think here we also want to pass another prop, which is going to be likedPuppies. Now we gotta be careful here.
which is going to be liked puppies. Now we gotta be careful here because this route is also served to non logged in users and the liked puppies only make sense. It's only a concept if we have a User. So we are going to check if the request has a user question mark, and if it does, we want to return a PuppyResource collection based on the User's liked puppies. So again, request user.
based on the user's liked puppies. So again, request User. And we are going to reach for the liked puppies property. And before I forget, if we do not have a logged in User, we'll pass an empty array like this. So if we do have a User, we have the PuppyResourceCollection or the liked puppies. If we don't, we have an empty array. And to refresh your memory, disliked puppies here, if I go on the User model is the belongsTo
And to refresh your memory, disliked puppies here, if I go on the User model, it is the belongsToMany relationship, which is basically the puppy_user pivot table that we've set up. All right, so let's go receive these liked puppies on the front end to check what's happening. So in the index page here, we are going to receive the liked puppies and this is going to be an array of the puppy type like this.
Fix PuppyResource likedBy2:28
puppies and this is going to be an array of the puppy type like this. And so maybe for now, just before the main components, let's render a pre tag with the json_encode liked puppies just to check it out. Uh, whoops, it looks like we've just uncovered a bug with our Puppy JSON resource. And as you can see, it has to do with the like buy property where we try to pluck the id. So let's go in the PuppyResource
where we try to pluck the id. So let's go in the PuppyResource and I will scroll down to the likedBy property. And indeed here we're trying to pluck the id of the Puppy, but we're trying to only do this if we have loaded the likedBy relationship. And so in our PuppyController originally we had the puppies, which is a collection where we load the likedBy property. But here we're trying to use the PuppyResource without
where we load the like buy properly. But here we're trying to use the puppy resource without loading dislikedBy relationship. And so here instead, and I'm sure coPilot will figure it out straight away. Yep. We want to first check when loaded is likedBy and then have a function where we then go and plug the likedById. So let's accept that one and delete this one. And I'm glad we got to fix this.
So let's accept that one and delete this one. And I'm glad we got to fix this. And so now if likedBy is not loaded, this should never be returned. And as a result I can now see the list of liked puppies for the logged in User. And there's about six. And as you can see, it's not limited to the current page. So if I was navigating to the page one, we would have a different set.
So if I was navigating to the page one, we would have a different set of liked puppies in the short list but not in here. And let's try to remove diamonds to prove that it's the right thing and it's gone. Alright, so back to the index page. It looks like we have the right data that we want to pass to the short list. And so let's do something that's going to trigger a next refactoring.
Refactor ShortList input4:15
And so let's do something that's going to trigger a next refactoring. But for now we are going to pass the likedPuppies as likedPuppies to the main components. And I'll remove this pret tag here. So we need to go in Main and accept the likedPuppies and once again it's an array of the Puppy type. And so now I can finally go and pass it to the ShortList. Instead of passing the puppies here, which is the paginated data, which was the bug,
Instead of passing the puppies here, which is the paginated data, which was the bug, we basically are going to pass the liked puppies. All right, so now we are passing the correct set of puppies to the shortList. So is the shortList gonna work? Not quite yet. As you can see, we have a blank page of death and if I look at the console, we're going to have an error and it's trying to do an includes check on something undefined and already know what's happening.
and it's trying to do an includes check on something undefined and already know what's happening. But let's go investigate. So if I drill through to the shortList, we receive the puppies and you can see that then we here try to filter over the puppies and then check which one is liked by the author based on the id. So this check was necessary beforehand when we were passing.
by the author based on the id. So this check was necessary beforehand when we were passing all the puppies or I guess the paginated puppies to the short list. And then it has to do the work of figuring out which one is liked. But now we have already upfront decided that we only passed the liked puppies for a certain User so we don't have to do any filtering anymore. And actually we need to get rid of this filtering.
so we don't have to do any filtering anymore. And actually we need to get rid of this filtering. The error we saw on the page was this call to includes here because remember we did not load the like buy relationship here, so it's undefined and then that includes blows up. But we can just get rid of the whole filtering here because once again we've done the filtering upfront and now I believe that the short list should work properly and yep, our console is all clear and we can see the puppies.
and yep, our console is all clear and we can see the puppies. And now I should be able to navigate to different pages. So let's go to page, let's say page four. And I am going to check that I can still see the liked puppies and we're going to like Maggie from this page and it should be added to the list. Very cool. And while we are on the topic of the short list, there's another thing I wanna change.
Limit shortlist to five6:22
Very cool. And while we are on the topic of the short list, there's another thing I wanna change. It's not a bug, but more of a UX flow I guess, is if you have a lot of liked puppies in your short list, it's going to grow really big and it doesn't make much sense. So let me show you what I mean. I will like a lot of puppies, I mean by a lot, I'll just like six or seven and that should be enough to show you that.
I'll just like six or seven and that should be enough to show you that the short list is going to start becoming longer and unwieldy. And as you can see with the narrow view port, the problem is even more pronounced. So I thought that'd be pretty cool to show say the first five like puppies and then show and and more. So if you like 27 puppies, it would show the first five.
and and more. So if you like 27 puppies, it would show the first five and then say and 22 more. Alright, let's give it a try. That shouldn't be complicated. And we are gonna do this completely on the front end. At the top of my short list component here, I'll create a const firstFivePuppies and we are going to slice the puppies array from the zero index and keep the first five. Next, we also want to know if they are extra puppies.
index and keep the first five. Next, we also want to know if they are extra puppies beyond this five. So const, extra puppies. And actually we want the extra puppies count indeed. And this count is going to be the puppies length minus the five that are in the first five puppies. Just like so. So if you think about it, if the extra puppies count is more than zero, that means
Just like so. So if you think about it, if the extraPuppiesCount is more than zero, that means that we have more than five like puppies and we want to display an X more. So let's see, we have uh, another list and then we have a listItem for each puppy. But instead here we want to map only over the first five puppies. So that should show up to five puppies maximum if we have five.
So that should show up to five puppies maximum if we have five or more puppies in the short list. And so after this we are going to check if extraPuppiesCount is greater than zero precisely like this. Uh, but let's not get ahead of ourselves. I don't really need the span tag here. And for the classes I'll go with something much simpler. I'll go text-small text-slate-800
And for the classes I'll go with something much simpler. I'll go text-sm text-slate-800 and maybe let's go see how this looks and yeah, pretty cool. So here I guess I'm liking 12 puppies because it shows 5 plus 7 more. Let's vertically align the plus 7 more. And because I'm in the flex child here, I can do self-center. There you go. Very nice. And let's verify that it works. So I will, unlike Maggie, it should go down to plus 6,
There you go. Very nice. And let's verify that it works. So I will, unlike Maggie, it should go down to plus six, unlike Sophie, Chloe. And you know what the spending state is taking too long. I had intentionally put a little sleep in the like method. So let's go in the PuppyController here and find the like. And this is the sleep. So while we're in dev here, we still want a tiny bit of sleep just because it shows the nice loading spinner.
So while we're in dev here, we still want a tiny bit of sleep just because it shows the nice loading spinner. But one second it's too much. So I'm gonna reduce that to let's say 200 milliseconds. And I think sleep only takes ints. So I can't go 0.2 like this. But what I can do is use the usleep function, which takes microseconds. So it's going to be 200000 microseconds, which is 200 milliseconds.
So it's going to be 200,000 microseconds, which is 200 milliseconds. And while I'm in here, let's do exactly the same for the store function, which is the form where we create new puppies. It's also going to be much shorter now, alright, and now removing from the short list should feel a little bit more snappy and it does, but it still shows the loading spinner. And so you've seen that now we have five puppies or four
but it still shows the loading spinner. And so you've seen that now we have five puppies or four and it's not going to show and blah blah blah more. But if I was to like one, we show the five. And if I like one more, you can see that now we have the plus one more. So it's working really well. I'm super happy with this refactoring, but there's one thing that's annoying me a little bit. We had to receive likedPuppies in the page component.
Remove prop drilling10:08
but there's one thing that's annoying me a little bit. We had to receive delightPuppies in the Page component and then pass it to the Main component and then receive it inside the Main component and pass it to the ShortList. And there is absolutely no good reason to need to do that. And I'm not talking about using the context API here or anything, but simply we have a Main component that really is just that. And so why don't we just grab this
that really is just that. And so why don't we just grab this and put it there instead of the main component. We are going to have some issues. It's missing the main ref, the oath and paginated puppies is not a thing. But we can grab our two hook calls here and move them to the top of the components like so and pass the puppies like they are called puppies. And now look at this. I can go down here
and pass the puppies like they are called puppies. And now look at this. I can go down here and I can delete all of this. And we just have one component for the page component and everything should work exactly the same. And let's verify that the app is still working. And sure enough, it is, let's try like paisley, which is now in a liked array with two more. And so that is much nicer. And the reason we originally had split components is
And so that is much nicer. And the reason we originally had split components is that we were using a suspense boundary, an error boundary. We had some states that we wanted to not be at the top level but nested inside for performance reason and re-renders. But all of that is gone away now and everything is much simpler. So we can just have a simple Page component and we don't have to drill. The prop stands for absolutely no reason.
and we don't have to drill. The prop stands for absolutely no reason.
