Lab - Build Basic Catalog Pages
Introduction
Your basic Next.js storefront build currently features only a store logo. Let’s expand it with basic catalog pages.
In this lab, you will:
- Add a main nav menu with your store’s top level categories
- Implement a basic category page with a product list
- Add pagination to the category page
- Implement a basic product detail page
Prerequisites
This exercise builds on the basic Next.js application begun in the previous lab and has the same technical requirements.
Your store should have the following catalog data associated with your headless channel:
- Multiple enabled top-level categories with a description, image, and products assigned
- Visible products with a SKU, default price, description, and default image
Setup
This exercise continues where you left off previously in your basic Next.js project. Simply start the dev server from the project root if it’s not currently running:
If you need a fresh start, you can follow the instructions below to set up a new project complete with previous exercise code.
- In your terminal, run the following, replacing the path to the working directory with your own path:
- Copy
.env.exampleas.env.localand modify.env.localwith configuration details for your store. - Start the dev server process:
- Browse to the local URL printed in the
pnpmoutput and verify your home page loads successfully.
Exercise Reference Copy
You may choose to download or clone the completed version of this lab in a separate location to serve as a reference for the final state.
Add a Main Nav Menu
Let’s add a simple nav menu to the storefront header, consisting of links to top-level categories. This will require querying additional data from the GraphQL Storefront API, specifically categoryTree. Note that, since this data is to be made available to all pages like the store settings you’re already fetching, we’re going for maximum efficiency by including it in the same query. This is part of the power of GraphQL.
- In
components/header/_data/component-data.ts, modify the GraphQL query to includecategoryTreedata, and add corresponding details to the response type.
- In the same file, modify
getHeaderSettingsto add nav categories to the result object.
- Open the file
components/header/index.tsx. AddnavCategoriesto the destructuring ofgetHeaderSettings.
- In the same file, add HTML structure for the main nav to the returned JSX.
You should be able to verify that the menu now displays on your home page!
Implement the Category Page Query
The categories in the main nav menu each link to a URL path like /category/someCategorySlug. Let’s flesh out the page route for this pattern. You’ll first need to implement the right GraphQL query to fetch the needed category information, including the category’s products.
- Open the file
types/catalog.ts. Fill in the details of theCategoryProductandBasicCategoryinterfaces as shown below.
These two definitions will help facilitate the right response type in the next step, where the basic category and product fields are the same but the structure of products is not as flat.
- Open the file
app/category/[...catPath]/page-data.tsand add the following code to define the query and the various necessary types.
This is a verbose block of code, but mainly because we’ve created two different versions of the query: getCategoryWithBeforeQuery and getCategoryWithAfterQuery. These support the GraphQL variables necessary for “previous” and “next” pagination, which you’ll make use of in subsequent steps. To avoid as much duplication as possible, GraphQL fragments are used for the fields selected for category and product records.
Note the GetCategoryWithProductsResp interface, defining the expected GraphQL response. The products field, rather than directly returning a list, has the sub-field edges, and each item in that list contains the field node. We’ve injected the BasicCategory and CategoryProduct interfaces separately into this structure.
Finally, note that the GraphQL queries already support the before and after arguments even though we’re not yet implementing pagination. This will avoid the need for major refactoring in the following steps.
- Update
getCategoryWithProductsto accept the proper input, perform the query, and parse the category and product data.
Just as we’re not implementing pagination yet, we also won’t be performing this fetch with any specific customer context. Nevertheless, the function supports a customerToken parameter that it passes in the GraphQL fetch, supporting this option for the future.
- Update the return value of
getCategoryWithProductsto return the appropriate values.
- Open the file
app/category/[...catPath]/page.tsx, the route file that will actually handle page requests like “/category/{category-name}”. Note that the file path segment in square brackets is a “catch-all” segment that will capture everything after “/category” in the URL. - For now, we’ll simply perform the appropriate fetch when the page is loaded and log the category data. Modify the
CategoryPagecomponent as follows.
params is a standard Next.js convention and will contain the values of any dynamic URL segments (in this case, catPath). With the URL path, we have what we need to call getCategoryWithProductsto fetch the data.
- In your browser, navigate to a category with a description and image attached. While the page will be blank, the terminal output where pnpm run dev was executed should display a log of the fetched category data.
Implement Category Page Content
- Still in
app/category/[...catPath]/page.tsx, remove theconsole.logstatement and add code to return a 404 response if no category is found.
- Update the page component to flesh out its content.
This JSX content utilizes a separate component - ProductCard- for each product on the category page. This component is currently empty and doesn’t even accept the props being passed to it, so let’s flesh it out.
- Open the file
components/product-card/index.tsxand update the component as follows.
- In your browser, navigate to a category with a description and image attached and observe the details in the category page.
Add Product List Pagination
Your category page displays one page of a category’s products, but currently there is no way to see more results. Let’s add this support for pagination.
The getCategoryWithProducts query already supports arguments for filtering the product list, but for full pagination support you also need to query data about the current “page” of results.
- In
app/category/[...catPath]/page-data.ts, add a fragment string definingpageInfofields, then utilize that fragment in both versions of the category query.
- In the same file, modify the response type definition to account for page data.
- Modify the return logic in
getCategoryWithProductsto include info about the current page.
Now the function returns data including the startCursor from the current result set only if there is a previous page and the endCursor if there is a next page.
Next, you’ll modify the category page component to use URL querystring information for paging. The expected URL pattern will be /category/someCategorySlug?before={productCursor} or /category/someCategorySlug?after={productCursor}.
- Modify
app/category/[...catPath]/page.tsxto use thepagefield on the category to conditionally output paging links.
- In the same file, modify the component to capture any
beforeorafterquerystring params and pass them into to the query.
- Browse to a category again and observe the pagination links in action.
If your category doesn’t contain enough products for multiple pages, temporarily set the limit value passed to getCategoryWithProducts to 1 or a sufficiently small value to see the effect.
Implement a Product Query
The process of creating a product detail page will look similar to that of creating the category page, starting with crafting the GraphQL query.
- Fill in the
Productinterface definition intypes/catalog.ts.
- Open the file
app/product/[...productPath]/page-data.tsand add the GraphQL query and vars/response types.
- In the same file, update the
getProductfunction to perform the query and return the product.
- Open the file app/product/[…productPath]/page.tsx and update the page component as follows to capture the URL path and fetch the product.
- From a category page in your browser, navigate to a product detail page to verify the product’s basic details are logged to the output of the terminal where
pnpm run devwas executed.
Implement Product Page Content
- Open the file
app/product/[...productPath]/page.tsx, remove the logging statement, and add an early return if no product was found.
- In the same file, update the page component definition with the following content.
- From a category page in your browser, navigate to a product detail page to verify the product’s basic details are displayed.
Full Lab Code
Taking it Further
What you have so far is a basic but still incomplete catalog implementation. If you want to continue to flesh out your Next.js storefront on your own, below are some possibilities for expansion.
- Fetch a more deeply nested list of categories with the
categoryTreequery and utilize this data to build a multi-level main nav with drop-downs for subcategories. - Add images to the product query to fetch all images assigned to the product, and utilize this data in the product page component to build a complete gallery.