00:00
[MUSIC]
00:05
Next, let's add in a paginated list of our movies for
00:08
our admin so that they're able to manage them,
00:10
put actions within that table.
00:11
Let's hide that pack away.
00:13
Within our routes file, let's scroll down to
00:14
where we have our admin section at.
00:16
I believe that's down near the bottom.
00:18
Yep, right here. Let's add in router.get/movies,
00:23
and let's add in an admin movies controller.
00:27
We don't have that created quite yet,
00:29
but we'll create that here in a second with
00:30
an index method as movies.index.
00:34
Remember that we have this route group
00:35
prefixed with the name of admin.
00:37
So this will really be admin.movies.index.
00:40
So it won't collide with our existing movies.index.
00:43
I'm going to jump into my terminal now,
00:44
stop our server, clear that out.
00:46
Node.asemakecontroller admin/movies,
00:51
and we'll do hyphen R to create that as a resource.
00:54
Cool. So this created our controller at
00:56
appcontrollers admin movies controller.ts.
00:59
Let's go and clear that out and boot our server back up.
01:01
So npm run dev.
01:02
Let's hide that back away.
01:03
Now you get a sense of why we're prefixing
01:05
these admin controllers with the word admin,
01:07
because we already have a movies controller imported right here.
01:11
We can go and give that a copy as a starting point.
01:13
Paste it in here, prefix the name with admin,
01:15
jump down to the actual import path,
01:17
and prefix that with admin/ as well.
01:19
Again, by nesting our controllers inside of subfolders,
01:21
we're able to give them a purpose and
01:23
also keep the names simplified as well.
01:26
Cool. So we can give that a save.
01:27
Let's scroll all the way back down because that's
01:29
where we'll be needing to pick back up here within this file.
01:31
Let's go and jump into our new movies controller or our admin.
01:34
Again, by creating this as a resource,
01:36
we're stubbed with the resourceful methods that we get.
01:38
So index, create, store, show, edit, update, and destroy.
01:42
You may have some ESLint warnings and errors for unused properties,
01:45
but that's okay. We'll take care of that as we fill this out.
01:47
All right. So let's start by getting our movies.
01:49
So const movies equals await.
01:51
We can import our movie model.query.
01:53
For the admin section, we're going to want to get back all of our movies.
01:56
You could add filtering in using the same approach that we
01:58
did with our watch list and movies pages.
02:00
Since we've already covered how you can go about that,
02:02
we're going to skip that here for this page.
02:03
So let's just order this by the updated at and descending order.
02:08
So we'll get them by most recently updated to the oldest updated.
02:12
Let's add paginate to the end of that.
02:14
This is where we'll want to grab the page and the per page counts.
02:17
So we can grab our request.
02:19
While we're in here, we'll also grab our view out of our HTTP context.
02:22
We can do const page equals request input page and default that to one.
02:28
If it's not provided, we'll provide that in there.
02:30
Per page, maybe we'll do 30.
02:32
Then we need to define our base URL.
02:34
So movies.baseURL, and we can import our router to make URL,
02:40
or our admin movies index page.
02:43
Since we're not worrying about filtering for this particular page,
02:45
we're not going to have additional query strings to worry about
02:47
depending onto these generated pagination URLs.
02:50
But if you did, as we previously covered,
02:52
you have movies.queryString at your disposal that you can provide
02:55
a key value record pair into to add query strings into your generated URLs.
02:59
So let's go ahead and return view.renderPages/.
03:04
Rather than putting this inside of our movies directory,
03:07
we're going to keep this scoped inside of our admin directory,
03:09
and we'll create another movies index page inside of there,
03:12
and provide our movies in.
03:14
If we wanted to list out some additional details,
03:16
we can go ahead and preload that onto our query as well.
03:18
So we could say preload the director and preload the writer.
03:23
Of course, there's aggregates and counts that we could do as well.
03:26
So we could do with count,
03:27
and we could say count our cast members and count crew members as well.
03:32
Let's also go ahead and preload our status into,
03:34
I forgot about that relationship status, and there we go.
03:37
So now we should have everything preloaded onto our movies that we'll need.
03:40
Let's go ahead and scroll on down and create our page.
03:42
So we'll scroll down to,
03:44
let's see, our pages admin section.
03:47
Right-click that folder, new file,
03:49
create a new movies directory with an index.edge page inside of it.
03:53
We have our app, we want to apply our layout.adminlayout and end that.
03:58
Now, we'll apply an h1 in here that says movies,
04:01
and then let's just do a simple table.
04:02
So we'll do a table with a T head and a table row with a table heading,
04:08
showing the movie title,
04:09
then maybe another one with the status,
04:12
then maybe writer director,
04:13
and maybe counts,
04:15
and then we'll do an empty one for actions.
04:17
For our T body,
04:19
go ahead and scroll down a little bit.
04:20
We're going to want to loop over each of our movies and apply them in as a row.
04:23
So we'll do @each movie in movies,
04:26
end our each, add in our table row,
04:29
table data, movie title,
04:31
TD, movie status, name,
04:34
another TD where we can do our movie.writer.fullname/moviedirector.fullname.
04:41
We'll have a TD for our counts and a TD for our actions.
04:46
So let's pause there for now and let's jump into
04:48
our admin layout and add an additional link for this new page.
04:51
So we have an href equals routes,
04:54
admin, movies, index, and we'll just call that movies.
04:57
Go ahead and close that out,
04:58
jump back into our browser and let's see what we get.
05:00
So let's jump into our new movies page.
05:02
It's not pretty, but it is there and it is working.
05:05
You can see our movie title,
05:06
the movie status, the writer, and director,
05:09
and it will take care of our counts and action here momentarily.
05:11
But first, I think we're going to need to make the text small,
05:14
maybe even extra small just to fit within our table here.
05:17
So let's jump up to our table class,
05:18
text extra small to try and squeeze everything in here real quick.
05:22
It'd probably also be good to go ahead and break these down on
05:24
separate lines and annotate which is which here.
05:27
So let's wrap this one here in a div and do writer,
05:31
colon, and then paste that back in.
05:33
Then let's do the same thing here,
05:35
director, colon, and paste their name back in there.
05:38
Now, let's take care of our counts.
05:39
So we'll do something similar for this.
05:41
So we'll split them up one per line.
05:43
We'll have our cast members as movie.
05:46
For this, we'll want to reach inside of the movies extras object as
05:50
counts aggregates and the like are not direct model properties.
05:53
So they're going to be plopped inside of our extras object.
05:56
I believe this should be called cast members_count.
06:00
Give that a copy because all that we need to do is switch cast to
06:03
crew and we'll have our crew members count there as well.
06:06
Give that a save and let's see if we got that right.
06:08
So let's jump back into our browser.
06:10
Okay. So now we have I'm your boogeyman,
06:12
post-production, writer, director,
06:14
cast members of four,
06:16
crew members of three.
06:17
It looks like everything there is working A-okay for our movies here so far.
06:20
So we'll worry about adding the actions in and subsequent lessons.
06:23
For now though, we need to get the pagination rigged up.
06:25
Now, on our movies page,
06:26
we've already added this in via our buttons right down here.
06:30
So we can replicate this into a component so that we can reuse it on our movies page,
06:34
as well as our watch list page,
06:36
and now our admin movies page as well.
06:39
So let's hide this back away and we want to jump into
06:41
either our movies or watch list index page.
06:44
We have it defined in both of them.
06:46
So we can scroll down to where we have,
06:47
let's see our pagination looks to start right here.
06:50
So we'll place our cursor right there.
06:51
I'm just going to go ahead and collapse this down and
06:53
jump down and select the end div there.
06:55
We can cut this out,
06:56
scroll up to our components.
06:58
Let's right-click that, new file, pagination,
07:01
and let's create an index.edge file within there.
07:04
Paste that in and there we go.
07:05
So everything within here should mostly rely on
07:08
our pagination methods and properties.
07:11
I'm going to just scroll through here real quick just to
07:13
verify that that is actually the case.
07:16
We have a pagination array right there that we'll want to
07:18
make sure that we're instantiating inside of this component as well.
07:21
But apart from that, everything does seem to be coming directly from the paginator.
07:24
Let's jump back into our pages movies and
07:26
see if we can find where that pagination is coming from.
07:28
Doesn't look like it's coming from our edge file.
07:30
So let's jump up into our movies controller
07:33
because it must be coming from here then.
07:35
Scroll down and sure enough, there is our pagination.
07:38
This can easily be refactored and moved down into our pagination components.
07:42
So I'm going to go ahead and get rid of that,
07:44
and we can remove that out of the page state there too.
07:46
Hit "Command P" and jump back into our new pagination components.
07:49
Scroll up to the top, give ourselves a couple of lines and we can paste that in.
07:52
It's not going to be formatted quite yet,
07:54
but what we're going to want to do is at let,
07:57
we can create the range min,
07:58
same as we were within our controller, just like so.
08:01
We want to do the exact same thing for our range max.
08:04
So at let, there we go,
08:05
as well as our pagination.
08:07
So at let there too.
08:09
What we want to do next is normalize all of our movies properties,
08:13
which is our movies paginator,
08:14
into a nonspecific name.
08:16
So I think the most appropriate name for that is probably going to be paginator,
08:20
as it controls all of our pagination logic by providing us our properties and methods.
08:25
So we'll go ahead and do a replace all there,
08:27
and everything should still be a okay with how we had it.
08:30
So we'll scroll through here,
08:31
make sure there's no red squigglies, looks okay.
08:33
Let's go and give this a save,
08:34
jump back into our movies page at exclamation point,
08:37
pagination, since this will be self-closing,
08:39
and provide in our paginator is our movies.
08:43
Let's give that a save, jump back into our browser,
08:45
and let's jump into our movies page to test it out.
08:47
Looks like I got a missing token.
08:48
Yeah, I never ended the let there for that one.
08:51
So let's go ahead and take care of that,
08:52
jump to our pagination component,
08:54
and there we go.
08:55
That looks better. Give that a save,
08:56
jump back into our browser,
08:57
give this a refresh once more.
08:59
Let's go and scroll on down and make sure everything's working here.
09:01
So page two, three, four, next goes to two,
09:04
and last goes to 28, first goes to one.
09:07
Awesome. So everything there does seem to be working a-okay.
09:09
Next, what we want to do is apply
09:11
the exact same paginator component into our watchlist page.
09:14
So let's hide our browser back away,
09:15
jump on down to our watchlist page,
09:17
which seems to be right here
09:19
off the root of our pages directory.
09:20
Scroll down to where we should have our pagination starting,
09:23
go ahead and hit the caret to collapse that down,
09:25
and we just need to get rid of everything there.
09:27
And this should be the exact same.
09:28
So at exclamation point, pagination, paginator,
09:32
and I believe we called it movies here as well.
09:34
Then we'll jump into our watchlist controller,
09:36
and we can get rid of the range min,
09:38
range max, and pagination there,
09:40
and get rid of it out of the page state there too.
09:42
All right, give that a save.
09:43
Let's make sure everything's working there before we move on.
09:45
Jump into our watchlist page, scroll on down.
09:47
We only have one page,
09:48
but everything should be working very okay
09:50
since it's using the exact same component.
09:52
Awesome. Last thing to do is apply that
09:54
into our admin movies page.
09:56
So let's go ahead and collapse that back down.
09:58
We've already done all of the work needed
10:00
for this inside of our controller.
10:01
So we can scroll on down into our admin movies index page,
10:05
go down outside of our table,
10:06
and do @ exclamation point pagination.
10:09
Hide in our paginator as our movies.
10:12
Give that a save, jump back into our browser,
10:13
and let's see if everything worked.
10:15
So scroll on down, and there we go.
10:16
So if we jump over to two,
10:17
looks like that's working A-okay.
10:19
And if we jump down to the last page,
10:21
looks like that's working A-okay too.
10:22
Awesome. So before we round out this lesson,
10:24
let's go ahead and clean up our table here a little bit,
10:26
because it's really hard to look at.
10:28
So let's go ahead and jump into,
10:30
I have flow by open here, but you can use whatever.
10:32
All we're looking for here is a TailwindCSS table component.
10:36
You can even style this relatively easily yourself.
10:38
Just going to go ahead and give the whole thing here a copy,
10:40
close that out, hide our browser.
10:41
And I'm going to scroll up above our existing table
10:44
and give it a paste on it.
10:45
And the first thing you might notice
10:46
is that they use an indent of four
10:47
while I use an indent of two.
10:49
If you ever have that use case,
10:50
go ahead and just select everything
10:52
that needs re-indenting, hit command shift P,
10:55
and type in re-indent.
10:57
And you can either do lines as a whole,
10:58
which will do the whole file or selected lines.
11:01
Awesome. Give that one indent there
11:02
so it's not right off the edge of our page.
11:04
And then another thing to fix is we are using slate
11:06
rather than gray.
11:07
So we'll just give gray there a highlight
11:09
and do a finder replace all gray with slate instead
11:12
and replace all of those.
11:13
All right, cool.
11:14
So now this table should match what we're doing.
11:16
So what we need to do now
11:17
is give the wrapper elements here a copy,
11:20
scroll down to our table right here,
11:22
paste their wrapper elements in
11:24
and get rid of our starting elements there.
11:27
And it looks like we'll want to indent everything
11:28
of ours one time as well
11:30
and add in an extra div underneath our table
11:33
to match their structure.
11:34
Okay, scroll on up.
11:35
Looks like they had some specific TH classes.
11:37
So we'll just give those classes,
11:39
oh, they had a scope on it too.
11:40
We can go ahead and give that whole block there a copy.
11:42
Go down to our THs, option command down arrow
11:44
to do some multi cursors and paste that in.
11:47
All right, let's scroll on up
11:48
and take care of our T body next.
11:49
We can simplify theirs by taking theirs
11:51
down to just a single row.
11:52
Looks like they had three total, so we'll get rid of two.
11:55
Scroll on up, give that TR class there a copy.
11:57
And then it looks like we're not gonna worry
11:59
about the specific TH right there,
12:01
but the rest of the TDs have a PX6, PY4 on it.
12:04
So we can add that in relatively easily.
12:05
So on our TR here, we'll give their class,
12:08
put that a copy and then class PX6, PY4,
12:13
give that a copy and we can paste it
12:14
into each of our TDs here, just like so.
12:17
All right, we should be done with their table.
12:19
So we can go ahead and nuke it out of our file,
12:21
just like so.
12:22
And let's give it a save and see how it looks.
12:24
Nope, it's picking up dark mode
12:25
and the padding is quite a bit
12:26
for what they were using here as well.
12:28
So first let's go ahead and add our text extra small back in,
12:31
switch everything from PX6 to maybe PX2
12:36
and everything from PY3 to I think PY maybe 1.5.
12:40
And then we're also going to want to get rid
12:42
of all of the dark mode stuff here too,
12:44
as we're not worrying about that.
12:46
And I guess I have my computer set to prefer dark mode.
12:48
Okay, it looks like there was only three classes
12:50
for dark mode there, so that's not too bad.
12:51
All right, give that a save,
12:52
jump back into our browser now,
12:54
and yeah, that's looking a lot better.
12:55
Okay, cool, awesome.
12:56
So now we have our movies table in place
12:58
and ready to go for us to add in our actions next.
Join The Discussion! (0 Comments)
Please sign in or sign up for free to join in on the dicussion.
Be the first to Comment!