Creating a Shopping App from Scratch (Part 2)
Tags: javascript, projects, node, ecommerce
Published: 2018-03-01 08:11:25

---
title: "Creating a Shopping App from Scratch (Part 2)"
published: true
tags: javascript,projects,node,ecommerce
canonical_url: https://medium.com/@samwsoftware/creating-a-shopping-app-from-scratch-part-2-5e5ec24b2e0b
cover_image: https://cdn-images-1.medium.com/max/1024/1*JoRrqATWLevBCcsYykwI9Q.png
---

This is part 2 of a series on creating a shopping website from scratch for an upcoming interview. [Click here](https://medium.com/@samwsoftware/creating-a-shopping-app-from-scratch-part-1-352ebbd78655) to read part 1 to find out  more!

### Product Lists

I knew that this bit would end up taking a while. I had to create and populate a products model, create a get route for the API with searching capabilities, then create product list, product preview, product and filter criteria components.

The basic back end came together quickly and the front end list and preview components were done reasonable quickly too. I’d set it up so the URL was /products/:gender/:category which ended up regretting later on but it  worked.

![](https://cdn-images-1.medium.com/max/1024/1*JoRrqATWLevBCcsYykwI9Q.png)

### Filtering

This is where things started to slowly unwind. I created a filter component using multi-select drop downs, populated from the same store as the sub-header. The multi-selects worked well and I managed to get the values from them (with Google, console.log and trial-and-improvement).

I now had to work out how to turn that search query into a URL. This is where I realised that having a category as a parameter in the URL had a major problem — what if they were searching for more than one category? I had been trying to go with a /products/:gender/:category/:brand type of URL but that was not going to work  now.

After some trial and error followed by a while of contemplative frustration, I decided to go with /products/:gender?filter-criteria. I could get the filter criteria and gender and pass them straight into the getProducts action… or  not.

#### Converting Filtering into  Queries

For some reason I had left the API functionality at getting all of the available products. Now I needed to take the filter from the front end and convert it into a query for  MongoDB.

The problem with this is that the query comes in as a string and it needs to be compiled with $and and $or controls for multiple fields and multiple values for those fields respectively.

For example, requesting all women’s shoes in size 5 or 6 and in blue or white come as a string like  this:

```
?gender=womens&stock=5&stock=6&colors=blue&colors=white
```

But the query to the mongo database needs to be in this  format:

```javascript
{
  $and: [
    { gender: "womens" },
    {  
      stock: [{ 
        $elemMatch: { 
          size: [5, 6],
          stock: { $gt: 0 } 
        }
      }]
    },
    { $or: [
      { colors: "blue" },
      { colors: "white" }
    ]}
  ]
}
```

By default, express parses the above query into this  format:

```javascript
{
    gender: "womens",
    stock: [5, 6],
    colors: ["blue", "white"]
}
```

There are 3 problems with this  :

- The stock parameter is actually an array of  objects.
- The colors parameter is an array of  strings.
- We need to have all three parameters in a  product.

The stock objects look like  this:

```javascript
{ size: 4, stock: 13 },
{ size: 4, stock: 0 }
```

This means that we need to create an array of objects that have one of the sized requested and also have stock. To do this we use $elemMatch for an object with size in our size array and stock being greater than  0.

```javascript
{  
  stock: [{ // create an array of elements
    $elemMatch: { // That match 
      size: [5, 6], // size of 5 or 6
      stock: { $gt: 0 } // and stock greater than 0
    }
  }]
}
```

To handle this, I created a handleStock function.

```javascript
function handleStock(size) {
  return { 
    stock: { $elemMatch: { size: size, stock: { $gt: 0 } } } 
  };
}
```

The colors is slightly simpler. We need to find products that match blue or white. This was similarly handed by a handleColorsArray function

```javascript
{ $or: [
  { colors: "blue" },
  { colors: "white" }
]}

function handleColorsArray(array) {
  return { $or: array.map(col => ({ colors: col })) };
}
```

The last issue is making sure the products contain all of the properties. To do this, if a query had more than one parameter I would pass it to convertToAnd(). This maps over every parameter. “stock” parameters are passed to handleStock. “colours” parameters are passed to handleColorsArray if they are a array. Everything else is just passed through as  is.

Once each of the parameters has been mapped over, the array of queries is wrapped in an $and  query.

```javascript
function convertToAnd(query) {
  let q = Object.keys(query).map(param => {
    if (param === "stock") {
      return handleStock(query.stock);
    } else if (param === "colors" && typeof query.color !== "string") {
      return handleColorsArray(query.colors);
    } else {
      return { [param]: query[param] };
    }
  });
  return { $and: q };
}
```

Now if I did a call to the API with queries, it could process them and return the array of all of the matching products. Hooray!

![](https://cdn-images-1.medium.com/max/1024/1*wKz2bHUSl4uiSIwooCulzQ.png)

### Filter Criteria

Now with the API able to receive and processing the filtered queries, I had to allow the users to select and change  them.

I created a FilterCriteria component that mapped over the filtering options and created a new Select dropdown for each. This Select uses MaterializeCSS multi-select dropdown boxes so that a user could select and unselect the options that they want. Because of MaterializeCSS these boxes worked well and looked  great.

![](https://cdn-images-1.medium.com/max/1024/1*AxkGH9-Q-KvTkslT5lEYNw.gif)

Now I had to get the resulting information from the form and somehow send this to the API. The solution I came up with was to make the search button a to the URL that corresponded to the  queries.

I did this by mapping over the form and extracting all of the drop down values. I then mapped over these adding them to a query string. If a value had multiple selected options, I mapped each of them to another section of the query  string.

![](https://cdn-images-1.medium.com/max/800/1*DzGkuvaF6BvWZ58p9t1WVg.gif)

FWith the completed query string, I generate the complete URL and push it into the  history.

#### A few small  hiccups

The way that I’d set things up, it currently worked like  this:

1. Search for trainers by Fred Perry in size  5
2. Redirected to URL /products/womens?category=TRAINERS&brand=FRED%20PERRY&size=5

The problem with this is that _TRAINERS_ doesn’t match _trainers_ like in the database. The reason that it is TRAINERS in the URL is that I capitalised the strings as lower case looked really  bad.

To try to fix this, I just converted all of the strings to lower case before processing them. This brought up two new problems.

- The default values don’t equal themselves as the value from the select has been lower cased →(“category” === “Category”) is false. This means they are added to the query string as _category=Category_
- The brands no longer match the database  strings

After some over complicated attempts to capitalise certain parts I realised I could just change the original values in the database.

“red” became “Red”, “trainers” became “Trainers”. I think this also looks much better than block capitals.

This meant that I didn’t need to do any string manipulation and everything would work as it had done  before.

### Product Page

Now I had a fully filterable product list, I needed to send the customers somewhere when they clicked on a  product.

This was a simple layout — image on the left — basic details on the right — full details  below.

![](https://cdn-images-1.medium.com/max/799/1*ULtTiuK7jg_XXMz4zKWFQQ.jpeg)<figcaption>Basic wireframing</figcaption>

Building this component was simple to build and most of my time was spent styling it so that it looked good and worked well on desktop and on  mobile.

I’ve still got some work to do with this page. The _select_ boxes are being created before the product information has been received and aren’t updating their values with the correct information. The _Add to Basket_ button currently doesn’t do anything as I need to create the user/basket update methods  first.

### Account Pages

The last UI thing I decided to tackle was building an account section. Again I _borrowed_ the design from Asos, simple tabs on the right and information on the right. When on mobile, the menu was full screen width and opened a new page that had a back  button.

Each of the options (Orders, Details, Addresses) have their own UI component. These components are either rendered to the right side of the menu when on desktop, or as a separate page when viewing on  mobile.

These components are very simple, taking a prop of either auth (user) and rendering out the relevant data. Again these components currently don’t support updating the user information as I’ve decided to work on other parts of the prototype first.

![](https://cdn-images-1.medium.com/max/800/1*VMBc63-4iXD-mXg-N-7PYg.gif)

### Things to  note

It may seem like I’m building lots of components without finishing some of them, even leaving some not working properly. You’d be right. I’m doing this for 3  reasons:

- I only have 3 weeks to build it. Making 80% of it work will take 20% of the time. I’m just skipping the last 20% and saving myself a load of  time.
- This is a prototype. I’m not trying to make a perfect product, I want to show all of the ideas I have. As long as they work reasonably well and demonstrate the skills and ideas that I have, they’re meeting their requirements.
- I’m actually on holiday. I’m doing this in the last few weeks of a 6 month road trip around South East Asia. I don’t want to be spending all day every day sat inside on a laptop when I could be outside climbing and having  fum.

In the next section I’ll talk about creating a chat bot to accompany the website. I’ve never worked with chat bots before so come along for the  ride!

If you liked this article, make sure to react and follow me to see the [part 3](https://hackernoon.com/shopping-app-from-scratch-part-3-89e631a34361)!