-
Style the BODY element with a white background color
-
Create a DIV and give it a
data-cart-info
attribute. Inside the DIV, create a HEADING withmdc-typography--headline4"
as its CSS class -
The HEADING should have 2 SPAN elements. The First displays a shopping cart by setting its class to
material-icons
and setting its content to shopping_cart. The second SPAN has an attribute ofdata-bill
and will be used to display the total figure the user is trying to pay on the app -
After the
data-cart-info
DIV, create another DIV, give it an attribute ofdata-credit-card
and set its class tomdc-card
andmdc-card--outlined
Within thedata-credit-card
DIV, create a new DIV with a class ofmdc-card__primary-action
These elements will be styled with the look and feel of an actual credit card! -
Within the
.mdc-card__primary-action
DIV, create an IMAGE with an attribute ofdata-card-type
and set its SRC to[http://placehold.it/120x60.png?text=Card](http://placehold.it/120x60.png?text=Card)
. This IMAGE will be used to display the credit card type, based on the series of numbers entered by the user -
Right after the IMAGE, create a DIV with an attribute of
data-cc-digits
. It should contain four INPUT text fields, each with asize
of4
and a placeholder of ---- (4 dashes). These fields will be used to collect the credit numbers -
Create a DIV with an attribute of
data-cc-info
as a sibling to thedata-cc-digits
DIV. This new DIV should have two INPUT text fields, one for entering the card holder's name while the other will be for the card's expiry date. The first field should have asize
of20
and aplaceholder
ofName Surname
. The expiry date field should have asize
of6
and aplaceholder
ofMM/YY
- indicating the expiry date format.
We are now done with the structure of the credit card component. Let's make a button to allow the user make payment with the card details
- Create a BUTTON as a sibling to the
data-credit-card
DIV. Set the BUTTON's class tomdc-button
and give it adata-pay-btn
attribute. It should havePay & Checkout Now
as its display text. After the user enters details of the card and clicks on this button, the app will strike-though the card numbers to indicate that they are in-valid.
While we might have the right structure in place, the app visually tells a different story. Time to make the app look good and usable.
-
SPAN elements within the
data-cart-info
DIV should be displayed as inline block elements, andvertical-align
set tomiddle
. The.material-icons
SPAN should have a150
pixels size of font. -
Give the
data-credit-card
DIV435px
width,240px
minimum height,10px
rounded borders, and a#5d6874
background colour. -
Display the
data-card-type
IMAGE as a block element. Give it a120px
width and a60px
height. -
The
data-cc-digits
DIV should have a2em
top margin. -
INPUT elements in the
data-cc-digits
DIV should have a white color,2em
font size and line height, no border or background, and a right margin of0.5em
; -
The
data-cc-info
DIV should have a1em
top margin. -
INPUT elements in the
data-cc-info
DIV should have a white color,1.2em
font size, no border and no background. The second input should also have a right padding of10px
and be floated to the right of the viewport. -
The
data-pay-btn
BUTTON should have a fixed position,90%
width, solid border of1px
and positioned20px
from thebottom
of the viewport.
Your app should look functional at this point.
Write all Javascript strictly with ES6. This means use arrow functions instead of the function keyword. Declare variables and functions with
const
orlet
. Useconst
by default, and only uselet
if you are sure you need to re-assign values to the said variable. Use the Selector API instead of the getElementBy... or getElementsBy... APIs.
Install the JSON Viewer Chrome extension, open a new tab and go to this API endpoint. You will be making HTTP requests to the API, so spend some time looking at the structure of the response data.
-
Create an
appState
variable and assign it an empty Object literal. This variable will hold data for the app. -
Create a
formatAsMoney
function. It should take in anamount
and abuyerCountry
parameter. It will use these parameters to format the user's bill as a proper currency. -
Create
detectCardType
,validateCardExpiryDate
, andvalidateCardHolderName
functions. Each should take in a parameter and use object de-structuring to obtain thetarget
property of the parameter. -
Create a
uiCanInteract
function. It will be called to setup the UI like adding event handlers to enable interactions with the app. -
Create a
displayCartTotal
function. It should expect a parameter and should use object de-structuring to obtainresults
property of the parameter. This function will be called with the data from an API call and it will display the total payment bill.
-
Create a
fetchBill
function. It should assignhttps://randomapi.com/api/006b08a801d82d0c9824dcfdfdfa3b3c
to anapi
variable. It should then use the browser'sfetch
function to make a HTTP request toapi
. Using an arrow function in a.then
call to thefetch
function, return the response after converting it to JSON. Using another.then
call to the first one, pass the JSON data todisplayCartTotal
. Make sure to handle errors that may occur, e.g by showing a warning message in the console. -
Call the
fetchBill
function from insidestartApp
.
-
In
displayCartTotal
, de-structure the first item in theresults
array into adata
variable. Next, use object de-structuring to obtain theitemsInCart
andbuyerCountry
properties ofdata
. -
Set
appState.items
toitemsInCart
and setappState.country
to buyerCountry -
Use the Array
.reduce
function to calculate the total bill fromitemsInCart
Note that each item has aqty
property indicating how many of that item the user bought. Assign the calculated bill toappState.bill
-
Go back to the
formatAsMoney
function. Use the.toLocaleString
function on itsamount
andbuyerCountry
to formatamount
as a currency with the currency symbol ofbuyerCountry
. The countries and their currency symbols are in thecountries
array you got in your starter code. If thebuyerCountry
is not incountries
, then useUnited States
and the country and format the currency accordingly. -
back to where you left off in
displayCartTotal
, use theformatAsMoney
function to setappState.billFormated
to the formatted total bill. The already assignedappState.bill
andappState.country
should come be handy now! -
Set the text content of the
data-bill
SPAN to the formatted bill set inappState.billFormated
-
Finally, call
uiCanInteract
to wrap updisplayCartTotal
Run the app (click the play button) and see if the correct formatted bill is displayed in the UI. Next, we will allow input and interaction so that users can provide payment information.
-
Create a
flagIfInvalid
function just afterformatAsMoney
function. This function is used to mark an input entry as invalid (strike-though) nor not. It should take afield
andisValid
parameters. IfisValid
is true, it should remove theis-invalid
class fromfield
, otherwise it should add it tofield
. -
Just after
flagIfInvalid
function, create aexpiryDateFormatIsValid
function which takes atarget
parameter representing the card's expiry date field. It should return true if the field's value complies with the MM/YY format, otherwise it should return false. -
With the above utility functions out of the way, go back to the
validateCardExpiryDate
function. It's de-structuredtarget
parameter will be the card's expiry date field. This function should return true if the value provided matches theMM/YY
format (hint: delegate to expiryDateFormatIsValid) AND if the date is in the future. In either case, it should use theflagIfInvalid
function to mark the field as valid or not. It then has to return true or false depending on if the validation requirements are met or not. -
Now to the
validateCardHolderName
function. It's de-structuredtarget
parameter will be the card holder's name. Recall that its placeholder already suggests the required format, which is Name Surname (2 names separated by space). Each name should be at least 3 characters long. It should use theflagIfInvalid
function to mark the field as valid or not and then return true or false depending on if the validation requirements are met or not.
The
detectCardType
function displays a Visa or MasterCard logo depending on the card number entered by the user. For simplicity sake, our Visa card numbers begin with 4 and MasterCard numbers begin with 5. These are the only supported credit cards in the PayCard app
Sample valid card numbers for your tests:
Visa:
4556372551434601
4916337563926287
4716361721613449
4539818898404311
4929416075118388
MasterCard:
5130752529459529
5250457226640843
5330664490375584
5241343263959571
5250445524664938
-
Create a
validateCardNumber
function above theuiCanInteract
function. -
The
detectCardType
function has a de-structuredtarget
parameter which represents the first (of four) input field containing the first 4 digits of the card. If it detects a Visa card, it should addis-visa
to thedata-credit-card
DIV, else it should remove it to addis-mastercard
instead, and vice versa. This gives the card a somewhat branded feel. To display the right card logo, it should set thesrc
of thedata-card-type
IMAGE using the data URLs provided in thesupportedCards
object. Finally, it needs to return theis-visa
oris-mastercard
value depending on the type of card detected
The
uiCanInteract
function will wire up event handling for PayCard
In the uiCanInteract
function
-
Set
detectCardType
as theblur
event listener for the first INPUT element in thedata-cc-digits
DIV. -
Set
validateCardHolderName
as theblur
event listener for the first INPUT element (card holder's name) in thedata-cc-info
DIV. -
Set
validateCardExpiryDate
as theblur
event listener for the second INPUT element (card expiry field) in thedata-cc-info
DIV. -
Set
validateCardNumber
as the click event listener for thedata-pay-btn
BUTTON -
Give
focus
to the first INPUT element in thedata-cc-digits
DIV.
Try filling in some details into the credit card UI and see if your validation code for the card holder's name and expiry date are working as stipulated. Does your
detectCardType
function also correctly set the right background color for the credit card component and display the right logo as well?
You will be implementing the The Luhn Algorithm to validate credit card numbers (16 digits. See here for more details, but follow the instructions below for simplicity.
- Given a series of up to 16 digits, from the right to left, double every other digit starting with the second to last digit:
1714
=> [1*, 7, 1*, 4]
=> [2, 7, 2, 4]
- If a resulting doubled number is greater than 9, replace it with either the sum of its own digits, or 9 subtracted from it.
[8, 18*, 1]
=> [8, (1+8), 1]
OR
=> [8, (18-9), 1]
Resulting in:
=> [8, 9, 1]
- Sum all of the final digits:
[8, 9, 1]
=> 8+9+1
=> 18
- Finally, take that sum and divide it by 10. If there is no remainder, the original credit card number is valid, else it is not valid.
Implementation
- Create a
validateWithLuhn
function above thevalidateCardNumber
function. It should take adigits
parameter which will represent the credit card numbers as an array of integers. It should return true or false depending on if the digits are valid or not.
Implement the validateCardNumber
function to validate the card numbers entered by the user. It delegates to the validateWithLuhn
function for the actual validation and returns the true or false value it gets from validateWithLuhn
. Before returning the outcome of the validation, it should also add or remove the is-invalid
class to the data-cc-digits
DIV depending on the validity of the card number.
Try filling in some details into the credit card UI then click the Pay & Checkout Now BUTTON to see if entered card numbers are correctly marked as invalid or not.