The repository consists of a project folder, a solution folder and others.

The project folder is where you will build the app.

The solution folder is an example solution you will get by following this codelab.

Navigate into the cloned repo and open the project folder.

$ cd pwa-ecommerce-demo/project

Then run npm install in the command line at the project directory.

$ npm install

This command should create node_modules directory and install all required node modules to your project. It takes a while.

Run npm run serve in the same directory to build and run the server in dist. Any changes you make to JavaScript files in this codelab will trigger rebuilding the app as long as you keep the command running.

$ npm run serve

Open your browser and navigate to http://localhost:8080 to see the initial state of the app working.

At this point, you should be able to see the e-commerce app running. Within this app, you can add items to the cart and proceed to the checkout form. Play with it for a while to understand how the original website works.

Note: The information you enter here won't be posted anywhere other than your local server, but you should use fake information. However, since credit card information requires validation, you can use following fake number so it can accept a random CVC: 4242 4242 4242 4242

From here, you will be implementing the Payment Request API.

The Payment Request API is not yet supported on desktop as of Chrome 58, so you will need an Android device with Chrome installed to test the code. Follow the instructions in the Access Local Servers article to set up port forwarding on your Android device. This lets you host the e-commerce app on your phone.

Create a PaymentRequest

Detect feature availability

First, let's add add a feature detection for the Payment Request API. And if it's available, let a user process payment with it.

