Skip to content

Instantly share code, notes, and snippets.

@lg-bot

lg-bot/README.md Secret

Last active July 31, 2017 21:49
Show Gist options
  • Select an option

  • Save lg-bot/1be9e9b91fc0f972b74b72df34c99d3d to your computer and use it in GitHub Desktop.

Select an option

Save lg-bot/1be9e9b91fc0f972b74b72df34c99d3d to your computer and use it in GitHub Desktop.
Phase 3 Interview Challenge A

Phase 3 Interview Challenge A

This is the challenge for getting into phase 3. There are 3 parts to the challenge.

To get started, create a new repository called phase-3-challenge. Do all of your work in this repo and submit it as your solution.

Skills covered:

  • Programming
  • Programming in JS
  • Node.js
  • HTTP
  • HTTP Applications
  • HTML & CSS
  • The Browser
  • SQL

Each requirement has a point value. A fully complete requirement gets full points; partially complete requirements get partial points; incomplete requirements get no points. Completeness is determined by calculating points earned divided by total points available.

General Requirements

  • 10: Solution is in a public repository called phase-3-challenge.
  • 10: Solution repository has 3 folders: part-1, part-2, and part-3.
  • 10: Solution repository includes a .gitignore ignoring files that don't shouldn't be committed (e.g. node_modules/, *.log files).
  • 10: Parts 1 and 2 have their own package.json specifying dependencies.
  • 20: Git history shows frequent commits.

Part 1: Simple web app

Build a very basic web app to perform basic calculations on numbers supplied in the URL.

Use Express. You don't need to use an HTML templater like EJS or Pug, just respond with plain text.

The web server should provide the following routes:

/api/supported-operations
/api/square
/api/compute

All routes just respond with a JSON response.

Example requests and responses:

// First route
request: GET /api/supported-operators
response: {"/": "division",
           "+": "addition",
           "-": "subtraction",
           "*": "multiplication"}
response content-type: application/json


// Second route
request: GET /api/square?number=10.5
request content type: application/json
response: {"result": 110.25}
response content-type: application/json

// Third route
request: POST /api/compute
request body params: {"operator": "+",
                      "operands": [3,4]}
request content type: application/json
response: {"result": 7}
response content type: application/json


request: POST /api/compute
request body params: {"operator": "/",
                      "operands": [5,3]}
request content type: application/json
response: {"result": 1.67}
response content type: application/json


request: POST /api/compute
request body params: {"operator": "?",
                      "operands": [5,3]}
request content type: application/json
response: {"error": "invalid operator ?. Valid operators are /, +, -, *"}
response content type: application/json
response status code: 404

Requirements

  • 10: All files are stored under the part-1/ folder
  • 10: All dependencies are specified in a package.json file
  • 10: Web server can be started with npm start command
  • 20: GET requests to the /api/supported-operators route responds with JSON content, as described in the example above
  • 80: POST requests to the /api/compute route add the two numbers provided in the request body and responds with the result. An invalid operator should return a 404.
  • 20: GET requests to the /api/square route squares the number provided in the query string variables number.

Part 2: Database for grocery store & tests

Build a small PostgreSQL database for a grocery store, then connect and write queries using Node.js. Same idea as in part 3, but focused on the database side.

Design a database to store grocery items, shoppers, and shoppers' orders. Let's call the database grocery_store (so clever, I know).

You'll need to design the schema and write some SQL statements to insert data. Look closely at the requirements to determine how to design your schema.

Use the provided grocery item data to seed your grocery items table, and write some custom insert statements to add 3-5 rows to the shoppers and orders tables and any join tables you may need to connect them all.

Then, use pg-promise and Mocha + Chai to write and test database queries.

Requirements

  • 10: All files are stored under the part-2/ folder
  • 10: Database schema (all CREATE TABLE statements) is defined in a file schema.sql
  • 10: SQL script to insert grocery seed data and load from CSV is created in a file load-data.sql
  • 10: All database query functions are written in a file database.js, and tests for queries are written in a file database_test.js
  • 10: Tests can be run with the command $ npm test

User Stories: Ensure that your schema design can satisfy the following scenarios

  • 10: As a shopper I can fetch all my orders
  • 10: As a shopper I can have multiple items in an order

Implement these functions in database.js using pg-promise to make the following queries:

  • 20: allItems() : Find the IDs, names, prices, and sections for all grocery items
  • 20: itemsInSection(<section>) : Find the IDs and names of all grocery items in the given section
  • 20: cheapItems() : Find the IDs, names, and prices of all grocery items that cost less than $10.00, ordered from lowest to highest price
  • 20: countItemsInSection(<section>) : Get the count of all grocery items in the given section
  • 20: mostRecentOrders() : Find the IDs and order dates for the 10 most recent orders
  • 20: lastShopperName() : Find the shopper's name who made the most recent order
  • 20: orderTotal(<ID>) : Find the sum of all prices for items for a specific order

Write tests with Mocha + Chai in database_test.js that assert:

  • 20: A call to itemsInSection("bulk") returns the items "Flour", "Pasta", and "Rice"
  • 20: A call to cheapItems() returns the item with name "Fish" as the first item and the item with name "Honey" as the last item
  • 20: A call to countItemsInSection("packaged") returns 5

Part 3: Web interface for grocery store

Create a front-end only site for an online grocery store where users can choose from a list of items and add them to a cart.

You only need to write HTML, CSS, and JavaScript. No web server is required.

The initial layout has already been provided for you in the grocer.html and grocer.css files. From this base, build the modal and add interactive behavior with JS.

Note that this interface has been intentionally simplified for the purposes of this challenge: for example, when adding multiple items it will just duplicate the same item instead of adding to a quantity.

Wireframe

