JSTize everything
authorNick Downing <nick@ndcode.org>
Sun, 19 Dec 2021 02:53:50 +0000 (13:53 +1100)
committerNick Downing <nick@ndcode.org>
Sun, 19 Dec 2021 02:53:50 +0000 (13:53 +1100)
13 files changed:
_library/basic_functions.jst [moved from _library/basic_functions.js with 88% similarity]
_library/random_number.js [deleted file]
_library/random_number.jst [new file with mode: 0644]
api/captureOrder.json.jst
api/createOrder.json.jst
api/getOrderDetails.json.jst
api/patchOrder.json.jst
index.html [deleted file]
index.html.jst [new file with mode: 0644]
pages/shipping.html [deleted file]
pages/shipping.html.jst [new file with mode: 0644]
pages/success.html [deleted file]
pages/success.html.jst [new file with mode: 0644]

similarity index 88%
rename from _library/basic_functions.js
rename to _library/basic_functions.jst
index b6ac0a9..fdb4ec8 100644 (file)
@@ -1,6 +1,5 @@
 const https = require('https');
-const config = require('../_config/config.json');
-const get_oauth = () => {
+const get_oauth = config => {
   return new Promise(resolve => {
       
       const data = 'grant_type=client_credentials';
@@ -35,16 +34,16 @@ const get_oauth = () => {
 
     });
 };
-const get_access_token = () => {
+const get_access_token = config => {
   return new Promise(resolve => {
-    get_oauth().then((response) => {
+    get_oauth(config).then((response) => {
       resolve(response.access_token);
     });
   });
 };
-const create_order = (item_obj) => {
+const create_order = (config, item_obj) => {
   return new Promise(resolve => {
-    get_access_token().then((access_token) => {
+    get_access_token(config).then((access_token) => {
   
     const options = {
       hostname: 'api.' + (config.environment === 'sandbox' ? 'sandbox.' : '') + 'paypal.com',
@@ -77,9 +76,9 @@ const create_order = (item_obj) => {
 
   });
 };
-const get_order_details = (order_id) => {
+const get_order_details = (config, order_id) => {
   return new Promise(resolve => {
-    get_access_token().then((access_token) => {
+    get_access_token(config).then((access_token) => {
   
     const options = {
       hostname: 'api.' + (config.environment === 'sandbox' ? 'sandbox.' : '') + 'paypal.com',
@@ -111,9 +110,9 @@ const get_order_details = (order_id) => {
 
   });
 };
-const patch_order_details = (new_order_details) => {
+const patch_order_details = (config, new_order_details) => {
   return new Promise((resolve, reject) => {
-    get_access_token().then((access_token) => {
+    get_access_token(config).then((access_token) => {
       patch_details = new_order_details.patch_details;
       order_id = new_order_details.order_id;
       const options = {
@@ -135,9 +134,9 @@ const patch_order_details = (new_order_details) => {
 });
 
 };
-const capture_order = (order_id) => {
+const capture_order = (config, order_id) => {
   return new Promise(resolve => {
-    get_access_token().then((access_token) => {
+    get_access_token(config).then((access_token) => {
     const options = {
       hostname: 'api.' + (config.environment === 'sandbox' ? 'sandbox.' : '') + 'paypal.com',
       port: 443,
@@ -166,7 +165,7 @@ const capture_order = (order_id) => {
   });
 };
 
-module.exports = {
+return {
   get_access_token: get_access_token,
   get_oauth: get_oauth,
   create_order: create_order,
diff --git a/_library/random_number.js b/_library/random_number.js
deleted file mode 100644 (file)
index a446935..0000000
+++ /dev/null
@@ -1 +0,0 @@
-module.exports = () => Math.floor(100000 + Math.random() * 900000)
diff --git a/_library/random_number.jst b/_library/random_number.jst
new file mode 100644 (file)
index 0000000..2152218
--- /dev/null
@@ -0,0 +1 @@
+return () => Math.floor(100000 + Math.random() * 900000)
index 3186882..4dd59eb 100644 (file)
@@ -1,9 +1,11 @@
-let basic_functions = require('../_library/basic_functions.js')
 let cookie = require('cookie')
 
 return async env => {
+  let basic_functions = await _require('/_library/basic_functions.jst')
+  let config = await env.site.get_json('/_config/config.json')
+
   let cookies = cookie.parse(env.request.headers.cookie || '')
-  let response = await basic_functions.capture_order(cookies.order_id)
+  let response = await basic_functions.capture_order(config, cookies.order_id)
   console.log('capture_order()', response)
 
   env.site.serve(
index 4cdb0fb..8c851c4 100644 (file)
@@ -1,11 +1,13 @@
-let basic_functions = require('../_library/basic_functions.js')
 let querystring = require('querystring')
-let random_number = require('../_library/random_number.js')
 let stream_buffers = require('stream-buffers')
 let XDate = require('xdate')
 
 return async env => {
-  let response = null;
+  let basic_functions = await _require('/_library/basic_functions.jst')
+  let config = await env.site.get_json('/_config/config.json')
+  let random_number = await _require('/_library/random_number.jst')
+
+  let response = null
   if (env.request.method === 'POST') {
     let write_stream = new stream_buffers.WritableStreamBuffer()
     let data = new Promise(
@@ -75,11 +77,11 @@ return async env => {
           }]
         }
       ]
-    };
+    }
     //If order details contain shipping, append shipping and preferences
     if (query.line1 !== undefined) {
-      item_obj.application_context.shipping_preference = "SET_PROVIDED_ADDRESS";
-      item_obj.application_context.user_action = "PAY_NOW";
+      item_obj.application_context.shipping_preference = "SET_PROVIDED_ADDRESS"
+      item_obj.application_context.user_action = "PAY_NOW"
       item_obj.purchase_units[0].shipping = {
         "address" : {
         "address_line_1": query.line1,
@@ -89,13 +91,13 @@ return async env => {
         "postal_code": query.zip,
         "country_code": query.countrySelect
         }
-      };
+      }
     }
     console.log('item_obj', item_obj)
-    response = await basic_functions.create_order(item_obj)
+    response = await basic_functions.create_order(config, item_obj)
     console.log('create_order()', response)
 
-    //sess.order_id = response.id;
+    //sess.order_id = response.id
     let expires = new XDate()
     expires.addDays(1)
     env.response.setHeader(
index b8cfaa9..4d8026d 100644 (file)
@@ -1,9 +1,12 @@
-let basic_functions = require('../_library/basic_functions.js')
 let cookie = require('cookie')
 
 return async env => {
+  let basic_functions = await _require('/_library/basic_functions.jst')
+  let config = await env.site.get_json('/_config/config.json')
+
   let cookies = cookie.parse(env.request.headers.cookie || '')
-  let response = await basic_functions.get_order_details(cookies.order_id)
+  let response =
+    await basic_functions.get_order_details(config, cookies.order_id)
   console.log('get_order_details()', response)
 
   env.site.serve(
index 0094534..41ae5df 100644 (file)
@@ -1,12 +1,14 @@
-let basic_functions = require('../_library/basic_functions.js')
 let cookie = require('cookie')
 let querystring = require('querystring')
-let random_number = require('../_library/random_number.js')
 let stream_buffers = require('stream-buffers')
 let XDate = require('xdate')
 
 return async env => {
-  let response = null;
+  let basic_functions = await _require('/_library/basic_functions.jst')
+  let config = await env.site.get_json('/_config/config.json')
+  let random_number = await _require('/_library/random_number.jst')
+
+  let response = null
   if (env.request.method === 'POST') {
     let write_stream = new stream_buffers.WritableStreamBuffer()
     let data = new Promise(
@@ -57,9 +59,10 @@ return async env => {
         }       
       }],
       "order_id": cookies.order_id
-    };
+    }
     response = {
-      http_code: await basic_functions.patch_order_details(new_order_details)
+      http_code:
+        await basic_functions.patch_order_details(config, new_order_details)
     }
     console.log('patch_order_details()', response)
   }
diff --git a/index.html b/index.html
deleted file mode 100644 (file)
index d8e5cce..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-<!DOCTYPE html>\r
-<html lang="en">\r
-\r
-<head>\r
-       <meta charset="utf-8" />\r
-       <meta http-equiv="x-ua-compatible" content="ie=edge" />\r
-       <meta name="viewport" content="width=device-width, initial-scale=1" />\r
-       <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">\r
-       <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script>\r
-       <title>Checkout With PayPal NodeJs Demo</title>\r
-       <style>\r
-       /* http://angrytools.com/gradient/ */\r
-       \r
-       .header-bg-color {\r
-               color: white;\r
-               background: -moz-linear-gradient(0deg, #004094 0%, #0096D9 50%, #004094 100%);\r
-               /* ff3.6+ */\r
-               background: -webkit-gradient(linear, left top, right top, color-stop(0%, #004094), color-stop(50%, #0096D9), color-stop(100%, #004094));\r
-               /* safari4+,chrome */\r
-               background: -webkit-linear-gradient(0deg, #004094 0%, #0096D9 50%, #004094 100%);\r
-               /* safari5.1+,chrome10+ */\r
-               background: -o-linear-gradient(0deg, #004094 0%, #0096D9 50%, #004094 100%);\r
-               /* opera 11.10+ */\r
-               background: -ms-linear-gradient(0deg, #004094 0%, #0096D9 50%, #004094 100%);\r
-               /* ie10+ */\r
-               background: linear-gradient(90deg, #004094 0%, #0096D9 50%, #004094 100%);\r
-               /* w3c */\r
-               filter: progid: DXImageTransform.Microsoft.gradient( startColorstr='#004094', endColorstr='#004094', GradientType=1);\r
-               /* ie6-9 */\r
-       }\r
-       </style>\r
-</head>\r
-\r
-<body>\r
-       <div class="container">\r
-               <div class="row header-bg-color mb-5 p-3">\r
-                       <h2 class="text-center">Checkout with PayPal Demo</h2>\r
-                       <h4 class="text-center">Using Orders v2 REST API with PayPal JavaScript SDK</h4>\r
-                       <h5 class="text-center">Server-side Integration</h5> </div>\r
-               <div class="row">\r
-                       <div class="col-sm">\r
-                               <div class="card"> <img class="card-img-top img-responsive" src="https://www.paypalobjects.com/web/res/b0b/e9fea36098a7a8192723a8d3b86b2/img/platform/common/merchantStore/cart/camera-lg.jpg">\r
-                                       <div class="card-body">\r
-                                               <h4 class="text-center">Sample Sandbox Buyer Credentials</h4>\r
-                                               <table class="table table-striped">\r
-                                                       <thead>\r
-                                                               <tr>\r
-                                                                       <th scope="col">Buyer Email</th>\r
-                                                                       <th scope="col">Password</th>\r
-                                                               </tr>\r
-                                                       </thead>\r
-                                                       <tbody>\r
-                                                               <tr>\r
-                                                                       <td>emily_doe@buyer.com</td>\r
-                                                                       <td>qwer1234</td>\r
-                                                               </tr>\r
-                                                               <tr>\r
-                                                                       <td>bill_bong@buyer.com</td>\r
-                                                                       <td>qwer1234</td>\r
-                                                               </tr>\r
-                                                               <tr>\r
-                                                                       <td>jack_potter@buyer.com</td>\r
-                                                                       <td>123456789</td>\r
-                                                               </tr>\r
-                                                               <tr>\r
-                                                                       <td>harry_doe@buyer.com</td>\r
-                                                                       <td>123456789</td>\r
-                                                               </tr>\r
-                                                               <tr>\r
-                                                                       <td>ron_brown@buyer.com</td>\r
-                                                                       <td>qwer1234</td>\r
-                                                               </tr>\r
-                                                               <tr>\r
-                                                                       <td>bella_brown@buyer.com</td>\r
-                                                                       <td>qwer1234</td>\r
-                                                               </tr>\r
-                                                       </tbody>\r
-                                               </table>\r
-                                       </div>\r
-                               </div>\r
-                       </div>\r
-                       <div class="col-sm">\r
-                               <h3 class="text-center">Pricing Details</h3>\r
-                               <hr>\r
-                               <form id="camera_form">\r
-                                       <!-- Cart Details -->\r
-                                       <input name="return_url" type="hidden" value="http://localhost/pages/success.html">\r
-                                       <input name="cancel_url" type="hidden" value="http://localhost/pages/success.html">\r
-                                       <div class="form-group">\r
-                                               <label for="camera_amount" class="col-sm-5 control-label">Camera</label>\r
-                                               <div class="col-sm">\r
-                                                       <input class="form-control" type="text" id="camera_amount" name="item_amt" value="300" readonly=""> </div>\r
-                                       </div>\r
-                                       <div class="form-group">\r
-                                               <label for="tax_amt" class="col-sm-5 control-label">Tax</label>\r
-                                               <div class="col-sm">\r
-                                                       <input class="form-control" type="text" id="tax_amt" name="tax_amt" value="5" readonly=""> </div>\r
-                                       </div>\r
-                                       <div class="form-group">\r
-                                               <label for="insurance_fee" class="col-sm-5 control-label">Insurance</label>\r
-                                               <div class="col-sm">\r
-                                                       <input class="form-control" type="text" id="insurance_fee" name="insurance_fee" value="10" readonly=""> </div>\r
-                                       </div>\r
-                                       <div class="form-group">\r
-                                               <label for="handling_fee" class="col-sm-5 control-label">Handling Fee</label>\r
-                                               <div class="col-sm">\r
-                                                       <input class="form-control" type="text" id="handling_fee" name="handling_fee" value="5" readonly=""> </div>\r
-                                       </div>\r
-                                       <div class="form-group">\r
-                                               <label for="shipping_amt" class="col-sm-5 control-label">Estimated Shipping</label>\r
-                                               <div class="col-sm">\r
-                                                       <input class="form-control" type="text" id="shipping_amt" name="shipping_amt" value="2" readonly=""> </div>\r
-                                       </div>\r
-                                       <div class="form-group">\r
-                                               <label for="shipping_discount" class="col-sm-5 control-label">Shipping Discount</label>\r
-                                               <div class="col-sm">\r
-                                                       <input class="form-control" type="text" id="shipping_discount" name="shipping_discount" value="2" readonly=""> </div>\r
-                                       </div>\r
-                                       <div class="form-group">\r
-                                               <label for="total_amt" class="col-sm-5 control-label">Total Amount</label>\r
-                                               <div class="col-sm">\r
-                                                       <input class="form-control" type="text" id="total_amt" name="total_amt" value="320" readonly=""> </div>\r
-                                       </div>\r
-                                       <div class="form-group">\r
-                                               <label for="currency_Code" class="col-sm-5 control-label">Currency</label>\r
-                                               <div class="col-sm">\r
-                                                       <input class="form-control" type="text" id="currency_Code" name="currency" value="USD" readonly=""> </div>\r
-                                       </div>\r
-                                       <hr>\r
-                                       <!-- Checkout Options -->\r
-                                       <div class="form-group">\r
-                                               <div class="col-sm-offset-5 col-sm">\r
-                                                       <!-- Container for PayPal Shortcut Checkout -->\r
-                                                       <div id="paypalCheckoutContainer"></div>\r
-                                                       <!-- Container for PayPal Mark Redirect -->\r
-                                                       <div id="paypalMarkRedirect">\r
-                                                               <h4 class="text-center">OR</h4>\r
-                                                               <a class="w-100 btn btn-success btn-block" href="pages/shipping.html" role="button">\r
-                                                                       <h4>Proceed to Checkout</h4> </a>\r
-                                                       </div>\r
-                                               </div>\r
-                                       </div>\r
-                               </form>\r
-                       </div>\r
-                       <div class="col-sm-4">\r
-                               <hr class="m-5">\r
-                               <h3 class="text-center">Readme</h3>\r
-                               <ol>\r
-                                       <li> Enter REST API credentials in common/config/config.json. You can get your own REST app credentials by creating a REST app with the steps outlined <i>\r
-                        <a href="https://developer.paypal.com/docs/api-basics/manage-apps/#create-or-edit-sandbox-and-live-apps" target="_blank">here</a>\r
-                    </i>. </li>\r
-                                       <li> Click on 'PayPal Checkout’ button and see the experience. </li>\r
-                                       <li> Checkout with PayPal using a buyer sandbox account provided on this page. And you're done! </li>\r
-                                       <li>In the guest checkout experience, the buyer country can be switched. When switched to one of Germany, Poland, Austria, Netherlands, Italy and Spain, you will be able to choose the alternative payment methods offered in those countries. </li>\r
-                                       <li>For example: Selecting 'Germany' in the country drop down will pre-fill the shipping address on the Shipping Information page. For all other countries not mentioned in step 5, the address has to be manually entered. </li>\r
-                               </ol>\r
-                               <hr>\r
-                               <h3 class="text-center">In-Context Checkout integration steps with PayPal JavaScript SDK</h3>\r
-                               <ol>\r
-                                       <li> Copy the files and folders in the package to the same location where you have your shopping cart page. </li>\r
-                                       <li> In order to view Alternative Payment Methods as part of the guest checkout flow, you must add query parameters intent=capture, commit=true, vault=false and buyer-country= and you must provide a supported buyer country </li>\r
-                                       <li> Include the following script on your shopping cart page: (For APMs, the layout must be <code>vertical</code> and setting up the payment in the alternative payment method <a href="https://developer.paypal.com/docs/checkout/integration-features/alternative-payment-methods/#availability" target="_blank">supported currency</a> is required for the alternative payment method to render.) <pre><code>\r
-        paypal.Buttons({\r
-        env: 'sandbox', // sandbox | production\r
-    \r
-            // Set style of buttons\r
-            style: {\r
-                layout: 'vertical',   // horizontal | vertical &lt;-Must be vertical for APMs\r
-                size:   'responsive',   // medium | large | responsive\r
-                shape:  'pill',         // pill | rect\r
-                color:  'gold',         // gold | blue | silver | black,\r
-                fundingicons: false,    // true | false,\r
-                tagline: false          // true | false,\r
-            },\r
-    \r
-        // payment() is called when the button is clicked\r
-        createOrder: function() {\r
-    \r
-            return fetch('/my-server/create-paypal-transaction')\r
-                .then(function(res) {\r
-                    return res.json();\r
-                }).then(function(data) {\r
-                    return data.orderID;\r
-                });\r
-        },\r
-    \r
-        // onAuthorize() is called when the buyer approves the payment\r
-        onApprove: function(data, actions) {\r
-    \r
-            return fetch('/my-server/capture-paypal-transaction', {\r
-                    body: JSON.stringify({\r
-                    orderID: data.orderID\r
-                    })\r
-                }).then(function(res) {\r
-                    return res.json();\r
-                }).then(function(details) {\r
-                    alert('Transaction funds captured from ' + details.payer_given_name);\r
-                });\r
-        }\r
-    }).render('#paypal-button-container');</code>\r
-                </pre> </li>\r
-                                       <li> Open your browser and navigate to your Shopping cart page. Click on 'Checkout with PayPal' button and complete the flow. </li>\r
-                                       <li> You can use the sample Buyer Sandbox credentials provided on index/home page. </li>\r
-                                       <li>Refer to <a href="https://developer.paypal.com/docs/checkout/" target="_blank">PayPal Developer</a> site for detailed guidelines.</li>\r
-                                       <li>Click <a href="https://developer.paypal.com/docs/api/orders/v2/" target="_blank">here</a> for the API reference. </li>\r
-                               </ol>\r
-                       </div>\r
-               </div>\r
-       </div>\r
-       <!-- Javascript Import -->\r
-       <script src="../js/config.js"></script>\r
-       <!-- PayPal In-Context Checkout script -->\r
-       <script type="text/javascript">\r
-       init_smart_buttons = () => {\r
-               paypal.Buttons({\r
-                       // Set your environment\r
-                       env: 'sandbox',\r
-                       // Set style of buttons\r
-                       style: {\r
-                               layout: 'vertical', // horizontal | vertical\r
-                               size: 'responsive', // medium | large | responsive\r
-                               shape: 'pill', // pill | rect\r
-                               color: 'gold', // gold | blue | silver | black,\r
-                               fundingicons: false, // true | false,\r
-                               tagline: false // true | false,\r
-                       },\r
-                       // Wait for the PayPal button to be clicked\r
-                       createOrder: function() {\r
-                               return new Promise((resolve, reject) => {\r
-                                       $.ajax({\r
-                                               type: 'POST',\r
-                                               url: 'api/createOrder.json',\r
-                                               data: serialize(document.getElementById("camera_form")),\r
-                                               success: function(response) {\r
-                                                       return(response)\r
-                                               },\r
-                                               error: function(error) {\r
-                                                       reject(error)\r
-                                               },\r
-                                       }).then(function(response) {\r
-                                               console.log('Order ID: ' + response.id);\r
-                                               resolve(response.id);\r
-                                       });\r
-                               })\r
-                       },\r
-                       // Wait for the payment to be authorized by the customer\r
-                       onApprove: function(data, actions) {\r
-                               return fetch('api/getOrderDetails.json', {\r
-                                       method: 'GET'\r
-                               }).then(function(res) {\r
-                                       return res.json();\r
-                               }).then(function(res) {\r
-                                       window.location.href = 'pages/success.html';\r
-                               });\r
-                       }\r
-               }).render('#paypalCheckoutContainer');\r
-       }\r
-       </script>\r
-       <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->\r
-       <script src="https://code.jquery.com/jquery.js"></script>\r
-</body>\r
-\r
-</html>\r
diff --git a/index.html.jst b/index.html.jst
new file mode 100644 (file)
index 0000000..ab4e035
--- /dev/null
@@ -0,0 +1,339 @@
+return async env => {
+  _out = []
+  _out.push('<!DOCTYPE html>')
+  html(lang="en") {
+    head {
+      meta(charset="utf-8") {}
+      meta(http-equiv="x-ua-compatible" content="ie=edge") {}
+      meta(name="viewport" content="width=device-width,initial-scale=1") {}
+      link(href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous") {}
+      script(src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous") {}
+      title {
+        'Checkout With PayPal NodeJs Demo'
+      }
+      style {
+        .header-bg-color {
+          color: #fff;
+          background: -moz-linear-gradient(0deg,#004094 0,#0096d9 50%,#004094 100%);
+          background: -webkit-gradient(linear,left top,right top,color-stop(0,#004094),color-stop(50%,#0096d9),color-stop(100%,#004094));
+          background: -webkit-linear-gradient(0deg,#004094 0,#0096d9 50%,#004094 100%);
+          background: -o-linear-gradient(0deg,#004094 0,#0096d9 50%,#004094 100%);
+          background: -ms-linear-gradient(0deg,#004094 0,#0096d9 50%,#004094 100%);
+          background: linear-gradient(90deg,#004094 0,#0096d9 50%,#004094 100%)
+        }
+      }
+    }
+    body {
+      div.container {
+        div.row.header-bg-color.'mb-5'.p-3 {
+          h2.text-center {
+            'Checkout with PayPal Demo'
+          }
+          h4.text-center {
+            'Using Orders v2 REST API with PayPal JavaScript SDK'
+          }
+          h5.text-center {
+            'Server-side Integration'
+          }
+        }
+        div.row {
+          div.col-sm {
+            div.card {
+              img.card-img-top.img-responsive(src="https://www.paypalobjects.com/web/res/b0b/e9fea36098a7a8192723a8d3b86b2/img/platform/common/merchantStore/cart/camera-lg.jpg") {}
+              div.card-body {
+                h4.text-center {
+                  'Sample Sandbox Buyer Credentials'
+                }
+                table.table.table-striped {
+                  thead {
+                    tr {
+                      th(scope="col") {
+                        'Buyer Email'
+                      }
+                      th(scope="col") {
+                        'Password'
+                      }
+                    }
+                  }
+                  tbody {
+                    tr {
+                      td {
+                        'emily_doe@buyer.com'
+                      }
+                      td {
+                        'qwer1234'
+                      }
+                    }
+                    tr {
+                      td {
+                        'bill_bong@buyer.com'
+                      }
+                      td {
+                        'qwer1234'
+                      }
+                    }
+                    tr {
+                      td {
+                        'jack_potter@buyer.com'
+                      }
+                      td {
+                        '123456789'
+                      }
+                    }
+                    tr {
+                      td {
+                        'harry_doe@buyer.com'
+                      }
+                      td {
+                        '123456789'
+                      }
+                    }
+                    tr {
+                      td {
+                        'ron_brown@buyer.com'
+                      }
+                      td {
+                        'qwer1234'
+                      }
+                    }
+                    tr {
+                      td {
+                        'bella_brown@buyer.com'
+                      }
+                      td {
+                        'qwer1234'
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+          div.col-sm {
+            h3.text-center {
+              'Pricing Details'
+            }
+            hr {}
+            form#camera_form {
+              _out.push('<!-- Cart Details -->')
+              ' '
+              input(name="return_url" type="hidden" value="http://localhost/pages/success.html") {}
+              ' '
+              input(name="cancel_url" type="hidden" value="http://localhost/pages/success.html") {}
+              div.form-group {
+                label.'col-sm-5'.control-label(for="camera_amount") {
+                  'Camera'
+                }
+                div.col-sm {
+                  input.form-control#camera_amount(type="text" name="item_amt" value="300" readonly="") {}
+                }
+              }
+              div.form-group {
+                label.'col-sm-5'.control-label(for="tax_amt") {
+                  'Tax'
+                }
+                div.col-sm {
+                  input.form-control#tax_amt(type="text" name="tax_amt" value="5" readonly="") {}
+                }
+              }
+              div.form-group {
+                label.'col-sm-5'.control-label(for="insurance_fee") {
+                  'Insurance'
+                }
+                div.col-sm {
+                  input.form-control#insurance_fee(type="text" name="insurance_fee" value="10" readonly="") {}
+                }
+              }
+              div.form-group {
+                label.'col-sm-5'.control-label(for="handling_fee") {
+                  'Handling Fee'
+                }
+                div.col-sm {
+                  input.form-control#handling_fee(type="text" name="handling_fee" value="5" readonly="") {}
+                }
+              }
+              div.form-group {
+                label.'col-sm-5'.control-label(for="shipping_amt") {
+                  'Estimated Shipping'
+                }
+                div.col-sm {
+                  input.form-control#shipping_amt(type="text" name="shipping_amt" value="2" readonly="") {}
+                }
+              }
+              div.form-group {
+                label.'col-sm-5'.control-label(for="shipping_discount") {
+                  'Shipping Discount'
+                }
+                div.col-sm {
+                  input.form-control#shipping_discount(type="text" name="shipping_discount" value="2" readonly="") {}
+                }
+              }
+              div.form-group {
+                label.'col-sm-5'.control-label(for="total_amt") {
+                  'Total Amount'
+                }
+                div.col-sm {
+                  input.form-control#total_amt(type="text" name="total_amt" value="320" readonly="") {}
+                }
+              }
+              div.form-group {
+                label.'col-sm-5'.control-label(for="currency_Code") {
+                  'Currency'
+                }
+                div.col-sm {
+                  input.form-control#currency_Code(type="text" name="currency" value="USD" readonly="") {}
+                }
+              }
+              hr {}
+              _out.push('<!-- Checkout Options -->')
+              div.form-group {
+                div.'col-sm-offset-5'.col-sm {
+                  _out.push('<!-- Container for PayPal Shortcut Checkout -->')
+                  div#paypalCheckoutContainer {}
+                  _out.push('<!-- Container for PayPal Mark Redirect -->')
+                  div#paypalMarkRedirect {
+                    h4.text-center {
+                      'OR'
+                    }
+                    a.'w-100'.btn.btn-success.btn-block(href="pages/shipping.html" role="button") {
+                      h4 {
+                        'Proceed to Checkout'
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+          div.col-sm-4 {
+            hr.m-5 {}
+            h3.text-center {
+              'Readme'
+            }
+            ol {
+              li {
+                'Enter REST API credentials in common/config/config.json. You can get your own REST app credentials by creating a REST app with the steps outlined '
+                i {
+                  a(href="https://developer.paypal.com/docs/api-basics/manage-apps/#create-or-edit-sandbox-and-live-apps" target="_blank") {
+                    'here'
+                  }
+                  ' '
+                }
+                '.'
+              }
+              li {
+                'Click on \'PayPal Checkout’ button and see the experience.'
+              }
+              li {
+                'Checkout with PayPal using a buyer sandbox account provided on this page. And you\'re done!'
+              }
+              li {
+                'In the guest checkout experience, the buyer country can be switched. When switched to one of Germany, Poland, Austria, Netherlands, Italy and Spain, you will be able to choose the alternative payment methods offered in those countries.'
+              }
+              li {
+                'For example: Selecting \'Germany\' in the country drop down will pre-fill the shipping address on the Shipping Information page. For all other countries not mentioned in step 5, the address has to be manually entered.'
+              }
+            }
+            hr {}
+            h3.text-center {
+              'In-Context Checkout integration steps with PayPal JavaScript SDK'
+            }
+            ol {
+              li {
+                'Copy the files and folders in the package to the same location where you have your shopping cart page.'
+              }
+              li {
+                'In order to view Alternative Payment Methods as part of the guest checkout flow, you must add query parameters intent=capture, commit=true, vault=false and buyer-country= and you must provide a supported buyer country'
+              }
+              li {
+                'Include the following script on your shopping cart page: (For APMs, the layout must be '
+                code {
+                  'vertical'
+                }
+                ' and setting up the payment in the alternative payment method '
+                a(href="https://developer.paypal.com/docs/checkout/integration-features/alternative-payment-methods/#availability" target="_blank") {
+                  'supported currency'
+                }
+                ' is required for the alternative payment method to render.)'
+                pre {
+                  code {
+                    '\r\n        paypal.Buttons({\r\n        env: \'sandbox\', // sandbox | production\r\n    \r\n            // Set style of buttons\r\n            style: {\r\n                layout: \'vertical\',   // horizontal | vertical <-Must be vertical for APMs\r\n                size:   \'responsive\',   // medium | large | responsive\r\n                shape:  \'pill\',         // pill | rect\r\n                color:  \'gold\',         // gold | blue | silver | black,\r\n                fundingicons: false,    // true | false,\r\n                tagline: false          // true | false,\r\n            },\r\n    \r\n        // payment() is called when the button is clicked\r\n        createOrder: function() {\r\n    \r\n            return fetch(\'/my-server/create-paypal-transaction\')\r\n                .then(function(res) {\r\n                    return res.json();\r\n                }).then(function(data) {\r\n                    return data.orderID;\r\n                });\r\n        },\r\n    \r\n        // onAuthorize() is called when the buyer approves the payment\r\n        onApprove: function(data, actions) {\r\n    \r\n            return fetch(\'/my-server/capture-paypal-transaction\', {\r\n                    body: JSON.stringify({\r\n                    orderID: data.orderID\r\n                    })\r\n                }).then(function(res) {\r\n                    return res.json();\r\n                }).then(function(details) {\r\n                    alert(\'Transaction funds captured from \' + details.payer_given_name);\r\n                });\r\n        }\r\n    }).render(\'#paypal-button-container\');'
+                  }
+                  '\r\n                '
+                }
+              }
+              li {
+                'Open your browser and navigate to your Shopping cart page. Click on \'Checkout with PayPal\' button and complete the flow.'
+              }
+              li {
+                'You can use the sample Buyer Sandbox credentials provided on index/home page.'
+              }
+              li {
+                'Refer to '
+                a(href="https://developer.paypal.com/docs/checkout/" target="_blank") {
+                  'PayPal Developer'
+                }
+                ' site for detailed guidelines.'
+              }
+              li {
+                'Click '
+                a(href="https://developer.paypal.com/docs/api/orders/v2/" target="_blank") {
+                  'here'
+                }
+                ' for the API reference.'
+              }
+            }
+          }
+        }
+      }
+      _out.push('<!-- Javascript Import -->')
+      script(src="../js/config.js") {}
+      _out.push('<!-- PayPal In-Context Checkout script -->')
+      script(type="text/javascript") {
+        init_smart_buttons = (() => {
+          paypal.Buttons({
+            env: "sandbox",
+            style: {
+              layout: "vertical",
+              size: "responsive",
+              shape: "pill",
+              color: "gold",
+              fundingicons: false,
+              tagline: false
+            },
+            createOrder: function() {
+              return new Promise((resolve, reject) => {
+                $.ajax({
+                  type: "POST",
+                  url: "api/createOrder.json",
+                  data: serialize(document.getElementById("camera_form")),
+                  success: function(response) {
+                    return response;
+                  },
+                  error: function(error) {
+                    reject(error);
+                  }
+                }).then(function(response) {
+                  console.log("Order ID: " + response.id);
+                  resolve(response.id);
+                });
+              });
+            },
+            onApprove: function(data, actions) {
+              return fetch("api/getOrderDetails.json", {
+                method: "GET"
+              }).then(function(res) {
+                return res.json();
+              }).then(function(res) {
+                window.location.href = "pages/success.html";
+              });
+            }
+          }).render("#paypalCheckoutContainer");
+        });
+      }
+      _out.push('<!-- jQuery (necessary for Bootstrap\'s JavaScript plugins) -->')
+      script(src="https://code.jquery.com/jquery.js") {}
+    }
+  }
+  env.site.serve(env, 200, Buffer.from(_out.join('')), 'index.html.jst')
+}
diff --git a/pages/shipping.html b/pages/shipping.html
deleted file mode 100644 (file)
index f47efb1..0000000
+++ /dev/null
@@ -1,435 +0,0 @@
-<!DOCTYPE html>\r
-<html lang="en">\r
-\r
-<head>\r
-       <meta charset="utf-8" />\r
-       <meta http-equiv="x-ua-compatible" content="ie=edge" />\r
-       <meta name="viewport" content="width=device-width, initial-scale=1" />\r
-       <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">\r
-       <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script>\r
-       <title>Checkout With PayPal NodeJs Demo</title>\r
-       <style>\r
-       /* http://angrytools.com/gradient/ */\r
-       \r
-       .header-bg-color {\r
-               color: white;\r
-               background: -moz-linear-gradient(0deg, #004094 0%, #0096D9 50%, #004094 100%);\r
-               /* ff3.6+ */\r
-               background: -webkit-gradient(linear, left top, right top, color-stop(0%, #004094), color-stop(50%, #0096D9), color-stop(100%, #004094));\r
-               /* safari4+,chrome */\r
-               background: -webkit-linear-gradient(0deg, #004094 0%, #0096D9 50%, #004094 100%);\r
-               /* safari5.1+,chrome10+ */\r
-               background: -o-linear-gradient(0deg, #004094 0%, #0096D9 50%, #004094 100%);\r
-               /* opera 11.10+ */\r
-               background: -ms-linear-gradient(0deg, #004094 0%, #0096D9 50%, #004094 100%);\r
-               /* ie10+ */\r
-               background: linear-gradient(90deg, #004094 0%, #0096D9 50%, #004094 100%);\r
-               /* w3c */\r
-               filter: progid: DXImageTransform.Microsoft.gradient( startColorstr='#004094', endColorstr='#004094', GradientType=1);\r
-               /* ie6-9 */\r
-       }\r
-       </style>\r
-</head>\r
-\r
-<body>\r
-       <div class="container">\r
-               <div class="row header-bg-color mb-5 p-3">\r
-                       <h2 class="text-center">Checkout with PayPal Demo</h2>\r
-                       <h4 class="text-center">Using Orders v2 REST API with PayPal JavaScript SDK</h4>\r
-                       <h5 class="text-center">Server-side Integration</h5> </div>\r
-               <div class="row">\r
-                       <div class="col-lg-3"></div>\r
-                       <div class="col-lg-6">\r
-                               <h3 class="text-center">Shipping Information</h3>\r
-                               <hr>\r
-                               <form id="camera_form">\r
-                                       <input name="return_url" type="hidden" value="http://localhost/pages/success.html">\r
-                                       <input name="cancel_url" type="hidden" value="http://localhost/pages/success.html">\r
-                                       <input id="item_amt" name="item_amt" type="hidden" value="300">\r
-                                       <input id="insurance_fee" name="insurance_fee" type="hidden" value="10">\r
-                                       <input id="handling_fee" name="handling_fee" type="hidden" value="5">\r
-                                       <input id="tax_amt" name="tax_amt" type="hidden" value="5">\r
-                                       <input id="shipping_discount" name="shipping_discount" type="hidden" value="2">\r
-                                       <input id="currency" name="currency" type="hidden" value="USD">\r
-                                       <input id="total_amt" name="total_amt" type="hidden" value="300">\r
-                                       <!-- Shipping Information -->\r
-                                       <div class="form-group row mb-2">\r
-                                                       <label for="recipient_name" class="col-sm-4 col-form-label">Recipient Name</label>\r
-                                                       <div class="col-sm-8">\r
-                                                       <input type="text" name="recipient_name" id="recipient_name" class="form-control" aria-describedby="passwordHelpInline" value="Jane Doe"> \r
-                                               </div>\r
-                                       </div>\r
-                                       <div class="form-group row mb-2">\r
-                                                       <label for="line1" class="col-sm-4 col-form-label">Address Line 1</label>\r
-                                                       <div class="col-sm-8">\r
-                                                               <input type="text" name="line1" id="line1" class="form-control" aria-describedby="passwordHelpInline" value="2211 North Street"> </div>\r
-                                       </div>\r
-                                       <div class="form-group row mb-2">\r
-                                                       <label for="line2" class="col-sm-4 col-form-label">Address Line 2</label>\r
-                                                       <div class="col-sm-8">\r
-                                                               <input type="text" name="line2" id="line2" class="form-control" aria-describedby="passwordHelpInline" value=""> </div>\r
-                                       </div>\r
-                                       <div class="form-group row mb-2">\r
-                                                       <label for="city" class="col-sm-4 col-form-label">City</label>\r
-                                                       <div class="col-sm-8">\r
-                                                               <input type="text" name="city" id="city" class="form-control" aria-describedby="passwordHelpInline" value="San Jose"> </div>\r
-                                       </div>\r
-                                       <div class="form-group row mb-2">\r
-                                                       <label for="state" class="col-sm-4 col-form-label">State</label>\r
-                                                       <div class="col-sm-8">\r
-                                                               <input type="text" name="state" id="state" class="form-control" aria-describedby="passwordHelpInline" value="CA"> </div>\r
-                                       </div>\r
-                                       <div class="form-group row mb-2">\r
-                                                       <label for="zip" class="col-sm-4 col-form-label">Postal Code</label>\r
-                                               <div class="col-sm-8">\r
-                                                       <input type="text" name="zip" id="zip" class="form-control" aria-describedby="passwordHelpInline" value="95123"> </div>\r
-                                       </div>\r
-                                       <div class="form-group row mb-2">\r
-                                                       <label for="countrySelect" class="col-sm-4 col-form-label">Country</label>\r
-                                               <div class="col-sm-8">\r
-                                                       <select class="form-select mb-2" name="countrySelect" id="countrySelect" aria-label="Country">\r
-                                                       <option value="AF">Afghanistan</option>\r
-                                                       <option value="AX">Aland Islands</option>\r
-                                                       <option value="AL">Albania</option>\r
-                                                       <option value="DZ">Algeria</option>\r
-                                                       <option value="AS">American Samoa</option>\r
-                                                       <option value="AD">Andorra</option>\r
-                                                       <option value="AO">Angola</option>\r
-                                                       <option value="AI">Anguilla</option>\r
-                                                       <option value="AQ">Antarctica</option>\r
-                                                       <option value="AG">Antigua and Barbuda</option>\r
-                                                       <option value="AR">Argentina</option>\r
-                                                       <option value="AM">Armenia</option>\r
-                                                       <option value="AW">Aruba</option>\r
-                                                       <option value="AU">Australia</option>\r
-                                                       <option value="AT">Austria</option>\r
-                                                       <option value="AZ">Azerbaijan</option>\r
-                                                       <option value="BS">Bahamas</option>\r
-                                                       <option value="BH">Bahrain</option>\r
-                                                       <option value="BD">Bangladesh</option>\r
-                                                       <option value="BB">Barbados</option>\r
-                                                       <option value="BY">Belarus</option>\r
-                                                       <option value="BE">Belgium</option>\r
-                                                       <option value="BZ">Belize</option>\r
-                                                       <option value="BJ">Benin</option>\r
-                                                       <option value="BM">Bermuda</option>\r
-                                                       <option value="BT">Bhutan</option>\r
-                                                       <option value="BO">Bolivia</option>\r
-                                                       <option value="BA">Bosnia and Herzegovina</option>\r
-                                                       <option value="BW">Botswana</option>\r
-                                                       <option value="BV">Bouvet Island</option>\r
-                                                       <option value="BR">Brazil</option>\r
-                                                       <option value="IO">British Indian Ocean Territory</option>\r
-                                                       <option value="BN">Brunei Darussalam</option>\r
-                                                       <option value="BG">Bulgaria</option>\r
-                                                       <option value="BF">Burkina Faso</option>\r
-                                                       <option value="BI">Burundi</option>\r
-                                                       <option value="KH">Cambodia</option>\r
-                                                       <option value="CM">Cameroon</option>\r
-                                                       <option value="CA">Canada</option>\r
-                                                       <option value="CV">Cape Verde</option>\r
-                                                       <option value="KY">Cayman Islands</option>\r
-                                                       <option value="CF">Central African Republic</option>\r
-                                                       <option value="TD">Chad</option>\r
-                                                       <option value="CL">Chile</option>\r
-                                                       <option value="CN">China</option>\r
-                                                       <option value="CX">Christmas Island</option>\r
-                                                       <option value="CC">Cocos (Keeling) Islands</option>\r
-                                                       <option value="CO">Colombia</option>\r
-                                                       <option value="KM">Comoros</option>\r
-                                                       <option value="CG">Congo</option>\r
-                                                       <option value="CD">Congo, The Democratic Republic of The</option>\r
-                                                       <option value="CK">Cook Islands</option>\r
-                                                       <option value="CR">Costa Rica</option>\r
-                                                       <option value="CI">Cote D'ivoire</option>\r
-                                                       <option value="HR">Croatia</option>\r
-                                                       <option value="CU">Cuba</option>\r
-                                                       <option value="CY">Cyprus</option>\r
-                                                       <option value="CZ">Czech Republic</option>\r
-                                                       <option value="DK">Denmark</option>\r
-                                                       <option value="DJ">Djibouti</option>\r
-                                                       <option value="DM">Dominica</option>\r
-                                                       <option value="DO">Dominican Republic</option>\r
-                                                       <option value="EC">Ecuador</option>\r
-                                                       <option value="EG">Egypt</option>\r
-                                                       <option value="SV">El Salvador</option>\r
-                                                       <option value="GQ">Equatorial Guinea</option>\r
-                                                       <option value="ER">Eritrea</option>\r
-                                                       <option value="EE">Estonia</option>\r
-                                                       <option value="ET">Ethiopia</option>\r
-                                                       <option value="FK">Falkland Islands (Malvinas)</option>\r
-                                                       <option value="FO">Faroe Islands</option>\r
-                                                       <option value="FJ">Fiji</option>\r
-                                                       <option value="FI">Finland</option>\r
-                                                       <option value="FR">France</option>\r
-                                                       <option value="GF">French Guiana</option>\r
-                                                       <option value="PF">French Polynesia</option>\r
-                                                       <option value="TF">French Southern Territories</option>\r
-                                                       <option value="GA">Gabon</option>\r
-                                                       <option value="GM">Gambia</option>\r
-                                                       <option value="GE">Georgia</option>\r
-                                                       <option value="DE">Germany</option>\r
-                                                       <option value="GH">Ghana</option>\r
-                                                       <option value="GI">Gibraltar</option>\r
-                                                       <option value="GR">Greece</option>\r
-                                                       <option value="GL">Greenland</option>\r
-                                                       <option value="GD">Grenada</option>\r
-                                                       <option value="GP">Guadeloupe</option>\r
-                                                       <option value="GU">Guam</option>\r
-                                                       <option value="GT">Guatemala</option>\r
-                                                       <option value="GG">Guernsey</option>\r
-                                                       <option value="GN">Guinea</option>\r
-                                                       <option value="GW">Guinea-bissau</option>\r
-                                                       <option value="GY">Guyana</option>\r
-                                                       <option value="HT">Haiti</option>\r
-                                                       <option value="HM">Heard Island and Mcdonald Islands</option>\r
-                                                       <option value="VA">Holy See (Vatican City State)</option>\r
-                                                       <option value="HN">Honduras</option>\r
-                                                       <option value="HK">Hong Kong</option>\r
-                                                       <option value="HU">Hungary</option>\r
-                                                       <option value="IS">Iceland</option>\r
-                                                       <option value="IN">India</option>\r
-                                                       <option value="ID">Indonesia</option>\r
-                                                       <option value="IR">Iran, Islamic Republic of</option>\r
-                                                       <option value="IQ">Iraq</option>\r
-                                                       <option value="IE">Ireland</option>\r
-                                                       <option value="IM">Isle of Man</option>\r
-                                                       <option value="IL">Israel</option>\r
-                                                       <option value="IT">Italy</option>\r
-                                                       <option value="JM">Jamaica</option>\r
-                                                       <option value="JP">Japan</option>\r
-                                                       <option value="JE">Jersey</option>\r
-                                                       <option value="JO">Jordan</option>\r
-                                                       <option value="KZ">Kazakhstan</option>\r
-                                                       <option value="KE">Kenya</option>\r
-                                                       <option value="KI">Kiribati</option>\r
-                                                       <option value="KP">Korea, Democratic People's Republic of</option>\r
-                                                       <option value="KR">Korea, Republic of</option>\r
-                                                       <option value="KW">Kuwait</option>\r
-                                                       <option value="KG">Kyrgyzstan</option>\r
-                                                       <option value="LA">Lao People's Democratic Republic</option>\r
-                                                       <option value="LV">Latvia</option>\r
-                                                       <option value="LB">Lebanon</option>\r
-                                                       <option value="LS">Lesotho</option>\r
-                                                       <option value="LR">Liberia</option>\r
-                                                       <option value="LY">Libyan Arab Jamahiriya</option>\r
-                                                       <option value="LI">Liechtenstein</option>\r
-                                                       <option value="LT">Lithuania</option>\r
-                                                       <option value="LU">Luxembourg</option>\r
-                                                       <option value="MO">Macao</option>\r
-                                                       <option value="MK">Macedonia, The Former Yugoslav Republic of</option>\r
-                                                       <option value="MG">Madagascar</option>\r
-                                                       <option value="MW">Malawi</option>\r
-                                                       <option value="MY">Malaysia</option>\r
-                                                       <option value="MV">Maldives</option>\r
-                                                       <option value="ML">Mali</option>\r
-                                                       <option value="MT">Malta</option>\r
-                                                       <option value="MH">Marshall Islands</option>\r
-                                                       <option value="MQ">Martinique</option>\r
-                                                       <option value="MR">Mauritania</option>\r
-                                                       <option value="MU">Mauritius</option>\r
-                                                       <option value="YT">Mayotte</option>\r
-                                                       <option value="MX">Mexico</option>\r
-                                                       <option value="FM">Micronesia, Federated States of</option>\r
-                                                       <option value="MD">Moldova, Republic of</option>\r
-                                                       <option value="MC">Monaco</option>\r
-                                                       <option value="MN">Mongolia</option>\r
-                                                       <option value="ME">Montenegro</option>\r
-                                                       <option value="MS">Montserrat</option>\r
-                                                       <option value="MA">Morocco</option>\r
-                                                       <option value="MZ">Mozambique</option>\r
-                                                       <option value="MM">Myanmar</option>\r
-                                                       <option value="NA">Namibia</option>\r
-                                                       <option value="NR">Nauru</option>\r
-                                                       <option value="NP">Nepal</option>\r
-                                                       <option value="NL">Netherlands</option>\r
-                                                       <option value="AN">Netherlands Antilles</option>\r
-                                                       <option value="NC">New Caledonia</option>\r
-                                                       <option value="NZ">New Zealand</option>\r
-                                                       <option value="NI">Nicaragua</option>\r
-                                                       <option value="NE">Niger</option>\r
-                                                       <option value="NG">Nigeria</option>\r
-                                                       <option value="NU">Niue</option>\r
-                                                       <option value="NF">Norfolk Island</option>\r
-                                                       <option value="MP">Northern Mariana Islands</option>\r
-                                                       <option value="NO">Norway</option>\r
-                                                       <option value="OM">Oman</option>\r
-                                                       <option value="PK">Pakistan</option>\r
-                                                       <option value="PW">Palau</option>\r
-                                                       <option value="PS">Palestinian Territory, Occupied</option>\r
-                                                       <option value="PA">Panama</option>\r
-                                                       <option value="PG">Papua New Guinea</option>\r
-                                                       <option value="PY">Paraguay</option>\r
-                                                       <option value="PE">Peru</option>\r
-                                                       <option value="PH">Philippines</option>\r
-                                                       <option value="PN">Pitcairn</option>\r
-                                                       <option value="PL">Poland</option>\r
-                                                       <option value="PT">Portugal</option>\r
-                                                       <option value="PR">Puerto Rico</option>\r
-                                                       <option value="QA">Qatar</option>\r
-                                                       <option value="RE">Reunion</option>\r
-                                                       <option value="RO">Romania</option>\r
-                                                       <option value="RU">Russian Federation</option>\r
-                                                       <option value="RW">Rwanda</option>\r
-                                                       <option value="SH">Saint Helena</option>\r
-                                                       <option value="KN">Saint Kitts and Nevis</option>\r
-                                                       <option value="LC">Saint Lucia</option>\r
-                                                       <option value="PM">Saint Pierre and Miquelon</option>\r
-                                                       <option value="VC">Saint Vincent and The Grenadines</option>\r
-                                                       <option value="WS">Samoa</option>\r
-                                                       <option value="SM">San Marino</option>\r
-                                                       <option value="ST">Sao Tome and Principe</option>\r
-                                                       <option value="SA">Saudi Arabia</option>\r
-                                                       <option value="SN">Senegal</option>\r
-                                                       <option value="RS">Serbia</option>\r
-                                                       <option value="SC">Seychelles</option>\r
-                                                       <option value="SL">Sierra Leone</option>\r
-                                                       <option value="SG">Singapore</option>\r
-                                                       <option value="SK">Slovakia</option>\r
-                                                       <option value="SI">Slovenia</option>\r
-                                                       <option value="SB">Solomon Islands</option>\r
-                                                       <option value="SO">Somalia</option>\r
-                                                       <option value="ZA">South Africa</option>\r
-                                                       <option value="GS">South Georgia and The South Sandwich Islands</option>\r
-                                                       <option value="ES">Spain</option>\r
-                                                       <option value="LK">Sri Lanka</option>\r
-                                                       <option value="SD">Sudan</option>\r
-                                                       <option value="SR">Suriname</option>\r
-                                                       <option value="SJ">Svalbard and Jan Mayen</option>\r
-                                                       <option value="SZ">Swaziland</option>\r
-                                                       <option value="SE">Sweden</option>\r
-                                                       <option value="CH">Switzerland</option>\r
-                                                       <option value="SY">Syrian Arab Republic</option>\r
-                                                       <option value="TW">Taiwan, Province of China</option>\r
-                                                       <option value="TJ">Tajikistan</option>\r
-                                                       <option value="TZ">Tanzania, United Republic of</option>\r
-                                                       <option value="TH">Thailand</option>\r
-                                                       <option value="TL">Timor-leste</option>\r
-                                                       <option value="TG">Togo</option>\r
-                                                       <option value="TK">Tokelau</option>\r
-                                                       <option value="TO">Tonga</option>\r
-                                                       <option value="TT">Trinidad and Tobago</option>\r
-                                                       <option value="TN">Tunisia</option>\r
-                                                       <option value="TR">Turkey</option>\r
-                                                       <option value="TM">Turkmenistan</option>\r
-                                                       <option value="TC">Turks and Caicos Islands</option>\r
-                                                       <option value="TV">Tuvalu</option>\r
-                                                       <option value="UG">Uganda</option>\r
-                                                       <option value="UA">Ukraine</option>\r
-                                                       <option value="AE">United Arab Emirates</option>\r
-                                                       <option value="GB">United Kingdom</option>\r
-                                                       <option value="US" selected="">United States</option>\r
-                                                       <option value="UM">United States Minor Outlying Islands</option>\r
-                                                       <option value="UY">Uruguay</option>\r
-                                                       <option value="UZ">Uzbekistan</option>\r
-                                                       <option value="VU">Vanuatu</option>\r
-                                                       <option value="VE">Venezuela</option>\r
-                                                       <option value="VN">Vietnam</option>\r
-                                                       <option value="VG">Virgin Islands, British</option>\r
-                                                       <option value="VI">Virgin Islands, U.S.</option>\r
-                                                       <option value="WF">Wallis and Futuna</option>\r
-                                                       <option value="EH">Western Sahara</option>\r
-                                                       <option value="YE">Yemen</option>\r
-                                                       <option value="ZM">Zambia</option>\r
-                                                       <option value="ZW">Zimbabwe</option>\r
-                                                       </select>\r
-                                               </div>\r
-                                       </div>\r
-                               <div class="row g-3 align-items-center mb-2">\r
-                                                       <label for="shipping_amt" class="col-sm-5 control-label">Shipping Type</label>\r
-                                               <div class="col-sm-7">\r
-                                                       <select class="form-control" name="shipping_amt" id="shipping_amt">\r
-                                                               <optgroup label="United Parcel Service" style="font-style:normal;">\r
-                                                                       <option value="8.00"> Worldwide Expedited - $8.00</option>\r
-                                                                       <option value="4.00"> Worldwide Express Saver - $4.00</option>\r
-                                                               </optgroup>\r
-                                                               <optgroup label="Flat Rate" style="font-style:normal;">\r
-                                                                       <option value="2.00" selected=""> Fixed - $2.00</option>\r
-                                                               </optgroup>\r
-                                                       </select>\r
-                                               </div>\r
-                                       </div>\r
-                                       <!-- Checkout Options -->\r
-                                       <div class="form-group mb-2">\r
-                                               <div class="col-sm-offset-5 col-sm-7">\r
-                                                       <div class="radio">\r
-                                                               <label>\r
-                                                                       <input type="radio" name="paymentMethod" id="paypalRadio" value="paypal" checked=""> <img src="https://www.paypalobjects.com/webstatic/mktg/logo/pp_cc_mark_37x23.jpg" alt="Acceptance Mark" class="v-middle"> <a href="https://www.paypal.com/us/cgi-bin/webscr?cmd=xpt/Marketing/popup/OLCWhatIsPayPal-outside" onclick="javascript:window.open('https://www.paypal.com/us/cgi-bin/webscr?cmd=xpt/Marketing/popup/OLCWhatIsPayPal-outside','olcwhatispaypal','toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes, ,left=0, top=0, width=400, height=350'); return false;">What is PayPal?</a> </label>\r
-                                                       </div>\r
-                                                       <div class="radio disabled mb-2">\r
-                                                               <label>\r
-                                                                       <input type="radio" name="paymentMethod" id="cardRadio" value="card" disabled=""> Card </label>\r
-                                                       </div>\r
-                                               </div>\r
-                                       </div>\r
-                                       <div class="row">\r
-                                                       <!-- Container for PayPal Mark Checkout -->\r
-                                                       <div id="paypalCheckoutContainer"></div>\r
-                                       </div>\r
-                       </form>\r
-                       </div>\r
-                       <div class="col-lg-3"></div>\r
-               </div>\r
-       </div>\r
-       <!-- Javascript Import -->\r
-       <script src="../js/config.js"></script>\r
-       <!-- PayPal In-Context Checkout script -->\r
-       <script type="text/javascript">\r
-       init_smart_buttons = () => {\r
-               paypal.Buttons({\r
-                       // Set your environment\r
-                       env: 'sandbox',\r
-                       // Set style of button\r
-                       style: {\r
-                               layout: 'vertical', // horizontal | vertical\r
-                               size: 'responsive', // medium | large | responsive\r
-                               shape: 'pill', // pill | rect\r
-                               color: 'gold' // gold | blue | silver | black\r
-                       },\r
-                       // Execute payment on authorize\r
-                       commit: true,\r
-                       // Wait for the PayPal button to be clicked\r
-                       createOrder: function() {\r
-                               let shipping_amtSelect = document.getElementById("shipping_amt"),\r
-                                       updatedShipping = shipping_amtSelect.options[shipping_amtSelect.selectedIndex].value,\r
-                                       countrySelect = document.getElementById("countrySelect"),\r
-                                       total_amt = parseFloat(document.getElementById("item_amt").value) + parseFloat(document.getElementById("tax_amt").value) + parseFloat(document.getElementById("handling_fee").value) + parseFloat(document.getElementById("insurance_fee").value) + parseFloat(updatedShipping) - parseFloat(document.getElementById("shipping_discount").value);\r
-                                       document.getElementById("total_amt").value = total_amt;\r
-                               return new Promise((resolve, reject) => {\r
-                                       $.ajax({\r
-                                               type: 'POST',\r
-                                               url: '/api/createOrder.json',\r
-                                               data: serialize(document.getElementById("camera_form")),\r
-                                               success: function(response) {\r
-                                                       return(response)\r
-                                               },\r
-                                               error: function(error) {\r
-                                                       reject(error)\r
-                                               },\r
-                                       }).then(function(response) {\r
-                                               console.log('Order ID: ' + response.id);\r
-                                               resolve(response.id);\r
-                                       });\r
-                               })\r
-                       },\r
-                       // Wait for the payment to be authorized by the customer\r
-                       onApprove: function(data, actions) {\r
-                               // Capture Order\r
-                               let postData = new FormData();\r
-                               return fetch('../api/captureOrder.json', {\r
-                                       method: 'POST',\r
-                                       body: postData\r
-                               }).then(function(res) {\r
-                                       return res.json();\r
-                               }).then(function() {\r
-                                       window.location.href = 'success.html?commit=true';\r
-                               });\r
-                       }\r
-               }).render('#paypalCheckoutContainer');\r
-       }\r
-       </script>\r
-       <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->\r
-       <script src="https://code.jquery.com/jquery.js"></script>\r
-</body>\r
-\r
-</html>\r
diff --git a/pages/shipping.html.jst b/pages/shipping.html.jst
new file mode 100644 (file)
index 0000000..adf1164
--- /dev/null
@@ -0,0 +1,960 @@
+return async env => {
+  let _out = []
+  _out.push('<!DOCTYPE html>')
+  html(lang="en") {
+    head {
+      meta(charset="utf-8") {}
+      meta(http-equiv="x-ua-compatible" content="ie=edge") {}
+      meta(name="viewport" content="width=device-width,initial-scale=1") {}
+      link(href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous") {}
+      script(src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous") {}
+      title {
+        'Checkout With PayPal NodeJs Demo'
+      }
+      style {
+        .header-bg-color {
+          color: #fff;
+          background: -moz-linear-gradient(0deg,#004094 0,#0096d9 50%,#004094 100%);
+          background: -webkit-gradient(linear,left top,right top,color-stop(0,#004094),color-stop(50%,#0096d9),color-stop(100%,#004094));
+          background: -webkit-linear-gradient(0deg,#004094 0,#0096d9 50%,#004094 100%);
+          background: -o-linear-gradient(0deg,#004094 0,#0096d9 50%,#004094 100%);
+          background: -ms-linear-gradient(0deg,#004094 0,#0096d9 50%,#004094 100%);
+          background: linear-gradient(90deg,#004094 0,#0096d9 50%,#004094 100%)
+        }
+      }
+    }
+    body {
+      div.container {
+        div.row.header-bg-color.'mb-5'.p-3 {
+          h2.text-center {
+            'Checkout with PayPal Demo'
+          }
+          h4.text-center {
+            'Using Orders v2 REST API with PayPal JavaScript SDK'
+          }
+          h5.text-center {
+            'Server-side Integration'
+          }
+        }
+        div.row {
+          div.col-lg-3 {}
+          div.col-lg-6 {
+            h3.text-center {
+              'Shipping Information'
+            }
+            hr {}
+            form#camera_form {
+              input(name="return_url" type="hidden" value="http://localhost/pages/success.html") {}
+              ' '
+              input(name="cancel_url" type="hidden" value="http://localhost/pages/success.html") {}
+              ' '
+              input#item_amt(name="item_amt" type="hidden" value="300") {}
+              ' '
+              input#insurance_fee(name="insurance_fee" type="hidden" value="10") {}
+              ' '
+              input#handling_fee(name="handling_fee" type="hidden" value="5") {}
+              ' '
+              input#tax_amt(name="tax_amt" type="hidden" value="5") {}
+              ' '
+              input#shipping_discount(name="shipping_discount" type="hidden" value="2") {}
+              ' '
+              input#currency(name="currency" type="hidden" value="USD") {}
+              ' '
+              input#total_amt(name="total_amt" type="hidden" value="300") {}
+              _out.push('<!-- Shipping Information -->')
+              div.form-group.row.mb-2 {
+                label.'col-sm-4'.col-form-label(for="recipient_name") {
+                  'Recipient Name'
+                }
+                div.col-sm-8 {
+                  input#recipient_name.form-control(type="text" name="recipient_name" aria-describedby="passwordHelpInline" value="Jane Doe") {}
+                }
+              }
+              div.form-group.row.mb-2 {
+                label.'col-sm-4'.col-form-label(for="line1") {
+                  'Address Line 1'
+                }
+                div.col-sm-8 {
+                  input#line1.form-control(type="text" name="line1" aria-describedby="passwordHelpInline" value="2211 North Street") {}
+                }
+              }
+              div.form-group.row.mb-2 {
+                label.'col-sm-4'.col-form-label(for="line2") {
+                  'Address Line 2'
+                }
+                div.col-sm-8 {
+                  input#line2.form-control(type="text" name="line2" aria-describedby="passwordHelpInline" value="") {}
+                }
+              }
+              div.form-group.row.mb-2 {
+                label.'col-sm-4'.col-form-label(for="city") {
+                  'City'
+                }
+                div.col-sm-8 {
+                  input#city.form-control(type="text" name="city" aria-describedby="passwordHelpInline" value="San Jose") {}
+                }
+              }
+              div.form-group.row.mb-2 {
+                label.'col-sm-4'.col-form-label(for="state") {
+                  'State'
+                }
+                div.col-sm-8 {
+                  input#state.form-control(type="text" name="state" aria-describedby="passwordHelpInline" value="CA") {}
+                }
+              }
+              div.form-group.row.mb-2 {
+                label.'col-sm-4'.col-form-label(for="zip") {
+                  'Postal Code'
+                }
+                div.col-sm-8 {
+                  input#zip.form-control(type="text" name="zip" aria-describedby="passwordHelpInline" value="95123") {}
+                }
+              }
+              div.form-group.row.mb-2 {
+                label.'col-sm-4'.col-form-label(for="countrySelect") {
+                  'Country'
+                }
+                div.col-sm-8 {
+                  select.form-select.mb-2#countrySelect(name="countrySelect" aria-label="Country") {
+                    option(value="AF") {
+                      'Afghanistan'
+                    }
+                    option(value="AX") {
+                      'Aland Islands'
+                    }
+                    option(value="AL") {
+                      'Albania'
+                    }
+                    option(value="DZ") {
+                      'Algeria'
+                    }
+                    option(value="AS") {
+                      'American Samoa'
+                    }
+                    option(value="AD") {
+                      'Andorra'
+                    }
+                    option(value="AO") {
+                      'Angola'
+                    }
+                    option(value="AI") {
+                      'Anguilla'
+                    }
+                    option(value="AQ") {
+                      'Antarctica'
+                    }
+                    option(value="AG") {
+                      'Antigua and Barbuda'
+                    }
+                    option(value="AR") {
+                      'Argentina'
+                    }
+                    option(value="AM") {
+                      'Armenia'
+                    }
+                    option(value="AW") {
+                      'Aruba'
+                    }
+                    option(value="AU") {
+                      'Australia'
+                    }
+                    option(value="AT") {
+                      'Austria'
+                    }
+                    option(value="AZ") {
+                      'Azerbaijan'
+                    }
+                    option(value="BS") {
+                      'Bahamas'
+                    }
+                    option(value="BH") {
+                      'Bahrain'
+                    }
+                    option(value="BD") {
+                      'Bangladesh'
+                    }
+                    option(value="BB") {
+                      'Barbados'
+                    }
+                    option(value="BY") {
+                      'Belarus'
+                    }
+                    option(value="BE") {
+                      'Belgium'
+                    }
+                    option(value="BZ") {
+                      'Belize'
+                    }
+                    option(value="BJ") {
+                      'Benin'
+                    }
+                    option(value="BM") {
+                      'Bermuda'
+                    }
+                    option(value="BT") {
+                      'Bhutan'
+                    }
+                    option(value="BO") {
+                      'Bolivia'
+                    }
+                    option(value="BA") {
+                      'Bosnia and Herzegovina'
+                    }
+                    option(value="BW") {
+                      'Botswana'
+                    }
+                    option(value="BV") {
+                      'Bouvet Island'
+                    }
+                    option(value="BR") {
+                      'Brazil'
+                    }
+                    option(value="IO") {
+                      'British Indian Ocean Territory'
+                    }
+                    option(value="BN") {
+                      'Brunei Darussalam'
+                    }
+                    option(value="BG") {
+                      'Bulgaria'
+                    }
+                    option(value="BF") {
+                      'Burkina Faso'
+                    }
+                    option(value="BI") {
+                      'Burundi'
+                    }
+                    option(value="KH") {
+                      'Cambodia'
+                    }
+                    option(value="CM") {
+                      'Cameroon'
+                    }
+                    option(value="CA") {
+                      'Canada'
+                    }
+                    option(value="CV") {
+                      'Cape Verde'
+                    }
+                    option(value="KY") {
+                      'Cayman Islands'
+                    }
+                    option(value="CF") {
+                      'Central African Republic'
+                    }
+                    option(value="TD") {
+                      'Chad'
+                    }
+                    option(value="CL") {
+                      'Chile'
+                    }
+                    option(value="CN") {
+                      'China'
+                    }
+                    option(value="CX") {
+                      'Christmas Island'
+                    }
+                    option(value="CC") {
+                      'Cocos (Keeling) Islands'
+                    }
+                    option(value="CO") {
+                      'Colombia'
+                    }
+                    option(value="KM") {
+                      'Comoros'
+                    }
+                    option(value="CG") {
+                      'Congo'
+                    }
+                    option(value="CD") {
+                      'Congo, The Democratic Republic of The'
+                    }
+                    option(value="CK") {
+                      'Cook Islands'
+                    }
+                    option(value="CR") {
+                      'Costa Rica'
+                    }
+                    option(value="CI") {
+                      'Cote D\'ivoire'
+                    }
+                    option(value="HR") {
+                      'Croatia'
+                    }
+                    option(value="CU") {
+                      'Cuba'
+                    }
+                    option(value="CY") {
+                      'Cyprus'
+                    }
+                    option(value="CZ") {
+                      'Czech Republic'
+                    }
+                    option(value="DK") {
+                      'Denmark'
+                    }
+                    option(value="DJ") {
+                      'Djibouti'
+                    }
+                    option(value="DM") {
+                      'Dominica'
+                    }
+                    option(value="DO") {
+                      'Dominican Republic'
+                    }
+                    option(value="EC") {
+                      'Ecuador'
+                    }
+                    option(value="EG") {
+                      'Egypt'
+                    }
+                    option(value="SV") {
+                      'El Salvador'
+                    }
+                    option(value="GQ") {
+                      'Equatorial Guinea'
+                    }
+                    option(value="ER") {
+                      'Eritrea'
+                    }
+                    option(value="EE") {
+                      'Estonia'
+                    }
+                    option(value="ET") {
+                      'Ethiopia'
+                    }
+                    option(value="FK") {
+                      'Falkland Islands (Malvinas)'
+                    }
+                    option(value="FO") {
+                      'Faroe Islands'
+                    }
+                    option(value="FJ") {
+                      'Fiji'
+                    }
+                    option(value="FI") {
+                      'Finland'
+                    }
+                    option(value="FR") {
+                      'France'
+                    }
+                    option(value="GF") {
+                      'French Guiana'
+                    }
+                    option(value="PF") {
+                      'French Polynesia'
+                    }
+                    option(value="TF") {
+                      'French Southern Territories'
+                    }
+                    option(value="GA") {
+                      'Gabon'
+                    }
+                    option(value="GM") {
+                      'Gambia'
+                    }
+                    option(value="GE") {
+                      'Georgia'
+                    }
+                    option(value="DE") {
+                      'Germany'
+                    }
+                    option(value="GH") {
+                      'Ghana'
+                    }
+                    option(value="GI") {
+                      'Gibraltar'
+                    }
+                    option(value="GR") {
+                      'Greece'
+                    }
+                    option(value="GL") {
+                      'Greenland'
+                    }
+                    option(value="GD") {
+                      'Grenada'
+                    }
+                    option(value="GP") {
+                      'Guadeloupe'
+                    }
+                    option(value="GU") {
+                      'Guam'
+                    }
+                    option(value="GT") {
+                      'Guatemala'
+                    }
+                    option(value="GG") {
+                      'Guernsey'
+                    }
+                    option(value="GN") {
+                      'Guinea'
+                    }
+                    option(value="GW") {
+                      'Guinea-bissau'
+                    }
+                    option(value="GY") {
+                      'Guyana'
+                    }
+                    option(value="HT") {
+                      'Haiti'
+                    }
+                    option(value="HM") {
+                      'Heard Island and Mcdonald Islands'
+                    }
+                    option(value="VA") {
+                      'Holy See (Vatican City State)'
+                    }
+                    option(value="HN") {
+                      'Honduras'
+                    }
+                    option(value="HK") {
+                      'Hong Kong'
+                    }
+                    option(value="HU") {
+                      'Hungary'
+                    }
+                    option(value="IS") {
+                      'Iceland'
+                    }
+                    option(value="IN") {
+                      'India'
+                    }
+                    option(value="ID") {
+                      'Indonesia'
+                    }
+                    option(value="IR") {
+                      'Iran, Islamic Republic of'
+                    }
+                    option(value="IQ") {
+                      'Iraq'
+                    }
+                    option(value="IE") {
+                      'Ireland'
+                    }
+                    option(value="IM") {
+                      'Isle of Man'
+                    }
+                    option(value="IL") {
+                      'Israel'
+                    }
+                    option(value="IT") {
+                      'Italy'
+                    }
+                    option(value="JM") {
+                      'Jamaica'
+                    }
+                    option(value="JP") {
+                      'Japan'
+                    }
+                    option(value="JE") {
+                      'Jersey'
+                    }
+                    option(value="JO") {
+                      'Jordan'
+                    }
+                    option(value="KZ") {
+                      'Kazakhstan'
+                    }
+                    option(value="KE") {
+                      'Kenya'
+                    }
+                    option(value="KI") {
+                      'Kiribati'
+                    }
+                    option(value="KP") {
+                      'Korea, Democratic People\'s Republic of'
+                    }
+                    option(value="KR") {
+                      'Korea, Republic of'
+                    }
+                    option(value="KW") {
+                      'Kuwait'
+                    }
+                    option(value="KG") {
+                      'Kyrgyzstan'
+                    }
+                    option(value="LA") {
+                      'Lao People\'s Democratic Republic'
+                    }
+                    option(value="LV") {
+                      'Latvia'
+                    }
+                    option(value="LB") {
+                      'Lebanon'
+                    }
+                    option(value="LS") {
+                      'Lesotho'
+                    }
+                    option(value="LR") {
+                      'Liberia'
+                    }
+                    option(value="LY") {
+                      'Libyan Arab Jamahiriya'
+                    }
+                    option(value="LI") {
+                      'Liechtenstein'
+                    }
+                    option(value="LT") {
+                      'Lithuania'
+                    }
+                    option(value="LU") {
+                      'Luxembourg'
+                    }
+                    option(value="MO") {
+                      'Macao'
+                    }
+                    option(value="MK") {
+                      'Macedonia, The Former Yugoslav Republic of'
+                    }
+                    option(value="MG") {
+                      'Madagascar'
+                    }
+                    option(value="MW") {
+                      'Malawi'
+                    }
+                    option(value="MY") {
+                      'Malaysia'
+                    }
+                    option(value="MV") {
+                      'Maldives'
+                    }
+                    option(value="ML") {
+                      'Mali'
+                    }
+                    option(value="MT") {
+                      'Malta'
+                    }
+                    option(value="MH") {
+                      'Marshall Islands'
+                    }
+                    option(value="MQ") {
+                      'Martinique'
+                    }
+                    option(value="MR") {
+                      'Mauritania'
+                    }
+                    option(value="MU") {
+                      'Mauritius'
+                    }
+                    option(value="YT") {
+                      'Mayotte'
+                    }
+                    option(value="MX") {
+                      'Mexico'
+                    }
+                    option(value="FM") {
+                      'Micronesia, Federated States of'
+                    }
+                    option(value="MD") {
+                      'Moldova, Republic of'
+                    }
+                    option(value="MC") {
+                      'Monaco'
+                    }
+                    option(value="MN") {
+                      'Mongolia'
+                    }
+                    option(value="ME") {
+                      'Montenegro'
+                    }
+                    option(value="MS") {
+                      'Montserrat'
+                    }
+                    option(value="MA") {
+                      'Morocco'
+                    }
+                    option(value="MZ") {
+                      'Mozambique'
+                    }
+                    option(value="MM") {
+                      'Myanmar'
+                    }
+                    option(value="NA") {
+                      'Namibia'
+                    }
+                    option(value="NR") {
+                      'Nauru'
+                    }
+                    option(value="NP") {
+                      'Nepal'
+                    }
+                    option(value="NL") {
+                      'Netherlands'
+                    }
+                    option(value="AN") {
+                      'Netherlands Antilles'
+                    }
+                    option(value="NC") {
+                      'New Caledonia'
+                    }
+                    option(value="NZ") {
+                      'New Zealand'
+                    }
+                    option(value="NI") {
+                      'Nicaragua'
+                    }
+                    option(value="NE") {
+                      'Niger'
+                    }
+                    option(value="NG") {
+                      'Nigeria'
+                    }
+                    option(value="NU") {
+                      'Niue'
+                    }
+                    option(value="NF") {
+                      'Norfolk Island'
+                    }
+                    option(value="MP") {
+                      'Northern Mariana Islands'
+                    }
+                    option(value="NO") {
+                      'Norway'
+                    }
+                    option(value="OM") {
+                      'Oman'
+                    }
+                    option(value="PK") {
+                      'Pakistan'
+                    }
+                    option(value="PW") {
+                      'Palau'
+                    }
+                    option(value="PS") {
+                      'Palestinian Territory, Occupied'
+                    }
+                    option(value="PA") {
+                      'Panama'
+                    }
+                    option(value="PG") {
+                      'Papua New Guinea'
+                    }
+                    option(value="PY") {
+                      'Paraguay'
+                    }
+                    option(value="PE") {
+                      'Peru'
+                    }
+                    option(value="PH") {
+                      'Philippines'
+                    }
+                    option(value="PN") {
+                      'Pitcairn'
+                    }
+                    option(value="PL") {
+                      'Poland'
+                    }
+                    option(value="PT") {
+                      'Portugal'
+                    }
+                    option(value="PR") {
+                      'Puerto Rico'
+                    }
+                    option(value="QA") {
+                      'Qatar'
+                    }
+                    option(value="RE") {
+                      'Reunion'
+                    }
+                    option(value="RO") {
+                      'Romania'
+                    }
+                    option(value="RU") {
+                      'Russian Federation'
+                    }
+                    option(value="RW") {
+                      'Rwanda'
+                    }
+                    option(value="SH") {
+                      'Saint Helena'
+                    }
+                    option(value="KN") {
+                      'Saint Kitts and Nevis'
+                    }
+                    option(value="LC") {
+                      'Saint Lucia'
+                    }
+                    option(value="PM") {
+                      'Saint Pierre and Miquelon'
+                    }
+                    option(value="VC") {
+                      'Saint Vincent and The Grenadines'
+                    }
+                    option(value="WS") {
+                      'Samoa'
+                    }
+                    option(value="SM") {
+                      'San Marino'
+                    }
+                    option(value="ST") {
+                      'Sao Tome and Principe'
+                    }
+                    option(value="SA") {
+                      'Saudi Arabia'
+                    }
+                    option(value="SN") {
+                      'Senegal'
+                    }
+                    option(value="RS") {
+                      'Serbia'
+                    }
+                    option(value="SC") {
+                      'Seychelles'
+                    }
+                    option(value="SL") {
+                      'Sierra Leone'
+                    }
+                    option(value="SG") {
+                      'Singapore'
+                    }
+                    option(value="SK") {
+                      'Slovakia'
+                    }
+                    option(value="SI") {
+                      'Slovenia'
+                    }
+                    option(value="SB") {
+                      'Solomon Islands'
+                    }
+                    option(value="SO") {
+                      'Somalia'
+                    }
+                    option(value="ZA") {
+                      'South Africa'
+                    }
+                    option(value="GS") {
+                      'South Georgia and The South Sandwich Islands'
+                    }
+                    option(value="ES") {
+                      'Spain'
+                    }
+                    option(value="LK") {
+                      'Sri Lanka'
+                    }
+                    option(value="SD") {
+                      'Sudan'
+                    }
+                    option(value="SR") {
+                      'Suriname'
+                    }
+                    option(value="SJ") {
+                      'Svalbard and Jan Mayen'
+                    }
+                    option(value="SZ") {
+                      'Swaziland'
+                    }
+                    option(value="SE") {
+                      'Sweden'
+                    }
+                    option(value="CH") {
+                      'Switzerland'
+                    }
+                    option(value="SY") {
+                      'Syrian Arab Republic'
+                    }
+                    option(value="TW") {
+                      'Taiwan, Province of China'
+                    }
+                    option(value="TJ") {
+                      'Tajikistan'
+                    }
+                    option(value="TZ") {
+                      'Tanzania, United Republic of'
+                    }
+                    option(value="TH") {
+                      'Thailand'
+                    }
+                    option(value="TL") {
+                      'Timor-leste'
+                    }
+                    option(value="TG") {
+                      'Togo'
+                    }
+                    option(value="TK") {
+                      'Tokelau'
+                    }
+                    option(value="TO") {
+                      'Tonga'
+                    }
+                    option(value="TT") {
+                      'Trinidad and Tobago'
+                    }
+                    option(value="TN") {
+                      'Tunisia'
+                    }
+                    option(value="TR") {
+                      'Turkey'
+                    }
+                    option(value="TM") {
+                      'Turkmenistan'
+                    }
+                    option(value="TC") {
+                      'Turks and Caicos Islands'
+                    }
+                    option(value="TV") {
+                      'Tuvalu'
+                    }
+                    option(value="UG") {
+                      'Uganda'
+                    }
+                    option(value="UA") {
+                      'Ukraine'
+                    }
+                    option(value="AE") {
+                      'United Arab Emirates'
+                    }
+                    option(value="GB") {
+                      'United Kingdom'
+                    }
+                    option(value="US" selected="") {
+                      'United States'
+                    }
+                    option(value="UM") {
+                      'United States Minor Outlying Islands'
+                    }
+                    option(value="UY") {
+                      'Uruguay'
+                    }
+                    option(value="UZ") {
+                      'Uzbekistan'
+                    }
+                    option(value="VU") {
+                      'Vanuatu'
+                    }
+                    option(value="VE") {
+                      'Venezuela'
+                    }
+                    option(value="VN") {
+                      'Vietnam'
+                    }
+                    option(value="VG") {
+                      'Virgin Islands, British'
+                    }
+                    option(value="VI") {
+                      'Virgin Islands, U.S.'
+                    }
+                    option(value="WF") {
+                      'Wallis and Futuna'
+                    }
+                    option(value="EH") {
+                      'Western Sahara'
+                    }
+                    option(value="YE") {
+                      'Yemen'
+                    }
+                    option(value="ZM") {
+                      'Zambia'
+                    }
+                    option(value="ZW") {
+                      'Zimbabwe'
+                    }
+                  }
+                }
+              }
+              div.row.'g-3'.align-items-center.mb-2 {
+                label.'col-sm-5'.control-label(for="shipping_amt") {
+                  'Shipping Type'
+                }
+                div.col-sm-7 {
+                  select.form-control#shipping_amt(name="shipping_amt") {
+                    optgroup(label="United Parcel Service" style="font-style:normal;") {
+                      option(value="8.00") {
+                        'Worldwide Expedited - $8.00'
+                      }
+                      option(value="4.00") {
+                        'Worldwide Express Saver - $4.00'
+                      }
+                    }
+                    optgroup(label="Flat Rate" style="font-style:normal;") {
+                      option(value="2.00" selected="") {
+                        'Fixed - $2.00'
+                      }
+                    }
+                  }
+                }
+              }
+              _out.push('<!-- Checkout Options -->')
+              div.form-group.mb-2 {
+                div.'col-sm-offset-5'.col-sm-7 {
+                  div.radio {
+                    label {
+                      input#paypalRadio(type="radio" name="paymentMethod" value="paypal" checked="") {}
+                      ' '
+                      img.v-middle(src="https://www.paypalobjects.com/webstatic/mktg/logo/pp_cc_mark_37x23.jpg" alt="Acceptance Mark") {}
+                      ' '
+                      a(href="https://www.paypal.com/us/cgi-bin/webscr?cmd=xpt/Marketing/popup/OLCWhatIsPayPal-outside" onclick="window.open('https://www.paypal.com/us/cgi-bin/webscr?cmd=xpt/Marketing/popup/OLCWhatIsPayPal-outside','olcwhatispaypal','toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes, ,left=0, top=0, width=400, height=350'); return false;") {
+                        'What is PayPal?'
+                      }
+                    }
+                  }
+                  div.radio.disabled.mb-2 {
+                    label {
+                      input#cardRadio(type="radio" name="paymentMethod" value="card" disabled="") {}
+                      ' Card'
+                    }
+                  }
+                }
+              }
+              div.row {
+                _out.push('<!-- Container for PayPal Mark Checkout -->')
+                div#paypalCheckoutContainer {}
+              }
+            }
+          }
+          div.col-lg-3 {}
+        }
+      }
+      _out.push('<!-- Javascript Import -->')
+      script(src="../js/config.js") {}
+      _out.push('<!-- PayPal In-Context Checkout script -->')
+      script(type="text/javascript") {
+        init_smart_buttons = (() => {
+          paypal.Buttons({
+            env: "sandbox",
+            style: {
+              layout: "vertical",
+              size: "responsive",
+              shape: "pill",
+              color: "gold"
+            },
+            commit: true,
+            createOrder: function() {
+              let shipping_amtSelect = document.getElementById("shipping_amt"), updatedShipping = shipping_amtSelect.options[shipping_amtSelect.selectedIndex].value, countrySelect = document.getElementById("countrySelect"), total_amt = parseFloat(document.getElementById("item_amt").value) + parseFloat(document.getElementById("tax_amt").value) + parseFloat(document.getElementById("handling_fee").value) + parseFloat(document.getElementById("insurance_fee").value) + parseFloat(updatedShipping) - parseFloat(document.getElementById("shipping_discount").value);
+              document.getElementById("total_amt").value = total_amt;
+              return new Promise((resolve, reject) => {
+                $.ajax({
+                  type: "POST",
+                  url: "/api/createOrder.json",
+                  data: serialize(document.getElementById("camera_form")),
+                  success: function(response) {
+                    return response;
+                  },
+                  error: function(error) {
+                    reject(error);
+                  }
+                }).then(function(response) {
+                  console.log("Order ID: " + response.id);
+                  resolve(response.id);
+                });
+              });
+            },
+            onApprove: function(data, actions) {
+              let postData = new FormData();
+              return fetch("../api/captureOrder.json", {
+                method: "POST",
+                body: postData
+              }).then(function(res) {
+                return res.json();
+              }).then(function() {
+                window.location.href = "success.html?commit=true";
+              });
+            }
+          }).render("#paypalCheckoutContainer");
+        });
+      }
+      _out.push('<!-- jQuery (necessary for Bootstrap\'s JavaScript plugins) -->')
+      script(src="https://code.jquery.com/jquery.js") {}
+    }
+  }
+  env.site.serve(env, 200, Buffer.from(_out.join('')), 'shipping.html.jst')
+}
diff --git a/pages/success.html b/pages/success.html
deleted file mode 100644 (file)
index 437d54b..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-
-<head>
-       <meta charset="utf-8" />
-       <meta http-equiv="x-ua-compatible" content="ie=edge" />
-       <meta name="viewport" content="width=device-width, initial-scale=1" />
-       <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
-       <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script>
-       <title>Checkout With PayPal NodeJs Demo</title>
-       <style>
-       /* http://angrytools.com/gradient/ */
-       
-       .header-bg-color {
-               color: white;
-               background: -moz-linear-gradient(0deg, #004094 0%, #0096D9 50%, #004094 100%);
-               /* ff3.6+ */
-               background: -webkit-gradient(linear, left top, right top, color-stop(0%, #004094), color-stop(50%, #0096D9), color-stop(100%, #004094));
-               /* safari4+,chrome */
-               background: -webkit-linear-gradient(0deg, #004094 0%, #0096D9 50%, #004094 100%);
-               /* safari5.1+,chrome10+ */
-               background: -o-linear-gradient(0deg, #004094 0%, #0096D9 50%, #004094 100%);
-               /* opera 11.10+ */
-               background: -ms-linear-gradient(0deg, #004094 0%, #0096D9 50%, #004094 100%);
-               /* ie10+ */
-               background: linear-gradient(90deg, #004094 0%, #0096D9 50%, #004094 100%);
-               /* w3c */
-               filter: progid: DXImageTransform.Microsoft.gradient( startColorstr='#004094', endColorstr='#004094', GradientType=1);
-               /* ie6-9 */
-       }
-       #orderView p, #orderConfirm p {
-               margin:0;
-       }
-       </style>
-</head>
-
-<body>
-       <div class="container">
-               <div class="row header-bg-color mb-5 p-3">
-                       <h2 class="text-center">Checkout with PayPal Demo</h2>
-                       <h4 class="text-center">Using Orders v2 REST API with PayPal JavaScript SDK</h4>
-                       <h5 class="text-center">Server-side Integration</h5> </div>
-               <div class="row">
-                       <div class="col-sm"> </div>
-                       <div class="col-sm">
-                               <div id="loadingAlert" class="card" style="display: none;">
-                                       <div class="card-body">
-                                               <div class="alert alert-info block" role="alert"> Loading.... </div>
-                                       </div>
-                               </div>
-                               <form id="orderConfirm" class="form-horizontal" style="display: none;">
-                                       <h3>Your payment is authorized.</h3>
-                                       <h4>Confirm the order to execute</h4>
-                                       <hr>
-                                       <div class="form-group">
-                                               <label style="font-weight:bold" class="col-sm-5 control-label">Shipping Information</label>
-                                               <div class="col-sm">
-                                                       <p id="confirmRecipient"></p>
-                                                       <p id="confirmAddressLine1"></p>
-                                                       <p id="confirmAddressLine2"></p>
-                                                       <p> <span id="confirmCity"></span>, <span id="confirmState"></span> - <span id="confirmZip"></span> </p>
-                                                       <p id="confirmCountry"></p>
-                                               </div>
-                                       </div>
-                                       <div class="form-group">
-                                               <label style="font-weight:bold" for="shippingMethod" class="col-sm-5 control-label">Shipping Type</label>
-                                               <div class="col-sm">
-                                                       <select class="form-control" name="shippingMethod" id="shippingMethod">
-                                                               <optgroup label="United Parcel Service" style="font-style:normal;">
-                                                                       <option value="8.00"> Worldwide Expedited - $8.00</option>
-                                                                       <option value="4.00"> Worldwide Express Saver - $4.00</option>
-                                                               </optgroup>
-                                                               <optgroup label="Flat Rate" style="font-style:normal;">
-                                                                       <option value="2.00" selected> Fixed - $2.00</option>
-                                                               </optgroup>
-                                                       </select>
-                                               </div>
-                                       </div>
-                                       <hr>
-                                       <div class="form-group">
-                                               <div class="col-sm-offset-5 col-sm">
-                                                       <label class="btn btn-primary" id="confirmButton">Complete Payment</label>
-                                               </div>
-                                       </div>
-                               </form>
-                               <form id="orderView" class="form-horizontal" style="display: none;">
-                                       <h3>Your payment is complete</h3>
-                                       <h4>
-                    <span id="viewFirstName"></span>
-                    <span id="viewLastName"></span>,
-                    Thank you for your Order
-                </h4>
-                                       <hr>
-                                       <div class="form-group">
-                                               <div class="form-group">
-                                                       <label style="font-weight:bold" class="col-sm-5 control-label">Shipping Details</label>
-                                                       <div class="col-sm">
-                                                               <p id="viewRecipientName"></p>
-                                                               <p id="viewAddressLine1"></p>
-                                                               <p id="viewAddressLine2"></p>
-                                                               <p> <span id="viewCity"></span>, <span id="viewState"></span> - <span id="viewPostalCode"></span> </p>
-                                                               <p id="confirmCountry"></p>
-                                                       </div>
-                                               </div>
-                                               <div class="form-group">
-                                                       <label style="font-weight:bold" class="col-sm-5 control-label">Transaction Details</label>
-                                                       <div class="col-sm">
-                                                               <p>Transaction ID: <span id="viewTransactionID"></span></p>
-                                                               <p>Payment Total Amount: <span id="viewFinalAmount"></span> </p>
-                                                               <p>Currency Code: <span id="viewCurrency"></span></p>
-                                                               <p>Payment Status: <span id="viewPaymentState"></span></p>
-                                                               <p id="transactionType">Payment Type: <span id="viewTransactionType"></span> </p>
-                                                       </div>
-                                               </div>
-                                       </div>
-                                       <hr>
-                                       <h4> Click <a href='/'>here </a> to return to Home Page</h4> </form>
-                       </div>
-                       <div class="col-sm"> </div>
-               </div>
-       </div>
-       <!-- Javascript Import -->
-       <script src="../js/config.js"></script>
-       <script type="text/javascript">
-       showDom('loadingAlert');
-       document.onreadystatechange = function() {
-               if(document.readyState === 'complete') {
-                       $.ajax({
-                               type: 'POST',
-                               url: '/api/getOrderDetails.json',
-                               success: function(response, textStatus, xhr) {
-                                       hideDom('loadingAlert');
-                                       if(textStatus === "success") {
-                                               console.log("Success Response:\n" + response);
-                                               if(getUrlParams('commit') === 'true') {
-                                                       showPaymentExecute(response);
-                                               } else {
-                                                       showPaymentGet(response);
-                                               }
-                                       } else {
-                                               alert('Something went wrong');
-                                       }
-                               }
-                       });
-               }
-       }
-
-       function showPaymentGet(res) {
-               let shipping = res.purchase_units[0].shipping;
-               let shipping_address = shipping.address;
-               console.log('Get Order result ' + JSON.stringify(res));
-               console.log('shipping add ' + JSON.stringify(shipping));
-               document.getElementById('confirmRecipient').innerText = shipping.name.full_name;
-               document.getElementById('confirmAddressLine1').innerText = shipping_address.address_line_1;
-               if(shipping_address.address_line_2) document.getElementById('confirmAddressLine2').innerText = shipping_address.address_line_1;
-               else document.getElementById('confirmAddressLine2').innerText = "";
-               document.getElementById('confirmCity').innerText = shipping_address.admin_area_2;
-               document.getElementById('confirmState').innerText = shipping_address.admin_area_1;
-               document.getElementById('confirmZip').innerText = shipping_address.postal_code;
-               document.getElementById('confirmCountry').innerText = shipping_address.country_code;
-               showDom('orderConfirm');
-               // Listen for click on confirm button
-               document.querySelector('#confirmButton').addEventListener('click', function() {
-                       let shippingMethodSelect = document.getElementById("shippingMethod"),
-                               updatedShipping = shippingMethodSelect.options[shippingMethodSelect.selectedIndex].value,
-                               currentShipping = res.purchase_units[0].amount.breakdown.shipping.value;
-                       let postPatchOrderData = {
-                               "order_id": res.id,
-                               "item_amt": res.purchase_units[0].amount.breakdown.item_total.value,
-                               "tax_amt": res.purchase_units[0].amount.breakdown.tax_total.value,
-                               "handling_fee": res.purchase_units[0].amount.breakdown.handling.value,
-                               "insurance_fee": res.purchase_units[0].amount.breakdown.insurance.value,
-                               "shipping_discount": res.purchase_units[0].amount.breakdown.shipping_discount.value,
-                               "total_amt": res.purchase_units[0].amount.value,
-                               "currency": res.purchase_units[0].amount.currency_code,
-                               "updated_shipping": updatedShipping,
-                               "current_shipping": currentShipping
-                       };
-                       console.log('patch data: ' + JSON.stringify(postPatchOrderData));
-                       // Execute the payment
-                       hideDom('orderConfirm');
-                       hideDom('confirmButton');
-                       showDom('loadingAlert');
-                       console.log('Current shipping ' + currentShipping + ' and updated shipping is ' + updatedShipping);
-                       if(currentShipping == updatedShipping) {
-                               return callPaymentCapture();
-                       } else {
-                               console.log("Trying patch first");
-                               $.ajax({
-                                       type: 'POST',
-                                       url: '/api/patchOrder.json',
-                                       data: postPatchOrderData,
-                                       success: function(response) {
-                                               console.log('Patch Order Response has no content in V2: ' + JSON.stringify(response));
-                                               //The PayPal Orders V2 Patch call only returns 204 http status code
-                                               if(response.http_code === 204) return callPaymentCapture();
-                                       }
-                               });
-                       }
-               });
-       }
-
-       function callPaymentCapture() {
-               $.ajax({
-                       type: 'POST',
-                       url: '/api/captureOrder.json',
-                       success: function(response) {
-                               hideDom('orderConfirm');
-                               hideDom('loadingAlert');
-                               console.log('Capture Response : ' + JSON.stringify(response));
-                               showPaymentExecute(response);
-                       },
-                       error: function(err) {
-                               alert("Something went wrong");
-                       }
-               });
-       }
-
-       function showPaymentExecute(result) {
-               console.log("Final Result:\n" + result);
-               document.getElementById('viewFirstName').textContent = result.payer.name.given_name;
-               document.getElementById('viewLastName').textContent = result.payer.name.surname;
-               document.getElementById('viewRecipientName').textContent = result.purchase_units[0].shipping.name.full_name;
-               document.getElementById('viewAddressLine1').textContent = result.purchase_units[0].shipping.address.address_line_1;
-               if (result.purchase_units[0].shipping.address.address_line_2) {
-               document.getElementById('viewAddressLine2').textContent = result.purchase_units[0].shipping.address.address_line_2;} else {
-               document.getElementById('viewAddressLine2').textContent = ""; }
-               document.getElementById('viewCity').textContent = result.purchase_units[0].shipping.address.admin_area_2;
-               document.getElementById('viewState').textContent = result.purchase_units[0].shipping.address.admin_area_1;
-               document.getElementById('viewPostalCode').innerHTML = result.purchase_units[0].shipping.address.postal_code;
-               document.getElementById('viewTransactionID').textContent = result.id;
-               if(result.purchase_units[0].payments && result.purchase_units[0].payments.captures) {
-                       document.getElementById('viewFinalAmount').textContent = result.purchase_units[0].payments.captures[0].amount.value;
-                       document.getElementById('viewCurrency').textContent = result.purchase_units[0].payments.captures[0].amount.currency_code;
-               } else {
-                       document.getElementById('viewFinalAmount').textContent = result.purchase_units[0].amount.value;
-                       document.getElementById('viewCurrency').textContent = result.purchase_units[0].amount.currency_code;
-               }
-               document.getElementById('viewPaymentState').textContent = result.status;
-               if(result.intent) {
-                       document.getElementById('viewTransactionType').textContent = result.intent;
-                       document.getElementById('transactionType').style.display = 'block';
-               } else {
-                       document.getElementById('transactionType').style.display = 'none';
-               }
-               hideDom('orderConfirm');
-               hideDom('loadingAlert');
-               showDom('orderView');
-       }
-       </script>
-       <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
-       <script src="https://code.jquery.com/jquery.js"></script>
-</body>
-
-</html>
diff --git a/pages/success.html.jst b/pages/success.html.jst
new file mode 100644 (file)
index 0000000..4de021c
--- /dev/null
@@ -0,0 +1,312 @@
+return async env => {
+  let _out = []
+  _out.push('<!DOCTYPE html>')
+  html(lang="en") {
+    head {
+      meta(charset="utf-8") {}
+      meta(http-equiv="x-ua-compatible" content="ie=edge") {}
+      meta(name="viewport" content="width=device-width,initial-scale=1") {}
+      link(href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous") {}
+      script(src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous") {}
+      title {
+        'Checkout With PayPal NodeJs Demo'
+      }
+      style {
+        .header-bg-color {
+          color: #fff;
+          background: -moz-linear-gradient(0deg,#004094 0,#0096d9 50%,#004094 100%);
+          background: -webkit-gradient(linear,left top,right top,color-stop(0,#004094),color-stop(50%,#0096d9),color-stop(100%,#004094));
+          background: -webkit-linear-gradient(0deg,#004094 0,#0096d9 50%,#004094 100%);
+          background: -o-linear-gradient(0deg,#004094 0,#0096d9 50%,#004094 100%);
+          background: -ms-linear-gradient(0deg,#004094 0,#0096d9 50%,#004094 100%);
+          background: linear-gradient(90deg,#004094 0,#0096d9 50%,#004094 100%)
+        }
+        #orderConfirm p,
+        #orderView p {
+          margin: 0
+        }
+      }
+    }
+    body {
+      div.container {
+        div.row.header-bg-color.'mb-5'.p-3 {
+          h2.text-center {
+            'Checkout with PayPal Demo'
+          }
+          h4.text-center {
+            'Using Orders v2 REST API with PayPal JavaScript SDK'
+          }
+          h5.text-center {
+            'Server-side Integration'
+          }
+        }
+        div.row {
+          div.col-sm {}
+          div.col-sm {
+            div#loadingAlert.card(style="display: none;") {
+              div.card-body {
+                div.alert.alert-info.block(role="alert") {
+                  'Loading....'
+                }
+              }
+            }
+            form#orderConfirm.form-horizontal(style="display: none;") {
+              h3 {
+                'Your payment is authorized.'
+              }
+              h4 {
+                'Confirm the order to execute'
+              }
+              hr {}
+              div.form-group {
+                label.'col-sm-5'.control-label(style="font-weight:bold") {
+                  'Shipping Information'
+                }
+                div.col-sm {
+                  p#confirmRecipient {}
+                  p#confirmAddressLine1 {}
+                  p#confirmAddressLine2 {}
+                  p {
+                    span#confirmCity {}
+                    ', '
+                    span#confirmState {}
+                    ' - '
+                    span#confirmZip {}
+                  }
+                  p#confirmCountry {}
+                }
+              }
+              div.form-group {
+                label.'col-sm-5'.control-label(style="font-weight:bold" for="shippingMethod") {
+                  'Shipping Type'
+                }
+                div.col-sm {
+                  select.form-control#shippingMethod(name="shippingMethod") {
+                    optgroup(label="United Parcel Service" style="font-style:normal;") {
+                      option(value="8.00") {
+                        'Worldwide Expedited - $8.00'
+                      }
+                      option(value="4.00") {
+                        'Worldwide Express Saver - $4.00'
+                      }
+                    }
+                    optgroup(label="Flat Rate" style="font-style:normal;") {
+                      option(value="2.00" selected="selected") {
+                        'Fixed - $2.00'
+                      }
+                    }
+                  }
+                }
+              }
+              hr {}
+              div.form-group {
+                div.'col-sm-offset-5'.col-sm {
+                  label.btn.btn-primary#confirmButton {
+                    'Complete Payment'
+                  }
+                }
+              }
+            }
+            form#orderView.form-horizontal(style="display: none;") {
+              h3 {
+                'Your payment is complete'
+              }
+              h4 {
+                span#viewFirstName {}
+                ' '
+                span#viewLastName {}
+                ', Thank you for your Order'
+              }
+              hr {}
+              div.form-group {
+                div.form-group {
+                  label.'col-sm-5'.control-label(style="font-weight:bold") {
+                    'Shipping Details'
+                  }
+                  div.col-sm {
+                    p#viewRecipientName {}
+                    p#viewAddressLine1 {}
+                    p#viewAddressLine2 {}
+                    p {
+                      span#viewCity {}
+                      ', '
+                      span#viewState {}
+                      ' - '
+                      span#viewPostalCode {}
+                    }
+                    p#confirmCountry {}
+                  }
+                }
+                div.form-group {
+                  label.'col-sm-5'.control-label(style="font-weight:bold") {
+                    'Transaction Details'
+                  }
+                  div.col-sm {
+                    p {
+                      'Transaction ID: '
+                      span#viewTransactionID {}
+                    }
+                    p {
+                      'Payment Total Amount: '
+                      span#viewFinalAmount {}
+                    }
+                    p {
+                      'Currency Code: '
+                      span#viewCurrency {}
+                    }
+                    p {
+                      'Payment Status: '
+                      span#viewPaymentState {}
+                    }
+                    p#transactionType {
+                      'Payment Type: '
+                      span#viewTransactionType {}
+                    }
+                  }
+                }
+              }
+              hr {}
+              h4 {
+                'Click '
+                a(href="/") {
+                  'here '
+                }
+                'to return to Home Page'
+              }
+            }
+          }
+          div.col-sm {}
+        }
+      }
+      _out.push('<!-- Javascript Import -->')
+      script(src="../js/config.js") {}
+      script(type="text/javascript") {
+        showDom("loadingAlert");
+        
+        document.onreadystatechange = function() {
+          if (document.readyState === "complete") {
+            $.ajax({
+              type: "POST",
+              url: "/api/getOrderDetails.json",
+              success: function(response, textStatus, xhr) {
+                hideDom("loadingAlert");
+                if (textStatus === "success") {
+                  console.log("Success Response:\n" + response);
+                  if (getUrlParams("commit") === "true") {
+                    showPaymentExecute(response);
+                  } else {
+                    showPaymentGet(response);
+                  }
+                } else {
+                  alert("Something went wrong");
+                }
+              }
+            });
+          }
+        };
+        
+        function showPaymentGet(res) {
+          let shipping = res.purchase_units[0].shipping;
+          let shipping_address = shipping.address;
+          console.log("Get Order result " + JSON.stringify(res));
+          console.log("shipping add " + JSON.stringify(shipping));
+          document.getElementById("confirmRecipient").innerText = shipping.name.full_name;
+          document.getElementById("confirmAddressLine1").innerText = shipping_address.address_line_1;
+          if (shipping_address.address_line_2) document.getElementById("confirmAddressLine2").innerText = shipping_address.address_line_1; else document.getElementById("confirmAddressLine2").innerText = "";
+          document.getElementById("confirmCity").innerText = shipping_address.admin_area_2;
+          document.getElementById("confirmState").innerText = shipping_address.admin_area_1;
+          document.getElementById("confirmZip").innerText = shipping_address.postal_code;
+          document.getElementById("confirmCountry").innerText = shipping_address.country_code;
+          showDom("orderConfirm");
+          document.querySelector("#confirmButton").addEventListener("click", function() {
+            let shippingMethodSelect = document.getElementById("shippingMethod"), updatedShipping = shippingMethodSelect.options[shippingMethodSelect.selectedIndex].value, currentShipping = res.purchase_units[0].amount.breakdown.shipping.value;
+            let postPatchOrderData = {
+              order_id: res.id,
+              item_amt: res.purchase_units[0].amount.breakdown.item_total.value,
+              tax_amt: res.purchase_units[0].amount.breakdown.tax_total.value,
+              handling_fee: res.purchase_units[0].amount.breakdown.handling.value,
+              insurance_fee: res.purchase_units[0].amount.breakdown.insurance.value,
+              shipping_discount: res.purchase_units[0].amount.breakdown.shipping_discount.value,
+              total_amt: res.purchase_units[0].amount.value,
+              currency: res.purchase_units[0].amount.currency_code,
+              updated_shipping: updatedShipping,
+              current_shipping: currentShipping
+            };
+            console.log("patch data: " + JSON.stringify(postPatchOrderData));
+            hideDom("orderConfirm");
+            hideDom("confirmButton");
+            showDom("loadingAlert");
+            console.log("Current shipping " + currentShipping + " and updated shipping is " + updatedShipping);
+            if (currentShipping == updatedShipping) {
+              return callPaymentCapture();
+            } else {
+              console.log("Trying patch first");
+              $.ajax({
+                type: "POST",
+                url: "/api/patchOrder.json",
+                data: postPatchOrderData,
+                success: function(response) {
+                  console.log("Patch Order Response has no content in V2: " + JSON.stringify(response));
+                  if (response.http_code === 204) return callPaymentCapture();
+                }
+              });
+            }
+          });
+        }
+        
+        function callPaymentCapture() {
+          $.ajax({
+            type: "POST",
+            url: "/api/captureOrder.json",
+            success: function(response) {
+              hideDom("orderConfirm");
+              hideDom("loadingAlert");
+              console.log("Capture Response : " + JSON.stringify(response));
+              showPaymentExecute(response);
+            },
+            error: function(err) {
+              alert("Something went wrong");
+            }
+          });
+        }
+        
+        function showPaymentExecute(result) {
+          console.log("Final Result:\n" + result);
+          document.getElementById("viewFirstName").textContent = result.payer.name.given_name;
+          document.getElementById("viewLastName").textContent = result.payer.name.surname;
+          document.getElementById("viewRecipientName").textContent = result.purchase_units[0].shipping.name.full_name;
+          document.getElementById("viewAddressLine1").textContent = result.purchase_units[0].shipping.address.address_line_1;
+          if (result.purchase_units[0].shipping.address.address_line_2) {
+            document.getElementById("viewAddressLine2").textContent = result.purchase_units[0].shipping.address.address_line_2;
+          } else {
+            document.getElementById("viewAddressLine2").textContent = "";
+          }
+          document.getElementById("viewCity").textContent = result.purchase_units[0].shipping.address.admin_area_2;
+          document.getElementById("viewState").textContent = result.purchase_units[0].shipping.address.admin_area_1;
+          document.getElementById("viewPostalCode").innerHTML = result.purchase_units[0].shipping.address.postal_code;
+          document.getElementById("viewTransactionID").textContent = result.id;
+          if (result.purchase_units[0].payments && result.purchase_units[0].payments.captures) {
+            document.getElementById("viewFinalAmount").textContent = result.purchase_units[0].payments.captures[0].amount.value;
+            document.getElementById("viewCurrency").textContent = result.purchase_units[0].payments.captures[0].amount.currency_code;
+          } else {
+            document.getElementById("viewFinalAmount").textContent = result.purchase_units[0].amount.value;
+            document.getElementById("viewCurrency").textContent = result.purchase_units[0].amount.currency_code;
+          }
+          document.getElementById("viewPaymentState").textContent = result.status;
+          if (result.intent) {
+            document.getElementById("viewTransactionType").textContent = result.intent;
+            document.getElementById("transactionType").style.display = "block";
+          } else {
+            document.getElementById("transactionType").style.display = "none";
+          }
+          hideDom("orderConfirm");
+          hideDom("loadingAlert");
+          showDom("orderView");
+        }
+      }
+      _out.push('<!-- jQuery (necessary for Bootstrap\'s JavaScript plugins) -->')
+      script(src="https://code.jquery.com/jquery.js") {}
+    }
+  }
+  env.site.serve(env, 200, Buffer.from(_out.join('')), 'success.html.jst')
+}