WDD 330: Web Frontend Development II

W03 Individual Activity: Expand Inventory

Overview

Many of the changes we have already made were to prepare the site to be able to scale up to as many products as we would like. In this activity we will add products organized from four categories: Tents, Sleeping Bags, Backpacks, and Hammocks. We will need to change the index page to show our four categories, and then build a dynamic product-listing page that will pull the products from an API, and display them.

Instructions

Complete the following assignment individually. Each student will write code for their own copy.

Core Requirements

Start the Task

  1. Visit the team's copy of the Trello board for the project.
  2. Add yourself to the Individual Activity W03: Expand inventory task.
  3. If no one else has done it yet, move it to 'Doing' list.
  4. Read the details of the card.
  5. Make sure to pull any changes from GitHub before proceeding.
  6. Create a new branch called yourinitials--individual3.

Refactor

  1. Create a new directory is src called product-listing.
  2. Add a new index.html file to that directory.
    Remember that the words directory and folder have essentially the same meaning. Directory is the more accurate term for file systems while folder 📂 refers to the graphical metaphor that is generally accepted because it is highly related to the term file.
  3. Create a product-listing.js file in the js directory.
  4. Add basic HTML to the new index.html page such as the header, footer, styles, etc. You may just want to use src/index.html as a starting point. Then remove the unnecessary content including the banner and text.
    🔨 Adding a new page to the site requires that vite.config.js file be updated to let Vite know about it or the build will break.
  5. Move the JS from the main.js that is responsible to render our list of products to the new product-listing.js file.
  6. Open up product-listing/index.html in the browser to make sure the tents are still rendered.
    🔨 You will need to fix some paths to get everything working correctly. For example, the new page will not be able to find the CSS file nor the new JS file we made until the file paths are fixed. Do not worry about fixing the image URLs yet. Those will change again anyway and we will fix those later.
  7. Add a grid of four (4) boxes to the src/index.html page, one for each category. They should look something like this:
    Screenshot of index page grid
    Here are links to the icons. The icons are being used with a Creative Commons license so we need to give credit to the creator. We will do that in this case by adding it to the alt attribute:
    • Tent (alt="Tent Icon from Noun Project: Mustofa Bayu")
    • Sleeping Bag (alt="Sleeping Bag Icon from Noun Project: Mustofa Bayu")
    • Backpack (alt="Backpack Icon from Noun Project: Mustofa Bayu")
    • Hammock (alt="Hammock Icon from Noun Project: Paul Richard")
  8. Each of the category elements should link to product-listing/index.html. Make sure to pass the correct category as part of the URL (tents, backpacks, sleeping-bags, or hammocks).
    If you need a reminder of how to add a URL parameter to a link check out the template function in ProductList.mjs. It has an example of passing a parameter in the URL.

Environment Variables

We are about to change our application so that it communicates with an API server. This server will provide endpoints that we can hit (access) to do things like pull product information, login users, submit orders, etc. During development, changes are made that do not need to show up in the production environment. A development server is a testing environment used during application development. The application can be changed without worrying about the live application on the production server which has the real real data that must be protected.

This separation is very common in development. This means however that we are going to have to change the URL we use depending on whether our code is running in a development environment or a production environment. We could do this manually, but chances are that at some point the development server URL is sent to the production server❗That would be bad.

Environment variables are a way to store values that are specific to the environment the code is running in. For example, we could have a variable that stores the URL of the development server and another variable that stores the URL of the production server. Environment variables provide values that change automatically depending on where the code is running. Most of the time we create these in a file called .env (dotenv). We are using Vite as our build tool and it has the built in ability to work with these files. It will automatically look for a .env file and if it finds one it will make the variables defined therein available through a special global: import.meta.env.

Because Vite is for building frontend projects where all the code ends up in the browser, it gives us a way to control which of our environment variables become available in our client facing code. Any variable we want to use in the code we send out will need to be prefaced by VITE_ syntax.

  1. Open the .env.sample file in the src directory.
  2. Look for the variable named VITE_SERVER_URL.
  3. Note that the server URL is provided as VITE_SERVER_URL=https://wdd330-backend.onrender.com/.
    This server URL variable is not something we need to keep secret. It needs to be available in the code. It has the VITE_ prefix.
  4. 🗝️ Rename the .env.sample to .env using File->Save As. Vite will now see the file and use the variables in it.
    It is common practice to provide a sample with a different name to make it clear that it is not the real file.

You may be wondering why that file is called .env.sample. Environment variables often contain sensitive information in them and so it is common to not include those files in the Git repo for the project. If you take a look in the .gitignore file that is part of the project you will see in fact that we have already been ignoring .env files. Files named that way will never be tracked by Git.

