در حال بارگذاری ...

Reviewing dashboard design0:00

Okay, so now that you're a little more comfortable with how you might go about maintaining and organizing global state, over the next couple of episodes, why don't we put all of the pieces together? And by all, I mean everything you've learned in this series. So it should be fun. As always, let's get going. Okay, so here's the initial design that I have for you. Again, it's a basic dashboard for managing a Team. And yeah, if we have a look here, and if we break it down, we can see a number of things. First, a Team consists of a name.

Now behind the scenes, in preparation for this video, you can see I added a TeamView that consists of a header that has a button and the name of the team. That of course corresponds to what you see right here. Next, we have a table where we list all of the members on the team. So here's one member for James Doe. Here's another one for Sarah. Here's another one for Steven. Here's another one for Jen. Here's another one for Joe. And then again, we are just hard coding some of this logic here that, of course, later

Extracting TeamMember component1:25

Here's another one for Joe. And then again, we are just hard coding some of this logic here that, of course, later we will need to make dynamic. And again, the same thing is true here. Okay, so what I want to get started with is some basic organization. And the first thing that pops up at me is the fact that I'm duplicating all of these table rows. So you'll notice it's the exact CSS classes. And by the way, notice that I am using Tailwind here. But yeah, notice it's the exact CSS classes for each section.

And by the way, notice that I am using Tailwind here. But yeah, notice it's the exact CSS classes for each section. So that seems like a good candidate for a custom component. Let's do that now. In the sidebar right here, let's create a new one. Now again, in terms of organizing your components, you can do it however you want. If you want to nest them in folders, that would be fine. Otherwise, if you want to follow a simple naming convention, that works as well. In this case, why don't we have a directory called teams. And then I'll have things like a Team.

In this case, why don't we have a directory called teams. And then I'll have things like a team. What would we call this? What does this represent? How about maybe teamMember or teamMemberItem, whatever you want. Why don't we just stick with teamMember for now? Okay, so now it looks like we need to grab the full contents of this table row. And I'm going to move it over like so. Now one step at a time, right? So at the moment, it looks like we will need to pass through the user's name, their email

Now one step at a time, right? So at the moment, it looks like we will need to pass through the user's name, their email address, and their status. So we might start by defining some props consisting of, again, the name, the email, and the status. Okay, so let's update these like so. Your name, and then here, the email, and then the status. And then you'll notice right here, I'm just using a placeholder service for the user's avatar. And to make it unique to a specific person, I can add a identifier here, in this case, the person's email.

And to make it unique to a specific person, I can add a identifier here, in this case, the person's email. So why don't we do this? Let's bind it. And we'll have something like this, username, and then the email. And actually, that might be enough. So I could save it like that, or convert it into a template string. And that looks pretty good to me. Okay, so now, this seems to be dynamic, which means if I switch back to our team view, I can now, at the top, import our new component, TeamMember, from, and what is it?

Okay, so now, this seems to be dynamic, which means if I switch back to our team view, I can now, at the top, import our new component, TeamMember, from Components/Team/TeamMember.vue. Okay, so now, if we scroll down, I can grab any one of these table rows, comment it out, and if I switch back, we can see now we only have four. Okay, let's replace it with our new TeamMember component, where we give the name, James Doe, the email, james.doe.com, and the status, which is active. Okay, so now if I switch back, there we go. But now we're using a custom component there. So what I'll do now is get rid of all of this, and I'm going to repeat this for Sarah, so

Loading members from JSON4:47

And yet, still, I don't know how realistic this is. In real life, this data would probably come from a database or an API call. We probably wouldn't hard-code it like this. Instead, we'd have something like a V4. So I don't want to set up a backend and a database, but what we could do is simulate it by creating a JSON file that we can read from. So let's do this. In my source directory, I'm going to add a file here, and I'll call it team.json. And yeah, here is where I could define our members. For example, name is John Doe, email is john.doe.com, status is active.

And yeah, here is where I could define our members. For example, name is John Doe, email is john.doe.com, status is active. Let's stick with that one and see if we can make this work. So now what I could do is go back to team view, and at the top, I'm going to import that file. Import team from our team.json file. And what I'll do here is console.log our team, so you can see that it's working the way we'd expect. Give it a refresh, info, there we go. Here's the file that we just imported.

Give it a refresh, info, there we go. Here's the file that we just imported. So if I wanted to grab the first User, I could grab the first item from the array, and sure enough, we have that data. Okay, so now think about it. If we scrolled back down here, we could remove all of these and instead reach for a v4 member in team, let's hide the sidebar there, and then we could just bind these like so member.name, member.email, and then finally, member.status. So if we now switch back, yeah, this is what we want. We're now reading from that JSON file, which is our simulation of a database or an API,

So if we now switch back, yeah, this is what we want. We're now reading from that team.json file, which is our simulation of a database or an API, and we can now loop over all of the members on the team. Cool. So now once again, if I switch back to team.json, I won't make you watch this, but I'm going to duplicate this for all five members on our team. Like so. Okay, so have a look. I now have five members for our team, and if I switch back and give it a refresh, there we go.

