W04 Team Activity: Checkout
Overview
The next step for our 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 group 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 group should really complete that card in Trello.
- Add a Checkout button/link that will take us to the checkout page.
- Next we need to build a form on the checkout page to gather the required information from
our users.
We will need the following:
- Customer Name
- First Name
- Last Name
- Address (we will assume billing and shipping are the same)
- 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
- Shipping Estimate
- Tax
- 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
- We need to fill in the information in the summary section. The item subtotal will come
from the items in the cart, and then we need to add tax and shipping costs and calculate the
order total. Once the user supplies a zip code you should calculate both shipping and tax
and display it in the order summary to the user.
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 ours simple we will use the same formulas for all orders.Create aTax: Use 6% sales tax.Shipping: Use $10 for the first item plus $2 for each additional item after that.
CheckoutProcess
module, and add a method to calculate and display the item subtotal. This should get called when the page loads. - It that same module, create a second method to calculate and display shipping, tax, and
the order total. This method should get called after the user fills in the zip code.
Example:
CheckoutProcess
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(); } calculateItemSummary() { // calculate and display the total amount of the items in the cart, and the number of items. } calculateOrdertotal() { // calculate the shipping and tax amounts. Then use them to along with the cart total to figure out the order total // display the totals. this.displayOrderTotals(); } displayOrderTotals() { // once the totals are all calculated display them in the order summary page } }
Refactor ProductData
We will use the same server we used last week to pull the products from for submitting our orders, but a different endpoint. The URL should be:
http://wdd330-backend.onrender.com/checkout
Because we need to send the order information we will need to make a POST request to the server instead of the GET request we have been using.
We are already making requests to this server for product data through our ProductData
module. This would be the logical place to add the functionality to submit an order. The name
"ProductData"
becomes less descriptive of what is going on in the module now however. It would more
descriptive with the name ExternalServices
.
Refactor your code to make this change.
- Commit and push your changes before proceeding. That will make it easy to revert if something goes wrong.
- Open
ProductData.mjs
and select the wordProductData
in the class definition. Right click on it and select Rename symbol in the menu. - Enter
ExternalServices
and hold down the shift key while hitting enter/return. This will preview the changes. It should open up a new panel in the editor where it will show you everywhere it found the name that you want to change. If you left-click on one of the lines it will open the file side by side with how it was before the changes and how it will be after. Review each change. If the changes looks good then right-click on the same line in the Preview panel and select apply Refactoring. Then goFile->Save All
-
Next we need to adjust the filename of the module so that it reflects the change. If you
right-click on the file in the file explorer in VS Code and select rename there you should
get a pop-up message that asks if you want to rename the imports as well. Say yes!
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 magnifying glass icon (ctrl/cmd + shift + F). Type
ProductData
and if there are any more instances, change them. - Test the product list and product detail pages to make sure they still work.
Submit the Order
Our 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"
}
Create a couple of functions in your CheckoutProcess
module.
- One will be used to prepare the items list part of this object for us.
- The other will get called when the form is submitted and will get the data object ready
and send it to ExternalServices.
// 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. Array.map would be perfect for this. } export default class CheckoutProcess { ... async checkout(form) { // build the data object from the calculated fields, the items in the cart, and the information entered into the form // call the checkout method in our ExternalServices module and send it our data object. } }
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.If you are struggling to convert your form into the object required take a look at the function below.
HINT
// 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 thevalue=""
property of an HTML input element. Remember to remove your defaults once everything is working. -
Add a new method to our newly renamed
ExternalServices
class. Call itcheckout
. It should accept the object that represents our order. -
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 we have 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}
We would use it like this:
fetch(url, options);
The choices include watching for aclick
event on the form button, or we can 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.
Instructor's 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 instructor's solution and use it to help you complete your own code.
Finally - Make a Pull Request
After you have completed what you can, reviewed the instructor's 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 I-Learn to report on your work.