The next question you may have is: "well if the environment variables do not get included in the repo...how do I get them out to my production environment?" That is addressed below.

When our code gets deployed to Netlify (the production environment) it will need to know the server URL it should use. Since our .env file will not be part of the repo we have to set it a different way.

Only one member of your teams needs to do the following maintenance.

  1. Log into Netlify and pull up the project.
  2. Navigate to the Site Settings->Environment Variables.
  3. Add a new variable.
  4. Enter VITE_SERVER_URL as the Key.
  5. Enter the server URL https://wdd330-backend.onrender.com/ as the Value.
  6. Be sure to Save the new variable.

Pulling from an API

Next we need to modify our code to pull the product data from an API instead of from the local JSON file. Because of the way we have structured our code this should be fairly easy.

  1. Open up ProductData.mjs.
  2. In the constructor we set a path for the products. That path was based off of the tents category and would later be used to pull the data. With the API we actually don't need to set the category in our DataSource anymore. We can pass it in when we need it. This will make our DataSource more flexible.

    Add the following line to the top of the file:
    const baseURL = import.meta.env.VITE_SERVER_URL
    Notice that we are using the environment variable we set in the .env file.
  3. Remove the category and path from the constructor.
  4. In the getData method, add a parameter of category and take this opportunity to change the fetch to use async/await. Change the getData function to look like this:
    async getData(category) {
      const response = await fetch(baseURL + `products/search/${category}`);
      const data = await convertToJson(response);
      return data.Result;
    }
    Why return data.Result? It used to be simply data. The data sent back from the API is structured differently. We will have some other corrections to make because of this as well.
  5. Open productList.js.
  6. Change the line in the init() method where we get our data. It should look like this after our changes:
    const list = await this.dataSource.getData(this.category);

You should now be seeing products listed if you click on one of the links, but there are two issues. The first is that no images are showing. The second is that all the links are showing the same list of products.

Pulling the Correct Products

You should be passing category in the URL to the product-listing page. We need to retrieve it from the parameter in product-listing.js. Then send it into the ProductList class. Remember that we created a method in utils.mjs earlier to grab parameters from a URL.

We have been moving a lot of things around. At this point your product-list.js file should look something like this:

import ProductData from './ProductData.js';
import ProductList from './ProductList.js';
import { loadHeaderFooter, getParam } from './utils.mjs';

loadHeaderFooter();

const category = getParam('category');
// first create an instance of our ProductData class.
const dataSource = new ProductData();
// then get the element we want the product list to render in
const listElement = document.querySelector('.product-list');
// then create an instance of our ProductList class and send it the correct information.
const myList = new ProductList(category, dataSource, listElement);
// finally call the init method to show our products
myList.init();

Fix the Product Detail page

If you try and click on on of the products to see the details you will notice it is broken. We will need to make some of the same changes to product.js and productDetail.js that we made for the product listing.

There are a few places we need to check to do this. We should make a list:

  1. Because we moved the product listing page into a directory the URL listed in the template for a product card in product-listing/index.html will be wrong. That needs to be fixed first.
  2. We removed the requirement for the DataSource to be set to a specific category, and we updated the getData method. Now we need to fix the findProductById method. We can query the API directly for this. The URL for the API endpoint you need to hit is: `${baseURL}product/${id}`
  3. Once you get it working you will find that the image is broken. We need to figure out why. See below for more on this.

Stretch Actviity

Fix the images

The data structure of our products changed slightly. This is why the images are broken. Analyze the data coming back from the API and figure out how to fix this issue.

You can use the PrimaryMedium image for the productList, and PrimaryLarge for the productDetail for now.

Fix the title

Title of the page currently says: Top Products. Add the category to that so that it looks like this:
Top Products: Tents (if the tent category link was selected)

Instructor's Solution

As a part of this individual activity, you are expected to look over a solution from the instructor, to compare your approach to that one.

Do NOT open the solution until you have worked through this activity individually for at least one hour. At the end of the hour, if you are still struggling with some of the core requirements, you are welcome to view the instructor's solution and use it to help you complete your own code. Even if you use the instructor's code to help you, you are welcome to report that you finished the core requirements, if you code them up yourself.

After working individually for the one hour activity, click here for the instructor's solution.

Finally

Wrap up this individual project work by finishing up your individual work and then coordinating with your team.

  1. Commit and push your changes.
  2. Meet with your team and discuss which team member's changes (branch) you would like to keep.
    Your team will only keep one.
  3. Submit a request for the branch that you decided to keep.
  4. Review the Pull Request, close it, and merge the branch back into the Main branch.
  5. Move the Trello card to the "Done" column.

Submission

Return to I-Learn to report on your work.