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

Project Overview0:00

Let's build a notification centered drop-down, the kind you see in all social media apps. Here's a bell icon with the number of unread notifications badge on top. Clicking on it shows you the notifications, all the older ones, plus the newer unread ones here. It also polls every few seconds, fetches new notifications, which smoothly slide down automatically. You can click on any notification, which ideally either takes you to this person's profile or takes you to the comment or post or anything, but also marks this notification as read. You can also mark all as read and see that the count automatically updates. So let's build this using Livewire and Alpine. We start with a basic notifications drop-down.

Basic Dropdown Setup0:45

So let's build this using Livewire and Alpine. We start with a basic notifications drop-down. Here's a bell icon. Clicking on this will load a certain number of notifications. No updates, no new notifications, no mark as read, nothing. So let's get started here. We have this single file Livewire component with notifications as a computed property. So it just gets the latest hundred notifications here. And down here is just a header with dashboard. And here's the button.

And down here is just a header with dashboard. And here's the button. Clicking on it, we will be able to see the drop-down because this open is toggled. The open state is toggled. We are showing this drop-down based on that open state and clicking outside will close the drop-down. Also hitting escape will close the drop-down because we have this here. And yes, so that's all it has. Also if there are no notifications, you will see the empty state. And each of these notifications item is in a blade component.

Also if there are no notifications, you will see the empty state. And each of these notifications item is in a blade component. So let's look at that as well. So here it is just a simple image with the person's name, as you can see here. And based on what type of notification it is, like comment, like, follow, we're able to see the icons here. So that's all this notification item component has. Let's go back to the Livewire component. To begin with, let's poll the server every few seconds and show new notifications. For this, there are multiple things we need to do.

Polling New Notifications2:22

To begin with, let's poll the server every few seconds and show new notifications. For this, there are multiple things we need to do. Firstly, let's use the new Livewire v4 islands feature so that all these older notifications remain intact. Only the new ones are added to this island. So let's wrap this for each loop within an island and give it a name called notifications. Close the island with end island. And now using wire poll of Livewire, let's poll the server every 10 seconds and check for new notifications. This method doesn't exist yet.

for new notifications. This method doesn't exist yet. We'll add. But to check for new notifications, we need to know what is the latest loaded notification so that we can only get the ones that are later than that. Ignore this error for now. It's because we haven't added this method yet. So we need a public property, latest loaded ID, so we can keep track of what's the latest loaded one. Initially, it's null.

loaded one. Initially, it's null. On mount, let's set this to the notifications first ID. Since this computed property runs on mount, we get the latest loaded ID here. Now we add the check for new method, public function check for new. Here we first get the latest ID from the database. We get the latest notifications ID. To check if it's greater than the latest loaded one, in that case, we render the island using render island method with notifications and the mode here is prepend because we are adding the new notifications on top before the older ones.

render island method with notifications and the mode here is prepend because we are adding the new notifications on top before the older ones. If you are using infinite, if you want infinite scroll, then we use the mode prepend like we did in one of the previous episodes. There's also replace, but here we need prepend. Once we do this, we also update the latest loaded ID. But when we render the island with notifications, this computed property will get triggered and once again, it will get all the notifications. That's not what we need. We need to check if there are some notifications loaded already, then we need to get the new

That's not what we need. We need to check if there are some notifications loaded already, then we need to get the new ones. So here, before we return, we check if the latest loaded ID is null. So if it's null, we return the first hundred, otherwise we only return the new ones. We get the latest ones where ID is greater than the loaded ID. To see if this works, we need newer notifications also. I have a scheduler running that creates notifications every few seconds. So now if we click on the bell icon and wait, you will see new notifications appearing. It pulls the server every 10 seconds.

Animating New Items5:19

So now if we click on the bell icon and wait, you will see new notifications appearing. It pulls the server every 10 seconds. So we have new notifications. That's great. But if you noticed, these new ones are just popping in. They're not sliding down with animation. So let's add that. To make that slide down animation, it's not very straightforward in CSS because you cannot animate height from zero to auto. That's what we need.

animate height from zero to auto. That's what we need. So we use the CSS grid animation hack where we wrap this entire notifications within a grid. So like, so we say div class equals grid. So this is within a grid container, and then we animate the grid template rows property from zero FR to one FR. If you're not following, this is okay. This is just a CSS hack. So let's open the CSS file and let me add some key frames.

This is just a CSS hack. So let's open the CSS file and let me add some key frames. So I have the slide down key frames, which goes from grid template rows zero to one FR. Let's also add a theme variable so we can use this key frames. These are from the previous episode. So we create another one. Similarly, we say animate slide down. We use the slide down key frames, could be 0.5 seconds, probably ease out and forwards only. So now we can use this as a CSS class.

