W04 Team Activity: Checkout
Overview
The next step for the site is to build out the checkout process.
Activity Instructions
Complete the following assignment as a team. Designate one team member as the "main driver" and collaborate on their copy of the code. Everyone on the team should be actively engaged in writing the code and contributing to the solution. Once the solution is working, make sure that everyone on the team gets a copy of the code.
There are many spots where code examples have been given. To get the most out of this activity, do not look at the examples until your team has given that section a try. Then after you look at the example, resist the temptation to copy/paste. Use the examples to get correction, or help you get unstuck.
Core Requirements
Trello
- In the synchronous meeting, the driver should visit the team's copy of the project Trello board.
- Add each of the attending team members to the
Team Activity 04: Checkout
card. - Move it to the
"Doing"
list in Trello. - Read the details of the card together.
GitHub Branch
- Pull any changes from the team GitHub project before proceeding.
- Create a new branch named
driverinitials--team4
.
The Cart
Check your cart page to make sure that it is correctly displaying a total.
If it is not then someone in your team should complete that card in Trello.
- Add a Checkout button/link that opens the checkout page.
- Next, build a
form
on the checkout/index.html page to gather the required information from the users.
The following is needed:- Customer Name
- First Name
- Last Name
- Address (treat billing and shipping address as the same for simplicity)
- Street Address
- City
- State
- Zip Code
- Payment
- Credit Card Number
- Expiration Date
- Security Code
- Checkout button
- Customer Name
- The form should not submit unless all of the fields are filled out.
- Include an order summary somewhere near the form that includes:
- Subtotal
- Tax
- Shipping Estimate
- Order Total
On a real site the server should verify the totals as well to make sure that the user doesn't try anything funny.
Order Summary
- Fill in the information in the order summary section.
✔ The item subtotal amount will come from the items in the cart.
✔ Add tax and then shipping costs.
✔ Calculate the order total.
Normally tax and shipping would be calculated according to the destination address. There would be a look up process that would figure out the right values to use. To keep it simple, use the same formulas for all orders.
Tax: Use 6% sales tax on the subtotal amount.
Shipping: Use $10 for the first item plus $2 for each additional item after that. - Create a CheckoutProcess.mjs module.
- Export a default class named
CheckoutProcess
module. - In
CheckoutProcess
, add a method to calculate and display the item subtotal. This method should get called when the page loads. - In
CheckoutProcess
, create another method to calculate and display tax, shipping, and the order total. This method should get called after the user fills in the zip code.Example:
CheckoutProcess.mjs
export default class CheckoutProcess { constructor(key, outputSelector) { this.key = key; this.outputSelector = outputSelector; this.list = []; this.itemTotal = 0; this.shipping = 0; this.tax = 0; this.orderTotal = 0; } init() { this.list = getLocalStorage(this.key); this.calculateItemSummary(); } calculateItemSubTotal() { // calculate and display the total dollar amount of the items in the cart, and the number of items. } calculateOrderTotal() { // calculate the tax and shipping amounts. Add those to the cart total to figure out the order total this.tax = (this.itemTotal ...) this.shipping = this.orderTotal = // display the totals. this.displayOrderTotals(); } displayOrderTotals() { // once the totals are all calculated display them in the order summary page const tax = document.querySelector(`${this.outputSelector} #tax`); tax.innerText = `$${this.tax.toFixed(2)}`; } }
Refactor ProductData
Use the same server from previous weeks to pull the products for submitting the orders, however, there is a different endpoint. The URL is:
http://wdd330-backend.onrender.com/checkout
Note that because data is now being sent to the server, a POST
request is required instead of a
GET
request.
The ProductData
module is currently making requests to the server and so this would be the logical
place to add the functionality to submit an order. However, the name "ProductData
" becomes less
descriptive of what is going on in the module. It would more descriptive to name it ExternalServices
.
If you panicked a bit when you read that you are paying attention. Renaming something that you have already used in multiple places is not something to do lightly, but sometimes it is necessary. Because of this, good development tools, like VS Code, have built-in ways to assist with development.
- Commit and push your changes before proceeding. That will make it easy to revert if something goes wrong.
- Open ProductData.mjs and select the word
ProductData
in the class definition. Right click on it and select Rename symbol in the menu. - Enter "
ExternalServices
" and hold down the ctrl key while hitting enter/return (or whatever key combination the dropdown menu tells you to do) to preview the change. A new panel named Refactor Preview will open in the editor and display all the instances where the where the name will need to be changed. Left-click on one of the lines it will open the file showing the proposed change. Clicking Apply in the panel will submit the change. Review each change and make the updates as needed. -
Next, rename the file of the module so that it reflects the change. If you right-click on the file in the File
Explorer and select rename there you should get a pop-up message that asks if you want to rename the
imports as well. Say yes and select
File->Save All
again. - Finally, just to make sure nothing was missed, go to the Activity Bar on the side of your
VS Code window and click on the Search (magnifying glass 🔎) icon (ctrl/cmd + shift + F). Type
ProductData
and if there are any more instances and change them. - Test the product list and product detail pages to make sure they still work.
Submit the Order – CheckoutProcess
The checkout process will involve a server. It is expecting us to send it an object with all the information about the order in a specific format. The object should look like the following (order does not matter):
{
orderDate: '2021-01-27T18:18:26.095Z',
fname: "John",
lname: "Doe",
street: "123 Main",
city: "Rexburg",
state: "ID",
zip: "83440",
cardNumber: "1234123412341234",
expiration: "8/21",
code: "123",
items: [{
id: "20CXG"
name: "The North Face Pivoter 27 L Backpack"
price: 39.99,
quantity: 1
}, {
id: "14GVF",
name: "Marmot 5°F Rampart Down Sleeping Bag - 650 Fill, Mummy (For Men and Women)",
price: 229.99,
quantity: 1
}],
orderTotal: "298.18",
shipping: 12,
tax: "16.20"
}
Note that the keys in your object MUST match the keys shown above. You cannot send "firstName". It has to be "fname". That is what the server will be expecting. Check your names in the html form if you have differences.
- Write a function in
CheckoutProcess
that will be used to prepare the order items list for use in this module.// takes the items currently stored in the cart (localstorage) and returns them in a simplified form. function packageItems(items) { // convert the list of products from localStorage to the simpler form required for the checkout process. // An Array.map would be perfect for this process. }
- Write a
checkout
function inCheckoutProcess
that will get called when the form is submitted and will get the data object ready and send it toExternalServices
.async checkout(form) { // get the form element data by the form name // convert the form data to a JSON order object using the formDataToJSON function // populate the JSON order object with the order Date, orderTotal, tax, shipping, and list of items // call the checkout method in the ExternalServices module and send it the JSON order data. }
If you are struggling to convert your form into the object required take a look at the function below.
Example
// takes a form element and returns an object where the key is the "name" of the form input. function formDataToJSON(formElement) { const formData = new FormData(formElement), convertedJSON = {}; formData.forEach(function (value, key) { convertedJSON[key] = value; }); return convertedJSON; }
-
Use
1234123412341234
for the card number,123
for the security code, and any expiration in the future if you want your order to succeed.For testing to save you time and typing remember that you can set the
value=""
property of an HTML input element. Remember to remove your defaults once everything is working. -
The method should POST that object. You will need to create a custom options object and pass it in with your
fetch. (Remember to stringify your object before sending it!) to the address above
(https://wdd330-backend.onrender.com:3000/checkout) and return the server response. The response will be JSON.
All of the requests made thus far have been fairly simple and the default settings for fetch have been sufficient. The defaults will not work for us here. Fetch has an optional second argument that is for options. An options object that will work for use here is below:
const options = { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload)}
That can be used like this:
fetch(url, options);
The choices include watching for a
click
event on the form button, or watch for asubmit
event on the form. -
Whichever you choose, you will want to keep the form from doing what it would normally do on submit. You can do
this by calling
event.preventDefault()
in the listener function. - You can consider this activity completed when you receive a response from your POST to the server. The next activity will continue this by handling the success and failure responses appropriately.
Example Solution
As a part of this team 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 as a team 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 example solution and use it to help you complete your own code.
Example Solution
Make a Pull Request
After you have completed what you can, reviewed the example solution, and gotten your code working:
- the driver should commit and push the changes,
- the driver should submit a pull request for this branch,
- the team reviews the pull request, closes it, and merges the branch back into the Main, and
- finally, someone moves the Trello card to "Done".
Submission
Return to Canvas to report on your work.