Skip to content

Commit

Permalink
Release 2.0.0.
Browse files Browse the repository at this point in the history
  • Loading branch information
WorldlineConnect committed Mar 19, 2024
1 parent 266da08 commit 58721e7
Show file tree
Hide file tree
Showing 196 changed files with 24,589 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
@@ -0,0 +1,4 @@
debug.log
npm-debug.log
.idea/
*.iml
9 changes: 9 additions & 0 deletions README.md
@@ -0,0 +1,9 @@
# Connect Client SDK Examples

This repository contains all SDK examples for the [Worldline Connect JavaScript Client SDK](https://docs.connect.worldline-solutions.com/documentation/sdk/mobile/javascript/).
Refer to the README in each folder for more details about that specific example.

## Full vs. minimal

Full examples offer a fully working payment flow that mimics all the functionality that the hosted payment pages offer.
The minimal examples show you how to include the SDK with a module loader.
1 change: 1 addition & 0 deletions full-angularjs/.gitattributes
@@ -0,0 +1 @@
* text=auto
8 changes: 8 additions & 0 deletions full-angularjs/.gitignore
@@ -0,0 +1,8 @@
.tmp/
coverage/
dist/
node_modules/
jspm_packages/
bower_components/
npm-debug*
package-lock.json
1 change: 1 addition & 0 deletions full-angularjs/.npmrc
@@ -0,0 +1 @@
package-lock=false
118 changes: 118 additions & 0 deletions full-angularjs/README.md
@@ -0,0 +1,118 @@
# Angularjs (1.x) Connect Client SDK Example

🚨 Please note that this example is only compatible with SDK versions up to major version 4.
To learn how to work with the SDK version 5+, please refer to the documentation
on https://docs.connect.worldline-solutions.com/documentation/sdk/mobile/javascript/.

### What is it?

This application is an angularjs implementation of an Worldline Connect checkout process. You can use this application as a base for your own angularjs intergrated Worldline Connect powered payment solution.
It offers all features of the [Worldline Connect Responsive Payment Pages (RPP)](https://docs.connect.worldline-solutions.com/documentation/hosted-payment-pages/), including
* payment product selection
* payment product detail pages
* co-branded cards support
* payment product grouping
* payment product switching based on IIN Lookup

and more.
The [Worldline Connect JavaScript Client SDK](https://github.com/Worldline-Global-Collect/connect-sdk-client-js) is used for all communication to the Worldline Connect Server API and crypto.
A simple webserver is included to make this application easy to install and run in development environments. See the [Worldline Connect Developer Hub](https://docs.connect.worldline-solutions.com/documentation/sdk/mobile/javascript/)
for more information on how to use the Worldline Connect Client API.

### How to install

Make sure you have installed [Node.js](https://nodejs.org/en/); the LTS version is recommended. Run

```bash
npm install
```

### How to start the application

Run the following command to start a webserver on `localhost` at port `3000` with [browsersync](https://www.browsersync.io/).
This will also start a watcher for the [sass](http://sass-lang.com/) files that auto compile to CSS; after each change the page is automatically reloaded for you on all connected devices.

```bash
npm run start
```

When the webserver has started it will automatically load a page in which you have to provide details about the Worldline Connect client session and the payment details.
This page is for example and development purposes only. Notice that the URL contains the `dev-` prefix indicating is a development page. In your production application this information is used to initialize the application.
The final page of the payment journey has a `dev-` prefix as well and contains the encrypted string containing all information that you need to send to Worldline to for-fill the payment.

### How to start the payment process

Create a client session identifier and a customer identifier, which the Client API needs for authentication purposes.
These can be obtained by your e-commerce server using the [Server SDKs](https://docs.connect.worldline-solutions.com/documentation/sdk/server/) or directly using the [Server API](https://apireference.connect.worldline-solutions.com/s2sapi/v1/en_US/index.html).
Use this information along with the geographical region of the Client API you want to connect to and the payment details to start the process.
If you incorporate this into your production process all this information should be used to initialize the payment process.

### In depth

This application uses the following key frameworks and libraries which are managed by npm:
* Angularjs
* Twitter Bootstrap
* DigitalBazaar Forge
* Worldline Connect Client SDK

### Other npm commands

| Command | Description |
|:----------------------|:---------------------------------------------------|
| `npm run build:sass` | builds all css files; once |
| `npm run browsersync` | starts the webserver with browser-sync |
| `npm run postinstall` | automatically run after install (clean&build:sass) |
| `npm run watch:sass` | watch sass changes |

### Folder structure

```
+-- app
| +-- js
| -- app.js - main controller with routing
| +-- payment-detail
| +-- directives
| +-- connect
| -- cardnumber.directive.js - directive which has all logic for cardnumber switchinh
| -- validation.directive.js - directive that binds Connect-sdk validation methods to angular.js
| +-- templates
| -- cards.html - specific template for card payments; since card payments have a lot of extra features compared to the other paymentmethods
| -- input-currency.html - template for currency based input fields
| -- input-default.html - template for input based fields
| -- input-select.html - template for dropdown based fields
| -- remember-me.html - template holding the account on file checkbox
| -- tooltip.html - template with the specific tooltip for a field (if present)
| -- paymentitem-detail.html - template for the payment form; this will load subtemplates on demand from the templates folder
| -- paymentitem-detail.controller.js - control logic for the payment form
| +-- payment-selection
| -- payment-selection.html - template for the payment selection form
| -- payment-selection.controller.js - control logic for the payment selection form
| +-- results
| -- failure.html - result page; failure
| -- success.html - result page; success; this page prints the encrypted blob you can send to Worldline Connect.
| +-- sessiondetails
| -- sessiondetails.html - this page provides the payment- and sessiondetails.
| -- sessiondetails.controller.js - control logic for the sessiondetails page
| +-- styles
| -- contains all sass files needed to compile the css file used with this demo
+-- fonts
| +-- icons
| -- icons.eot/icons.svg/icons.ttf/icons.woff - icons that are used in the cards form
+-- global
| +-- images
| -- loader.png - loading spinner
| -- logo.png - example logo
+-- node_modules
| ... folder containing all node dependencies; run npm install to get the dependencies
+-- styles
| +-- img
| ... folder containing all images used by the CSS
| -- base.css - the compiled css file; use npm run build:sass to compile this file
| -- forms.css - overrides for forms; this is purely used in this example; production code should use a better method to handle the displaying of validation errors
```

### Module loading

This example focuses on displaying how to integrate the Worldline Connect JavaScript Client SDK with angularjs.
Module loading is out of scope of this example.
Refer to the various minimal examples on how to use module loading.
35 changes: 35 additions & 0 deletions full-angularjs/app/js/app.js
@@ -0,0 +1,35 @@
var app = angular.module('app', ['ngRoute', 'ui.bootstrap', 'ui.mask', 'connect.validation', 'connect.cardnumber', 'connect.GooglePay']);

app.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/paymentitem-selection', {
templateUrl: 'app/paymentitem-selection/paymentitem-selection.html',
requiresSession: false
}).when('/paymentitem-detail/:type/:id/:aof?', {
templateUrl: 'app/paymentitem-detail/paymentitem-detail.html',
requiresSession: false
}).when('/dev-sessiondetails', {
templateUrl: 'app/sessiondetails/sessiondetails.html',
requiresSession: false
}).when('/dev-success', {
templateUrl: 'app/results/success.html',
requiresSession: true
}).when('/dev-failure', {
templateUrl: 'app/results/failure.html',
requiresSession: true
}).otherwise({
templateUrl: 'app/sessiondetails/sessiondetails.html',
requiresSession: false
});
}]);

app.run(['$rootScope', '$location', function ($rootScope, $location) {
$rootScope.$on('$routeChangeStart', function (event, next, current) {
if (next.requiresSession && !$rootScope.hasSession) {
$location.path('/dev-sessiondetails');
}
});
}]);

app.controller('app', ['$scope', '$rootScope', '$location', function ($scope, $rootScope, $location) {
$rootScope.loading = false;
}]);
@@ -0,0 +1,98 @@
angular.module('connect.cardnumber', []).directive('connectCardNumber', function () {
return {
priority: 101,
require: 'ngModel',
restrict: 'A',
compile: function connectCardnumberCompilingFunction() {

var $scope;

return function connectCardnumberLinkingFunction(scope, iElement, iAttrs, controller) {
$scope = scope.$parent.$parent.$parent.$parent.$parent; // this is the paymentitem.controller
if (iAttrs.connectCardNumber === 'cardNumber') {
$scope.$watch(function () {
return controller.$$rawModelValue;
}, function (value) {
if (checkBINLength(value)) {
var newBIN = extractBin(value);
getIinDetails(newBIN);
}
});
}
};

function checkBINLength(value) {
var ret = false;
if (value) {
var newBIN = extractBin(value);
if (newBIN !== $scope.currentBIN) {
$scope.currentBIN = newBIN;
ret = true;
}
}
return ret;
}

function extractBin(value) {
var newBIN;
if (value.length >= 8) {
newBIN = value.substring(0, 8);
} else {
newBIN = value.substring(0, 6);
}
return newBIN;
}

function getIinDetails(value) {
$scope.connect.session.getIinDetails(value, $scope.connect.paymentDetails).then(function (response) {
$scope.$apply(function () {
$scope.iinDetails = response;
$scope.ccstate = response.status;
if (response.status === "SUPPORTED") {
handleSupportedResponse(response);
}
});
}, function () {
$scope.$apply(function () {
$scope.ccstate = "ERROR";
});
});
}

function handleSupportedResponse(response) {
// this card is supported; switch to the card
$scope.getPaymentProduct(response.paymentProductId).then(function (paymentProduct) {
$scope.$apply(function () {
$scope.hasCobrand = false;
$scope.setProduct(paymentProduct.id);
// enrich the cobrands response
if (response.coBrands) {
handleCobrand(response);
}
});
});
};

function handleCobrand(response) {
var cobrandCount = 0;
angular.forEach(response.coBrands, function (cobrand) {
var paymentProductId = cobrand.paymentProductId;
if (cobrand.isAllowedInContext) {
$scope.paymentProductDisplayHints = $scope.paymentProductDisplayHints || {};
cobrandCount++;
if (!$scope.paymentProductDisplayHints[paymentProductId]) {
$scope.getPaymentProduct(paymentProductId).then(function (paymentProduct) {
$scope.$apply(function () {
$scope.paymentProductDisplayHints[paymentProductId] = paymentProduct.displayHints;
});
});
}
}
});
if (cobrandCount > 1) {
$scope.hasCobrand = true;
}
}
}
}
});
@@ -0,0 +1,48 @@
angular.module('connect.validation', []).directive('connectValidation', function () {
return {
priority: 100,
require: 'ngModel',
restrict: 'A',
compile: function connectValidationCompilingFunction() {

return function connectValidationLinkingFunction(scope, iElement, iAttrs, controller) {
var addValidations = function (field) {
/* Add validators based on the dataRestrictions */
angular.forEach(field.dataRestrictions.validationRules, function (validationRule) {
controller.$validators[validationRule.type] = function (modelValue, viewValue) {
if (validationRule.type !== 'boletoBancarioRequiredness') {
if (modelValue) {
return validationRule.validate(modelValue);
} else {
return true;
}
} else {
return validationRule.validate(modelValue || '', scope.item['fiscalNumber'] || '');
}
};
});
}
var field = scope.paymentitem.paymentProductFieldById[scope.paymentItemFieldId || scope.paymentItemfield.id]

scope.$watch(iAttrs.connectValidation, function (n, o) {
if (n !== o) {
field = scope.paymentitem.paymentProductFieldById[scope.paymentItemFieldId || scope.paymentItemfield.id];
addValidations(field);
}
});
addValidations(field);

scope.$watch(function () {
return scope.item && scope.item['fiscalNumber']
}, function (n, o) {
// recheck requiredness of the other fields
if (n) {
scope.paymentform.firstName && scope.paymentform.firstName.$validate();
scope.paymentform.surname && scope.paymentform.surname.$validate();
scope.paymentform.companyName && scope.paymentform.companyName.$validate();
}
});
}
}
}
});

0 comments on commit 58721e7

Please sign in to comment.