Add Request Book Action0:00
(upbeat music) Now it's time to add some custom actions everywhere. First, in this books resource for each of the books right here, let's add an action for the user to be able to request a book. We need that in each of these records, so we do that using a method record actions in the books tables. Open books table and scroll down to almost the end. Yes, use the record actions method and let's make a custom action.
Yes, use the record actions method and let's make a custom action. Action make request and let's label it request book. Yeah, let me import this. Limit actions action. The moment I add this, we see this request book as a link, but we want to make it look like a button. Can do that using the button method,
but we want to make it look like a button. Can do that using the button method, which will then make it look the solid green button, which doesn't look that great. And when it's there on every single card, it's quite, it's too prominent. So let's change this button to outline only using outline method. Now refresh, this is much better. We want it slightly tinier as well.
Now refresh, this is much better. We want it slightly tinier as well. So use the size method and maybe XS iron or SM should be good. Let me refresh. I think this is SM, which means we need access. Yeah, access is better. Let's also add an icon. You're saying icon, not book open maybe like a request.
Handle Request Logic1:43
You're saying icon, not book open maybe like a request. So a clock is good. We will change this later, of course. Now, what do we want this button to do? That's something we define using the action method function, inject the record here and we put the action logic here, which is we use the book user model and either create a row or update an existing one.
which is we use the book user model and either create a row or update an existing one. Now there might already be a case where a user has read a book, return it, but wants to request it again. In that case, there's no point creating an other row. We can simply reuse the older one, which is why we can use the update or create method exactly. So if the user ID, which is the authenticated ID and the book ID, which is the record ID already exists,
So if the user ID, which is the authenticated ID and the book ID, which is the record ID already exists, then we simply update the status to requested and change the requested at timestamp. And if it doesn't exist, all these a new row is created. So import class. All right, let's see if this works. Refresh, request a book. And yes, immediately the badge changed to requested.
Refresh, request a book. And yes, immediately the badge changed to requested. Let's check in the book users requested and yes, the first book is here. Okay, let's go back to the book's resource book stable and we want this button to appear only if it has not been requested already, right? That's why what we will do is we'll just use the visible method. Yes, perfect because if the status is already returned,
the visible method. Yes, perfect because if the status is already returned, that means the user has read it before, but might want to request it again. In that case, we show it. So only if the status is not requested or borrowed, this action is visible. Let's see. Let me refresh and yes, the button is gone now. Great, all looks good,
Reorder Cards Layout3:46
Let me refresh and yes, the button is gone now. Great, all looks good, but I feel if the image is on the right side and the text on the left, everything will look aligned along with this action button. So let me just make that one small change. So scroll up and let me find the image column. Just remove it from here and add it after the stack. Like so, refresh. Yeah, that looks much better.
Like so, refresh. Yeah, that looks much better. They make the same change in book user's table as well. Scroll up and put it here, right? We need a comma here. And I think I'm just going to remove this comment. It's anywhere there in the book stable for reference. Fresh, not here, book user's table. Yes, this looks good. Now here I would like to also add an additional column
Show Requested Time4:43
Yes, this looks good. Now here I would like to also add an additional column which says how long ago it was requested. And the same applies for all three tabs. So let's go to the book user's table and write after both these text columns. I will add another text column. Column, make, create a that. And instead of showing the date,
create a that. And instead of showing the date, sorry, not this, instead of showing the date, we could show in a human readable format. And filament has a method for that which is since automatically, it shows something like yes, one day ago or, you know, yeah, we did everything one day ago. So that's the only thing you'll see here. Let's change the way this looks using this extra attributes
So that's the only thing you'll see here. Let's change the way this looks using this extra attributes and change the class here to yes, text, SM, text array 500 because we don't want so much prominence for this. Refresh, perfect. Or I think it should be much smaller. So let's say text, excess. Refresh, yes. Now let's add a custom action
Add Cancel Request Action5:55
Refresh, yes. Now let's add a custom action to each of these cards here to cancel the request. So if the user has requested it by mistake or doesn't need it anymore, they should be able to cancel. So right here we add the record actions. Let me add that here. Record actions. So here we can simply reuse the delete action
Record actions. So here we can simply reuse the delete action that already exists. So we will just have to change the label, make delete, yes. But let's change the label to cancel request, yes. We can also add an icon here. First, let's see how it appears. Refresh, yeah, we see it like so, like a link. Again, I wanted to look like the button outlined and much smaller.
Again, I wanted to look like the button outlined and much smaller. So we could say change the size to excess. Outlined, that is, okay. So we have this button like so. Now clicking on this will open the confirmation model by default, but this text is something we need to custom. Close it. And that's something you can do using the model heading method. Cancel book request, okay.
And that's something you can do using the model heading method. Cancel book request, okay. And not model subheading model description. Are you sure you want to cancel your request? So for this book sounds good, close this. We also need to change the action button's label. It's a delete and cancel. That's quite confusing. You can change that using the model submit action label. We can just say yes, that's good enough.
You can change that using the model submit action label. We can just say yes, that's good enough. Model, cancel, action label could simply be no, right? See what this looks like, refresh, cancel request, yeah, cancel book request. Now that's a question and we have the options yes and no. Let's click on yes. And yes, it has gotten deleted. We also see a notification by default which simply says deleted.
We also see a notification by default which simply says deleted. We would customize that in the next episode. Okay, so the cancel button works, but I guess it appears in all the other tabs as well, which is not something we want. So let's customize that. Let's change that using the visible method. And let's make it visible only if the status is requested. Perfect, refresh.
Add Return Book Review8:31
And let's make it visible only if the status is requested. Perfect, refresh. And now it doesn't appear in the return tab. All right, this was one action. Now let's add a custom action in the borrowed tab also, but first we need a book. Let me add it manually. Now we have a book and we need a button here to return the book, right? So the user can click on it.
to return the book, right? So the user can click on it. Let's add it right here after the delete action. Let an action make return book and label would be return book. Let's yeah, let it look like a button, let it be outlined, sizes, axis, great, refresh. Yeah, we do have a book. Let's also add an icon here. Icon, yeah, something like this.
Let's also add an icon here. Icon, yeah, something like this. We will change this native refresh, yeah, return book. Now when a user clicks on this button, it would be great to request for a rating and review of the user at this point, right? So to show a model with a form, it's super easy with filament. Let's do that first using the model heading, not return book.
Let's do that first using the model heading, not return book. We would like to say something like, did you like the book? Yeah, do you like the book? And then model description would be feedback, helps us improve our recommendation. That's great. And here we would like to show a form with a couple of fields rating and review
And here we would like to show a form with a couple of fields rating and review that can be done using the schema method. Let me just make this full screen again, schema. For the rating field, it would be actually nice if the user can hover over the stars and give a rating. That's something we would customize in one of the future episodes. For now, we will simply add a select, make rating perfect and let this be a required field.
For now, we will simply add a select, make rating perfect and let this be a required field. And for the review, let's use a rich editor. Rich editor, make review, write a review. This is not required. We could have a placeholder saying, share your thoughts about the book and we could customize the toolbar buttons where the user could format the text using bold, it like link, maybe not.
where the user could format the text using bold, it like link, maybe not. Maybe let's simply add on the line and maybe a hedge two and a hedge three. Okay. Now let's see what this looks like. Click on the button and yes, we do see an amazing model with the form. Did you like the book? Yes, we could give it a rating
Did you like the book? Yes, we could give it a rating and we can write the review. But now when the user submits this button, what we want is not the status to directly change to return, right? We discussed this while we were creating our migration. We can't allow the user to change that status to return. It has to come from the admin, but the user can return the book.
It has to come from the admin, but the user can return the book. So we will set this timestamp that we have returned requested at, but keep the status as borrowed. And right here after the schema, let's add the action of exactly what we want to happen. We will inject the record and data, but no, let's not update the status. Let's change the return.
let's not update the status. Let's change the return. Let's just set this column, return requested at to now and we get the rating from here, rating and review. We update that in the database, of course. All right. So let's see if this works, refresh, return the book, select a rating and then I just love the book. Like this, click on submit.
select a rating and then I just love the book. Like this, click on submit. It does look like nothing happened, but that's because we are showing this button irrespective of the return requested at timestamp. The status of the book is still borrowed, right? Let's change that. Let's make this button visible only when the status is borrowed and the return requested timestamp is set.
when the status is borrowed and the return requested timestamp is set. So let's go back and add this, probably somewhere here after the icon. Let's use the visible method. Yes, when the status is borrowed, but also when, yeah, the return requested at is null. Okay, refresh and now it's gone and we don't see this button elsewhere. Great.
Show Return Requested Badge13:09
and we don't see this button elsewhere. Great. The user might get confused that, okay, I requested for return, why do I still see this card? So let's add a badge here to say that the return has been requested. Go back up and write after this column. Let's add another text column. Make status, no of this. Make status, we can simply set the state.
Make status, no of this. Make status, we can simply set the state. We can hard code it right here saying return requested and it's a badge. It could also set the size to text size, extra small. Great, the badge looks perfect, could I guess it appears elsewhere? No, we need to set the visible method here. So here we say this is visible only if the return requested are to set
So here we say this is visible only if the return requested are to set and the status is borrowed, yeah. All right, now let's look at this. Attempt to read a property, okay. Let me just add a question mark here, refresh. That's better. Now I just realized we made a mistake while displaying this timestamp in a previous episode. We're using the created at column,
while displaying this timestamp in a previous episode. We're using the created at column, but we have to actually change this to updated at because that's the time the user would like to see. Refresh, one minute ago, I think that's better. Let's leave it. All right, so we have added quite a few custom actions. We added request book here. The only last thing we'll do in this episode is add an action in the empty state, okay.
Add Empty State Action14:51
The only last thing we'll do in this episode is add an action in the empty state, okay. So let's come down here after the empty state heading and icon, let's add an action. But to be able to see that, let me cancel both these requests. Now we have the empty state. This is where we want the button, empty state, shin, shins,
empty state, shin, shins, and yeah, exactly. Browse books and this is not a route. We could simply get the URL from the book resource, get URL like so and a button. Yeah, fresh. All right, this looks great. Okay, this was a loaded episode. In the next one, let's customize
Okay, this was a loaded episode. In the next one, let's customize how the notifications are built. (upbeat music)