Replace "TODO PAY-3.1" in app/scripts/modules/app.js with the following code and remove the dummy conditional of if (false) { to add PaymentRequest feature detection:

app.js

if (window.PaymentRequest) {

Explanation

The feature detection is as simple as examining if window.PaymentRequest returns undefined or not.

Create a PaymentRequest

Create a Payment Request object using the PaymentRequest constructor.

Replace "TODO PAY-3.2" in app/scripts/modules/payment-api.js with the following code and initialize PaymentRequest:

payment-api.js

Explanation

The constructor takes three parameters.

supportedInstruments: The first argument is a required set of data about supported payment methods. This can include basic credit cards as well as payment processors like Android Pay. We'll use only basic credit cards in this codelab.

details: The second argument is required information about the transaction. This must include the information to display the total to the user (i.e., a label, currency, and value amount), but it can also include a breakdown of items in the transaction.

paymentOptions: The third argument is an optional parameter for things like shipping. This allows you to require additional information from the user, like payer name, phone, email, and shipping information.

Try it out

You should now be able to try the Payment Request API. If you are not running your server, npm run serve and try it using your Android device.

$ npm run serve

The PaymentRequest UI displays when you click Checkout.

Beware, this is only the first step and there is more work to be done. Let's continue...

Add payment methods

At this point, most of the arguments are empty arrays or objects. Let's configure the payment method (supportedInstruments) with proper values.

Replace "TODO PAY-4" and its following JSON block in scripts/modules/payment-api.js with this:

payment-api.js

Explanation

The first argument of the PaymentRequest constructor takes a list of supported payment methods as JSON objects.

supportedMethods takes a list of supported method names as an array. Supported methods can be basic-card or a URL representing a payment app. These are defined in the Payment Method Identifiers specification.

payment-api.js

Explanation

A required total parameter consists of a label, currency and total amount to be charged.

An optional displayItems parameter indicates how the final amount was calculated.

The displayItems parameter is not intended to be a line-item list, but is rather a summary of the order's major components: subtotal, discounts, tax, shipping costs, etc. Let's define it in the next section.

Define the display items

The displayItems variable should be defined based on items added to the cart.

Replace "TODO PAY-5" in app/scripts/modules/payment-api.js with the following code and remove the existing let displayItems = [];:

payment-api.js

Explanation

The payment UI should look like this. Try expanding "Order summary":

Notice that the display items are present in the "Order summary" row. We gave each item a label and amount. label is a display label information of the item. amount is an object that constructs price information for the item.

Complete the PaymentRequest

You've put minimum required options to run a Payment Request. Let's allow a user to complete the payment.

Replace "TODO PAY-6" and the existing return request.show(); in app/scripts/modules/payment-api.js with the following code:

Explanation

The PaymentRequest interface is activated by calling its show() method. This method invokes a native UI that allows the user to examine the details of the purchase, add or change information, and pay. A Promise (indicated by its then() method and callback function) that resolves will be returned when the user accepts or rejects the payment request.

Calling toJSON() serializes the response object. You can then POST it to a server to process the payment. This portion differs depending on what payment processor / payment gateway you are using.

Once the server returns a response, call complete() to tell the user if processing the payment was successful or not by passing it success or fail.

Try out the app

Awesome! Now you have completed implementing the basic Payment Request API features in your app. If you are not running your server, npm run serve and try it using your Android device.

$ npm run serve

The PaymentRequest UI displays when you click Checkout.

Allow shipping options

So far you've learned how to integrate the Payment Request API when it doesn't involve shipping items. Moving forward you will learn how to collect shipping information and options from the user.

Define the shipping options

When you want to collect the user's address information in order to ship items, add requestShipping: true in the third property of the PaymentRequest constructor.

Replace "TODO PAY-7.1" in app/scripts/modules/payment-api.js with the following code:

payment-api.js

requestShipping: true,

You also need to provide list of shipping options.

Replace "TODO PAY-7.2" in app/scripts/modules/payment-api.js with the following code:

payment-api.js

,
shippingOptions: displayedShippingOptions

Luckily SHIPPING_OPTIONS is predefined in the app/scripts/modules/payment-api.js; you can parse it and construct the displayShippingOptions object from it.

Replace "TODO PAY-7.3" in app/scripts/modules/payment-api.js with the following code:

Explanation

id is a unique identifier of the shipping option item. label is a displayed label of the item. amount is an object that constructs price information for the item. selected is a boolean that indicates if the item is selected.

Notice that these changes add a section to the Payment Request UI, "Shipping". But beware, selecting shipping address will cause UI to freeze and timeout. To resolve this, you will need to handle shippingaddresschange event in the next section.

The address information available here is retrieved from the browser's autofill information. Depending on the user's browser status, users will get address information pre-filled without typing any text. They can also add a new entry on the fly.

Add event handlers

What if a user specifies a shipping address that's outside of your target countries and not deliverable? How do you charge a user when the user changes a shipping option? The answer is to receive events upon the user's making changes and update with relevant information.

Add shippingaddresschange event listener

When the user changes a shipping address, you will receive the shippingaddresschange event.

Replace "TODO PAY-8.1" in app/scripts/modules/payment-api.js with the following code:

Explanation

Upon receiving the shippingaddresschange event, the request object's shippingAddress information is updated. By examining it, you can determine if

The item is deliverable.

Shipping cost needs to be added/updated.

This code looks into the country of the shipping address and provides free shipping and express shipping inside the US, and provides international shipping otherwise. Checkout optionsForCountry() function in app/scripts/modules/payment-api.js to see how the evaluation is done.

Note that passing an empty array to shippingOptions indicates that shipping is not available for this address. You can display an error message via shippingOption.error in that case.

Add shippingoptionchange event listener

When the user changes a shipping option, you will receive the shippingoptionchange event.

Replace "TODO PAY-8.2" in app/scripts/modules/payment-api.js with the following code:

Explanation

Upon receiving the shippingoptionchange event, the request object's shippingOption is updated. It indicates the id of the shipping options. Look for the price of the shipping option and update the display items so that the user knows the total cost is changed. Also change the shipping option's selected to true to indicate that user has chosen the item. Checkout buildPaymentDetails() function in app/scripts/modules/payment-api.js to see how it works.

Add payment options

In addition to the shipping address, there are options to collect payer's information such as email address, phone number, and name.

Replace "TODO PAY-9" in app/scripts/modules/payment-api.js with the following payment options:

payment-api.js

Explanation

By adding requestPayerPhone: true, requestPayerEmail: true, requestPayerName: true to the third argument of the PaymentRequest constructor, you can request the payer's phone number, email address, and name.

Test it out

Phew! You have now completed implementing the Payment Request API with shipping option. Let's try it once again by running your server if it's stopped.

$ npm run serve

Try: add random items to the card, go to checkout, change shipping address and options, and finally make a payment.

Congratulations!

You have added Payment integration to the e-commerce app. Congratulations!