only. So now we can use this as a CSS class. Let me close this. And here we use this now, animate slide down. And also while we are using this hack, there needs to be another div within this, which has min height zero and overflow hidden. That's a requirement. Again, like I said, it's a hack. So this would make it work. Let's check.

Adding Unread Count7:18

So this would make it work. Let's check. Let's refresh. Click on the bell icon again and wait for new notifications. Once new notifications arrive, as you noticed, this entire older ones just slide down and this new newer ones expand from zero FR to one FR in the grid. Great. We have a very smooth loading right now. Let's add this count of unread notifications here. First add a public property, unread count and set it to zero to start with.

Let's add this count of unread notifications here. First add a public property, unread count and set it to zero to start with. On mount, we update the count, we get all the notifications where read at is null. We count them and set that to unread count. Also update it every time we check for new notifications right here. And now let's just add the badge right after the bell icon, absolute positioned. It's just a span with X cloak, some classes, and then X text shows the unread count. If it's greater than 99, then there's no point showing the exact number. So it just shows 99 plus, otherwise it shows the exact count. And of course, we don't show it at all if there are no new notifications.

So it just shows 99 plus, otherwise it shows the exact count. And of course, we don't show it at all if there are no new notifications. So let's see. Let me save this and refresh. Yeah, we already see the count here. If you wait for a few seconds, this will pull for new notifications and the count will update automatically. There we have, but if you click on the dropdown, you will not see any visual feedback as to which of the notifications are read or unread. So let's add some classes here.

Marking Notifications Read9:01

which of the notifications are read or unread. So let's add some classes here. Maybe the unread notifications can have a slight blue background. Also a dot here, which signifies that it's unread. All right, let's open the notification item blade component. Let's handle this on the Alpine side. So I will convert this outer div into an Alpine component and set the red state to the red at of the notification. So if red at is true, this red is also true. As we have this, let's bind the class so that if red is false, we see a background

So if red at is true, this red is also true. As we have this, let's bind the class so that if red is false, we see a background blue color. And at the end of this, let's add that blue dot. If it's not red, like so. Let's check, refresh, click on this. And yeah, now we see the light blue background and the dot. Now if we click on this, we should be able to mark this as unread, sorry, mark this as read. So let's close this, go back to the component, LiveWire component and add a method, public

read. So let's close this, go back to the component, LiveWire component and add a method, public function mark as read. Yeah, it takes in the notification ID, updates that with the current timestamp and also updates the unread count. But since we're not really rendering any new HTML, we can simply mark this as renderless because this can happen too often. The user might keep clicking on the notifications. It's useless to render the HTML again because we are anyway handling that on the Alpine side.

It's useless to render the HTML again because we are anyway handling that on the Alpine side. Let me import this. All right, let's handle the click in the component. So if I click on this, add click. So if it's not already read, set read as true and then call the method mark as read with the notification ID. Okay, let's open this, click on something and you'll see that this is immediately marked as unread. The blue dot has disappeared, even the background color and so on.

as unread. The blue dot has disappeared, even the background color and so on. This is good. Now, since we have too many notifications, unread notifications, I might want to show this mark all as read here so I can mark everything as read at once. Let's add that method also right here. Public function mark all as read. Once again, just the same thing. Update everything as read and set the unread count as zero. This also could be renderless because again, the same thing.

Update everything as read and set the unread count as zero. This also could be renderless because again, the same thing. Let's add the button right next to notifications here, button, add click, wire, mark all as read. Yeah, perfect. Let me close this, mark all as read and close the button. Okay, let's see. Let me click on this. Yeah, I think this should be text blue 500, hover could be text blue 700. Let's refresh again.

Yeah, I think this should be text blue 500, hover could be text blue 700. Let's refresh again. Yeah, mark all as read. Let me click on this. The unread count is gone, of course, but if you scroll down, you will still see these indicators. That's because we have to tell our Alpine component to set everything as read. So right here, after we mark all as read, let's dispatch an event, dispatch, mark all read. Yeah.

read. Yeah. So let's go to the blade component and add a listener. So here, if we get the mark all read on the window, set read to true. And we do this for every single notification. Now let's let me start the scheduler again. So we have new notifications. All right. We have two unread notifications. Let me mark all as read and this works.

We have two unread notifications. Let me mark all as read and this works. And that's it. That's our notification center dropdown. I hope you got some idea of which part should be taken care of by Alpine and which should be taken care by Livewire, when to use renderless, when to use computed properties, feel free to pick up the code and add it into any of your applications. See you in the next episode.

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