So anyways, now if we come back and refresh, we'll have to tweak things just a little bit, right? Because we're now importing something different. Let's go back to teamView, and we'll say, let's get rid of that, and we want to iterate or loop over the teamMembers. So if we scroll back, teamMembers. And again, just to be crystal clear, teamMembers. And that should do it. Okay, so now we can swap in all of the other dynamic data, such as this one, team.name. And what else?

Okay, so now we can swap in all of the other dynamic data, such as this one, team.name. And what else? Down here in the footer, once again, team.name. And then finally, the number of spots, team.spots. Okay, so if we have a look at this, yeah, we get the same thing as before, but now this is dynamic. So for example, if we have eight spots on the team, and the name is Acme, give it a refresh, all of that is being updated the way we'd expect, except for this little label. I should update that as well. Okay, let's bring it back into team view, and let's see what we got here.

Adding spots remaining logic9:04

I should update that as well. Okay, let's bring it back into team view, and let's see what we got here. Yeah, right here is my label, team.spots. Okay, so the next step is to add a bit of logic to determine if we have any spots remaining on our team. We might initially say, here's our button, disable the button if the teamMembers or the number of the teamMembers equals the teamSpots. If that's the case, then it should be disabled. And in this case, if we come back, sure enough, it is. But yeah, if we were to test this, let's assume you have seven spots.

And in this case, if we come back, sure enough, it is. But yeah, if we were to test this, let's assume you have seven spots. Well now, we should have two more. So come back and refresh, and it's no longer disabled. Okay, next, let's make zero spots left dynamic. So we could say right here, what would we do, team.spots minus team.members.length. Again, things like this can be great candidates for computed properties, or getters, if we were to use store and pinia terminology. And we'll do that later. So come back and refresh, and sure enough, this is now dynamic.

And we'll do that later. So come back and refresh, and sure enough, this is now dynamic. The label is dynamic. But what about this section here? We'll need to update that. So scroll down, and we'll say, well, only show this paragraph, v-show or v-if would be fine. Only show it if team, once again, same thing, if the number of team members has met the total number of spots. If that's the case, we need to show a note to them.

Extracting header/list/footer components11:09

do, and this is looking pretty good to me. Now, this is simple enough that I would be fine keeping it as it is, but yeah, why don't we continue extracting this to simulate what you might do in real life? Right here, this might be extracted into something like a team header. So let's go into components, into teams, and we might call this the header or team header, whatever you want. All right, so we'll have our template here, and yeah, once again, we'll need to add script setup to declare what our props are. So again, notice I'm having to do this over and over again. Every time I want to extract a component, I then have to declare a bunch of props so

So again, notice I'm having to do this over and over again. Every time I want to extract a component, I then have to declare a bunch of props so that I can keep track of all of this team data. This is the whole reason why in the next episode, we will extract a dedicated store. But yeah, for now, I'm going to create all the duplication so that we can refactor away from the duplication. In this case, why don't we say, let's just expect the full team object, like so, okay? So if I switch back, I can now reach for its teamHeader. And keep in mind, this got imported at the top automatically, and we will pass through the team.

And keep in mind, this got imported at the top automatically, and we will pass through the team. All right, so if I switch back, oops, that's not working. teamHeader, teamHeader, let's add the extension. There we go. Now it's working. Okay, next, maybe this full table could be its own component. And maybe we'd call it something like TeamMembers, let's see, how about TeamMembersList, whatever you want. teamMembers.vue.

But these days, I often see the script portion go at the top with the template below it. And then the style tag below that. It doesn't really matter. Whatever you want. Okay, so let's switch back to team view. And now here, we'll have our teamMembers, where we will once again pass through the team. And I'll add the extension there. Okay, so now I can remove this import because teamMember is being referenced from this component here.

Okay, so now I can remove this import because teamMember is being referenced from this component here. So I will add that as well. Okay, looking good. Switch back. Yep. Finally, maybe this section down here in a real life project is significant enough that we're going to do the exact same thing where we extract a component. So let's do a View component called TeamFooter. And I will grab this and move it in here.

So let's do a view component called TeamFooter. And I will grab this and move it in here. And once again, PhpStorm, you're looking bad. Once again, we will define some props. And here, yeah, remember, I'm keeping it simple by saying, just give me the full object. But often, you might do something like this, where you have a number that represents the remainingSpots, and then another one for the name. Often you will want to be explicit. I'm just keeping it a little basic, because I know we're going to refactor away from this. Okay, so back to TeamView, we can now import our TeamFooter, pass through the team.

Preparing for Pinia store15:36

So we effectively had what we started with, but now everything is dynamic and nicely structured and organized. So in the next episode, we're going to extract a dedicated PINUS store so that we can access our team state across the entire application.

Extract Vue Components

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