In this chapter, we're going to go ahead and implement category pages. We are basically going to ensure that when we click on a category, we can load that page and we will also apply this specific style to our search filter component. I believe that's what it's called. We're also going to have to support the subcategory routing as well, which means we're going to have to implement this kind of breadcrumb right here. And I also want to take this time to refactor our components and put them into their respective modules.
So as always let's go ahead and ensure that we are on the master or main branch that we have no leftover changes from our last time we were here. And then we can go ahead and just do bun run dev. Now let's go ahead and revisit our localhost 3000 and the first thing I want to do is start refactoring this app folder app route group home so in here we have search filters footer navbar sidebar and navbar all the things that don't belong in this folder. So instead, here's what I'm going to do. I'm going to create a module called Home.
So by Home, what I mean to say is this is only, these components only belong on this screen. You might argue that these are related to search or categories, but we're not really going to reuse them anywhere but on the homepage. So that's why I feel comfortable putting them in the homepage. So we're gonna start with some simple ones like navbar so we can see things slowly change. So go ahead and create a new module called Home.
And now inside of this Home, let's go ahead and create a UI folder. And inside of here, components. Let's start with a simple one. So go inside of your home route group and remove the navbar from here and paste it inside of the components. And you might get prompted to update imports for navbar, and you can freely say yes.
And you're going to see how that looks like now. So you can see that my layout has been modified, because it has modified the navbar to be imported from the modules. And I'm just going to replace this with an alias so it's even simpler to access to. Basically, this is the refactor we're going to be doing. We're going to be adding this home-related components into their respective groups.
Now let's do the same thing with the footer. I'm going to cut the footer from the home route group and I'm going to add it to home UI components and I will update the imports. So now you can go back inside of your layout here you can see that this was modified now as well so I'm just going to change it to this. You can also manually modify it if yours was not modified at all. And let me add double quotes while I'm here.
Now let's go ahead and do the same thing for the navbar sidebar. So I'm going to cut it out from here and I'm going to add it to the components here and I will click yes for updating the imports. Let's see what was modified. So in the layout, I think nothing was modified. But I think if we go inside of the home module UI and go inside of the navbar in here, we might notice a navbar sidebar change.
So it should go to .slash navbar sidebar because that's where it is at the moment. Now let's see what else we have. We have the search filters, which we can copy, and I mean, cut out entirely and add them in the components as a big folder and select yes for updating the imports. Let's go back to the layout to confirm what has changed because I think this is where the change happened and here it is. So the search filters and the search filters skeleton should be from add modules and now all of our modules from home can be here together.
And just like that, we have decluttered our home route group. So it only includes the pages and the layouts here. Great. So, now that we have this solved, what I want to do is I want to go inside of the app folder home, and I want to create the category architecture, right. So what we're going to do is we're going to create a dynamic category route.
So if you go ahead and create a page.tsx here, you can call this category page, like this. So if you click on a main page now, it should redirect you to the category page. So this is my localhost now, slash education, which matches this exactly. Because all of these are route groups, which means not a part of the URL, not a part of the URL, not a part of the URL either. This is the first actual segment of the URL, which means that this is localhost 3000 slash and then any value.
And we are going to read this value from here. So what we can do here is the following. Interface, props, params, promise, category, string. You can mark this as an asynchronous method. And then in here, props, destructure the params, and you can do...
What's the best way I can do this? Just a second. We can destructure the category from await params, like this. And then you can say category like this. Now it says education.
Now it says business and money. Now drawing, painting, fitness and health, right? So whenever you click on this, it should show you the name of the main category with no errors whatsoever. But if you click on a subcategory, it should still bring some errors. So let's go ahead and resolve that as well.
I'm gonna go ahead and copy this and paste it inside of itself. So make sure it's inside of the category and simply change this to subcategory like this. If it asks you to update imports, you can say yes, and then you will have this weird file in the .next cache. You don't have to worry about that. Just press save and make sure you close this .next folder.
That folder gets updated automatically. You don't have to worry about that. Just press save and make sure you close this .next folder. That folder gets updated automatically. You don't have to worry about it.
Now let's go inside of the subcategory page. And besides having the category, we're also going to have subcategory. Like this. So now we can destructure both of them here. So I can now do subcategory.
I bet you didn't see the break tag in a long time, huh? There we go. So now we have the category and the subcategory available. So I can go to acrylic, there we go. I can go to education tutoring, and you can see how it works.
Why? Because this is my URL string in the subcategory. The first part is the equal part to category, and the second part is subcategory. That's why in the subcategory, we can access both of them together because every subsequent page.tsx, which is inside of this dynamic route, has access to its parent. But category, so this one, doesn't have access to the subcategory, even though this could be...
No, actually, it could not be rendered standalone. No. So yeah, only subcategory can access both its parent and itself. Right? So, yeah, the params are a promise.
I forgot to explain that. That's the Next.js convention. If you remove the promise from here and just try to do this, where you don't await them, it will still work, I think. Let me try going. There we go.
You can see it still works, but you can see that in here you get an error that category used params.category. Params should be awaited before using the properties. And you can read more about the message here. So that's why I thought you to assign it properly. It's a promise.
Great, so now we resolved our errors here. And by the way, this is where I experienced the maximum update depth error the most when I switched my pages, right? So in case you start experiencing those maximum update depth errors, it could be, if it's really annoying you, you can just downgrade 10-stack React query to 5.66.3, because that's where I didn't see that bug happening. But so far, no bugs are appearing for me at the moment, right? So I'm talking about this issue, right?
The maximum update depth exceeded because this one, right? So if you experience that, this is where I started experiencing it, when I added the ability to change routes, right? When I added more routes. But now what I want to do is I want this component search filter to actually know which route is active because sure, we know it here, but obviously we don't know it here because we keep selecting all as the active route. You might remember why that is.
If you go inside of source, this time into modules, go inside of home, UI, search filters, categories, In here, we set the active category to be all. So now it is time for us to refactor this. So let's go ahead and let's introduce params from useParams from Next Navigation. So I'm going to move that here. So this is the client way of accessing the params, right?
In our category pages, we did the server component way, and now this is the client way because this is a client component. So inside of here, what we can do now is we can destructure the category param to be params.category as string or undefined. It might not have the category at all. And then in here we can put the category param or fall back to all. So now, there we go, you can see how now it works.
I'm able to click on music. Let me try, it has to load the music first. There we go. And music stays selected. Same for drawing and painting, pathography, right?
And even if you go inside of a subcategory, it will still know that the parent is whatever the parent is, right? Why? Because we look at params.category. Subcategory is stored in the subcategory value. So if we were to look at subcategory, that would be a different story.
But for now, this is what we need here. And also, here's another cool thing that should now work. Try clicking on self-improvement or something that's next to your view all button. And if you collapse like this, basically you can see that now view all appears as the selected one, because your selected one no longer fits in here, right? So you can see when I zoom in, since it no longer fits here, we indicate to the user that your selected category is here within all the other hidden ones, right?
So I think that's pretty cool. So this is responsible for that, right? This calculates whether a selected category is hidden, right? This is why we spend so much time on this. And I honestly think it looks amazing, right?
It's super cool. Great. But we're not done yet. What I want to do now is I want to go inside of search filters index dot ESX. And in here, I want to go ahead and extract the params.
So I'm just going to go ahead and leave this as it is. But I'm going to go ahead and do const params, use params here, from next navigation, like this. And in here, I'm going to get the category param to be params.category as string or undefined. Const active category will be category param or all. So similar to what we did before.
And now let's get the active category data. So we are going to use our data dot find, get an individual category and check if that category slug matches the active category, right? Because the active category is the param. And once we are able to obtain an active category data, we're gonna do the following. Const activeCategoryColor will be activeCategoryData.color.
Question mark dot color, like this. Category color will be activeCategoryData.color?Color, like this. Or we want to fall back to the default background color. So here's what I'm gonna do. Since I now have a module for home finally, inside of that module I'm gonna create constants.ts like this and export const default background color to be F5, F5, F5, so I don't have to write it all the time.
Now I'm going to go back inside of search filters index here, and I will fall back to default background color, which I have just imported from modules home constants. Or since we are already in the modules here, I'm pretty sure I can just go back. Yeah, I can kind of do this, right? Since I'm already in the modules folder, I just have to exit the search filters and go all the way here, however you prefer to use it. Okay, so we now have the active category color.
And now is the const active category name. So in here, let's do active category data, question mark name, or no. And now we have to do a similar thing here, but for the subcategory, right? So let's do const active subcategory, params subcategory as string or undefined. And on const, active subcategory name will be activeCategoryData?
.Subcategories? Find. Question mark dot subcategories question mark find. For an individual subcategory, we're going to do subcategory dot slug equals active subcategory. And then if we are able to extract the name from that.
Or, fall back to null, because it's only the name that we need. In here, we are calling that data. We are doing the same thing, right? But in here, we need the name so we can do it directly like this. Just make sure you put a question mark here.
And now what you can do is you can replace this fixed background color with active category color. So now you can see that when you click on a specific category, it changes the color to that, even if you go to the subcategory. So the last thing I want to do here is just add the breadcrumb so we can see in here that we are in a subcategory because you can see that it's not really highlighted. So a user might not know where they are at the moment. So we're going to create a component called BreadcrumbNavigation.
And I'm going to put that... Oh, so this is the skeleton. My apologies. So just after the categories, let's add bread from navigation. Pass in the active category name.
Active category name. And let's pass in the active category to be active category and active subcategory name to be active subcategory. So yeah, this component won't exactly be too reusable. But I think that's okay, because we are going to be using ShatCN reusable components inside, right? So if we want to build the breadcrumb somewhere else, we have the components for that.
It's just that we want this specific subcategory. Okay, let me just refresh this. Okay, breadcrumb navigation is not defined. That's completely normal. Inside of search filters, which we have now officially moved to the home UI components module, go ahead and create breadcrumbs-navigation.esx.
And in here, we are going to need to import link from next link and we're going to need to import everything from the breadcrumbs from our chat CNUI. We can then also create our props here. So active category name, which is a string or null with a question mark and the same thing for the active category and active category sub name so this active category is not a good prop name this is the slug basically right that's why it's a string let's do const breadcrumb navigation Let's go ahead and assign these here. And now let's go ahead and just destructure all of them. There we go.
And now in here, if there is no active category name, or if active category is equal to all, return null. And now let's go ahead and render the breadcrumb here. And before we go further, let's just export const here. And let's go in the index and let's import breadcrumb navigation. Breadcrumb navigation.
And I have a typo here. It should be breadcrumb navigation like this. So breadcrumb navigation, there we go. Now we have the proper import here. So they are in the same folder, right?
Looks like I have the active subcategory. Oh, yeah, you should use the active subcategory name here in the prop, my apologies. So you should have no unused constants here. Now go back inside of the breadcrumb navigation. And now you should be able to see it for for now you can only see some empty space, but now we're going to start seeing this.
So now add the breadcrumb list. Check if we have the active subcategory name. If we do have it, open a fragment here and render the breadcrumb item. Breadcrumb link, let me just properly indent these like this and pass in our link here with an href of slash active category and just that and inside active category name and close the link Give this as child and class name text extra large font medium underline and text primary. So that's the first case.
But since this is for subcategory, we first show the main category name so users can click on that and go back to the main category. Now we need breadcrumb separator here. I'm just going to put a forward slash here, like this. And give this a class name, TextPrimaryFontMedium and TextExtraLarge, like this. And then another breadcrumb item, which you can copy and just move below the separator here which will be for font medium and does not need the underline nor text here and no link here actually so This is actually using the breadcrumb page and this will...
It doesn't need anything. It can just be this. Like that. You don't need as child either. And this isn't breadcrumb.
Yeah, this is breadcrumb page. And then you can just copy this last one and add the other ternary here and just render this. And inside, yeah, so here, what's supposed to render here is the active subcategory name, like this. And in the alternative ternary, it's this. And there we go.
You can now see that you can see exactly which subcategory you are on. And if you click here, it will lead you back to the other one. So I think that's exactly what we imagined here as well. Excellent. So now we officially have implemented the category pages, which means that we can start loading data inside of them.
And one thing that's bothering me is the View All button doesn't elevate. So let's quickly go back inside of categories.dsx. Let's find the View All button. It's the last one here. And I just think it's missing a variant of elevated here.
So now when I hover, there we go. Now it hovers as well. Great. I am super satisfied with how this turned out. Our breadcrumb is working nicely.
We have refactored all of those components into their appropriate fields, and we can control pretty much all pages here. Yes, also your all page should clear everything and just bring you to clean localhost. So only when some other category is at play, should it display, should it show the breadcrumbs and things. So you can see that when I'm on the main category, this isn't a link. But when I go into a subcategory, this becomes a link to go back.
Excellent. That's it. So I'm going to go ahead and mark this as finished. So we show the current main category style, we show the breadcrumbs, and we refactor components to their modules. All that's left is to push these changes to GitHub.
So quite a lot of files changed, mostly because of our refactoring, right? So we moved things like footer, navbar, sidebar, navbar, category sidebar, and all of those items in the search filters, we move them to the modules. But besides that, we've created a couple of new things such as the pages for the subcategory and the category here. And we also implemented the breadcrumb navigation here which we put inside of here. Excellent.
Let's go ahead and resolve this. So git checkout-b10, and this lesson is called category pages. Let's add. And let's push. There we go.
Now you can see that I am on a new branch. You can see that I have detached from my master branch, so I'm going to go ahead in my GitHub, open a pull request, create a pull request, and wait for the review. And here we go, the walkthrough. This pull request introduces asynchronous page components for category and subcategory routing by defining the new props interfaces and modifying the dynamic extraction of URL parameters. Those are basically these two right here.
We also replaced our legacy search filters, which are exactly the same as our new ones. We just moved them to a new place but it noticed the new breadcrumb navigation, the use of absolute paths right before because we changed them to modules now so pretty cool. It also of course added some diagrams if you wish to better understand how everything that we've just implemented is working and it also detected some related PRs like home layout where we added the footer and the navbar for the first time which we modified in this PR, the search filters because we modified the search filters this time and we introduced a whole new component inside, and of course the categories because we worked with categories again. And down here it left two comments but since these are just demo mock examples we are not going to apply them but still good suggestions. I'm going to go ahead and merge this whole request.
There we go. I'm not going to delete my branch. I'm just going to confirm that it's here. There we go. And after that is done, I'm going to check out back to my main or master branch and git pull origin main or master.
There we go. After that, I'm doing git status to confirm everything is up to date. And of course, I'm checking it visually with the graph here. We detached, we merged, I am on the master branch. And That's it.
That marks the end of this chapter with Push to GitHub. Amazing job and see you in the next chapter.