Clicking on the "Cart" button opens the cart modal.

modal

Requirements

  • 10: All files are stored under the part-3/ folder
  • 20: No third party CSS or JS libraries are used (all code must be written from scratch)
  • 10: HTML, CSS, and JS are separated into their own files.
  • 20: Clicking on a section in the "Sections" sidebar will jump to that section in the page
  • 20: Clicking on "Add to cart" will update the number displayed next to the "Cart" button to show the total number of items in the user's cart
  • 20: Clicking on the "Cart" button will show the cart modal with a list of all items added
  • 20: Clicking on the "Clear" button in the cart modal removes all items from the cart
  • 20: Clicking on the "X" button in the cart modal closes the modal
  • 20: The "Total" in the cart modal shows the calculated sum of all item prices
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: "Lucida Grande", "Helvetica", sans-serif;
}
/* LAYOUT UTILS */
.flex {
display: -webkit-flex;
display: flex;
}
.flex-column {
flex-direction: column;
}
.flex-row-between {
flex-direction: row;
justify-content: space-between;
}
.flex-full {
flex: 1;
}
/* HEADER */
.site-header {
flex: 0;
padding: 4px 0px;
border-bottom: 2px solid #ccc;
background-color: #eee;
}
.site-header > *:first-child {
margin-left: 12px;
}
.site-header > *:last-child {
margin-right: 12px;
}
.site-header h1 {
font-size: 24px;
}
.site-header button {
font-size: 20px;
}
/* SIDEBAR */
.sidebar {
flex: 0 0 20%;
border-right: solid 1px #ccc;
}
.sidebar ul {
list-style-type: none;
margin: 0;
padding: 0;
}
.sidebar h4 {
background-color: #ddd;
border-bottom: 1px solid #ccc;
margin: 0;
padding: 4px;
}
.sidebar li {
padding: 4px;
}
/* CONTENT */
.content {
flex: 1;
padding: 4px 0;
}
.content * {
padding: 0 12px;
}
/* ITEM LIST */
.item-section {
list-style-type: none;
margin: 32px 0 0;
padding: 0;
}
.item-section h3 {
font-weight: normal;
font-style: italic;
}
.item {
margin-bottom: 8px;
}
.item:hover {
background-color: #eee;
}
.item > * {
font-size: 18px;
padding: 8px;
}
.item-name {
flex: 1;
}
.item-price {
flex: 0;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Grocer</title>
<link rel="stylesheet" href="grocer.css">
</head>
<body class="flex flex-column">
<header class="site-header flex flex-row-between">
<h1>Grocer</h1>
<button type="button" id="cart-button">
Cart
&nbsp;<span id="cart-item-count">(3)</span>
</button>
</header>
<div class="flex flex-full">
<div class="sidebar">
<ul>
<h4>Sections</h4>
<li>Produce</li>
<li>Deli</li>
<li>Frozen</li>
</ul>
</div>
<div class="content">
<h1>Groceries</h1>
<ul class="item-section">
<h3>Produce</h3>
<li class="item flex flex-row-between">
<span class="item-name">Onions</span>
<span class="item-price">$1.11</span>
<button type="button">Add to cart</button>
</li>
<li class="item flex flex-row-between">
<span class="item-name">Tomatoes</span>
<span class="item-price">$1.56</span>
<button type="button">Add to cart</button>
</li>
<li class="item flex flex-row-between">
<span class="item-name">Carrots</span>
<span class="item-price">$2.88</span>
<button type="button">Add to cart</button>
</li>
</ul>
<ul class="item-section">
<h3>Deli</h3>
<li class="item flex flex-row-between">
<span class="item-name">Cold Cuts</span>
<span class="item-price">$1.47</span>
<button type="button">Add to cart</button>
</li>
</ul>
<ul class="item-section">
<h3>Frozen</h3>
<li class="item flex flex-row-between">
<span class="item-name">Orange Juice</span>
<span class="item-price">$2.52</span>
<button type="button">Add to cart</button>
</li>
<li class="item flex flex-row-between">
<span class="item-name">Ice Cream</span>
<span class="item-price">$14.08</span>
<button type="button">Add to cart</button>
</li>
<li class="item flex flex-row-between">
<span class="item-name">Pizza</span>
<span class="item-price">$16.61</span>
<button type="button">Add to cart</button>
</li>
</ul>
</div>
</div>
</body>
</html>
name price section
Aluminum Foil 8.84 miscellaneous
Apples 10.81 produce
Bacon 9.01 meat
Bagles 10.67 bread
Baguette/French Bread 5.01 bread
Barbeque Sauce 16.96 packaged
Butter 4.29 dairy
Carrots 2.88 produce
Cheese 1.75 dairy
Coffee 6.17 packaged
Cold Cuts 1.47 deli
Cream Cheese 16.11 dairy
Croissants 6.36 bread
Eggs 2.66 dairy
Fish 0.49 meat
Flour 8.74 bulk
Fruit 8.87 produce
Grapes 8.78 produce
Green Beans 7.86 produce
Ground Beef 16.03 meat
Ham 13.27 meat
Honey 9.31 packaged
Ice Cream 14.08 frozen
Ketchup 2.94 packaged
Lemons 17.24 produce
Lettuce 16.28 produce
Milk 2.34 dairy
Mushrooms 16.68 produce
Oil 5.25 packaged
Onions 1.11 produce
Orange Juice 2.52 frozen
Oranges 3.40 produce
Pasta 13.39 bulk
Pizza 16.61 frozen
Potatoes 13.29 produce
Rice 5.23 bulk
Salami 12.70 meat
Soda 11.21 miscellaneous
Sour Cream 1.73 dairy
Tomatoes 1.56 produce
Yogurt 18.67 dairy
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment