@fat-zebra/sdk 1.4.15 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1,2 @@
1
1
  process.env.API_ENV = 'local'
2
+ process.env.PAYNOW_BASE_URL = 'https://paynow.test'
package/README.dev.md CHANGED
@@ -109,19 +109,6 @@ Visit https://fzapplepay.ngrok.io in Safari. That's all!
109
109
 
110
110
  Webpack-dev-server supports hot reloading, meaning that code changes are reflected on the web page without restarting the server.
111
111
 
112
- ## PayPal
113
-
114
- You can build & run for PayPal integration using:
115
- ```bash
116
- npm run start:dev:paypal
117
- ```
118
-
119
- You can also change the order request in:
120
- ```bash
121
- # Change the `data` argument in the `paymentMethod` field
122
- examples/paypal/merchant.ejs
123
- ```
124
-
125
112
  ## Build Javascript
126
113
 
127
114
  There are two npm build scripts in `package.json` for building javascript files.
@@ -159,4 +146,4 @@ The release of the sdk follows a weekly schedule. In the beginning of a new rele
159
146
  10. Prepare a new git tag for the new release version `git tag -a vX.X.X`.
160
147
  11. Push git tag. `git push origin vX.X.X`.
161
148
 
162
- Upon successful CI , a new entry with title 'Merged in release/vX.X,X' will be visible in the master branch page. This provides us with a clear view of what gets released in the past. Moreoever, we can quickly find out the list of features/bug fixes in a release by referring to the PR of the release candidate.
149
+ Upon successful CI , a new entry with title 'Merged in release/vX.X,X' will be visible in the master branch page. This provides us with a clear view of what gets released in the past. Moreoever, we can quickly find out the list of features/bug fixes in a release by referring to the PR of the release candidate.
@@ -0,0 +1,12 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ // Define the source file and the destination folder
5
+ const sourceFile = path.join(__dirname, './src/styles.css');
6
+ const destinationFolder = path.join(__dirname, 'dist/' + process.env.ENVIRONMENT);
7
+ const destinationFile = path.join(destinationFolder, 'fatzebra.css');
8
+
9
+ // Copy the file
10
+ fs.copyFileSync(sourceFile, destinationFile);
11
+
12
+ console.log('File copied successfully!');
@@ -1,5 +1,8 @@
1
1
  import { PaymentIntent } from "../shared/types";
2
2
  import { ClickToPayOptions } from "./types";
3
+ export declare const CLICK_TO_PAY_DEFAULT_OPTIONS: {
4
+ [key: string]: boolean | string;
5
+ };
3
6
  interface ClickToPayModuleConfig {
4
7
  paymentIntent: PaymentIntent;
5
8
  username: string;
@@ -14,15 +17,15 @@ declare class ClickToPay {
14
17
  private iframe;
15
18
  private paymentIntent;
16
19
  private username;
17
- private cardToken;
18
20
  private postMessageClient;
19
21
  private test;
20
22
  private options;
21
23
  constructor(config: ClickToPayModuleConfig);
22
24
  load(config: ClickToPayLoadParams): void;
23
25
  getPayNowUrl(options?: {
24
- [key: string]: boolean | string;
26
+ [key: string]: any;
25
27
  }): string;
28
+ setCrossFramesEventListeners(): void;
26
29
  purchase(): void;
27
30
  }
28
31
  export default ClickToPay;
@@ -1,13 +1,20 @@
1
- import { BridgeEvent } from "../shared/types";
1
+ import { PostMessageClient } from "../shared/post-message-client";
2
+ import { BridgeEvent, PublicEvent } from "../shared/types";
2
3
  import * as util from '../shared/util';
3
- const CLICK_TO_PAY_DEFAULT_OPTIONS = {
4
+ import { emit } from "../shared/event-manager";
5
+ export const CLICK_TO_PAY_DEFAULT_OPTIONS = {
4
6
  iframe: true,
7
+ postmessage: true,
5
8
  };
6
9
  class ClickToPay {
7
10
  constructor(config) {
8
11
  this.paymentIntent = config.paymentIntent;
9
12
  this.username = config.username;
10
13
  this.test = config.test;
14
+ this.postMessageClient = new PostMessageClient({
15
+ channel: 'click_to_pay',
16
+ target: this.iframe
17
+ });
11
18
  }
12
19
  load(config) {
13
20
  this.options = config.options;
@@ -15,6 +22,9 @@ class ClickToPay {
15
22
  document.getElementById(config.containerId).appendChild(this.iframe);
16
23
  const payNowUrl = this.getPayNowUrl(config.options);
17
24
  this.iframe.setAttribute("src", payNowUrl);
25
+ this.iframe.onload = () => {
26
+ this.setCrossFramesEventListeners();
27
+ };
18
28
  }
19
29
  getPayNowUrl(options) {
20
30
  const { payment } = this.paymentIntent;
@@ -25,18 +35,53 @@ class ClickToPay {
25
35
  this.username,
26
36
  payment.reference,
27
37
  payment.currency,
28
- payment.amount,
38
+ // If amount is left as 0 (type: Number), it will be filtered out later
39
+ // So we convert to string as "0" will be allowed through the filter
40
+ // Yes, we do want $0 purchases (especially for tokenizeOnly / auth flows)
41
+ payment.amount.toString(),
29
42
  this.paymentIntent.verification
30
43
  ].filter(part => part).join('/');
31
- let queryString;
32
- if (options) {
33
- const _options = Object.assign(Object.assign({}, CLICK_TO_PAY_DEFAULT_OPTIONS), options);
34
- queryString = Object.keys(_options).map(key => {
35
- return util.toSnakeCase(key) + '=' + _options[key];
36
- }).join('&');
37
- }
38
- let searchParams = new URLSearchParams(queryString);
39
- return queryString ? `${base}?${searchParams.toString()}` : `${base}`;
44
+ let searchParams = new URLSearchParams();
45
+ const combinedOptions = Object.assign(Object.assign({}, CLICK_TO_PAY_DEFAULT_OPTIONS), options);
46
+ Object.keys(combinedOptions).map(key => {
47
+ if (combinedOptions[key] !== null && combinedOptions[key] !== undefined) {
48
+ searchParams.append(util.toSnakeCase(key), combinedOptions[key]);
49
+ }
50
+ });
51
+ return searchParams.toString().length > 0 ? `${base}?${searchParams.toString()}` : `${base}`;
52
+ }
53
+ setCrossFramesEventListeners() {
54
+ const handlers = {};
55
+ handlers[BridgeEvent.TOKENIZE_CARD_RESPONSE] = (data) => {
56
+ if (data.errors) {
57
+ emit(PublicEvent.TOKENIZATION_ERROR, {
58
+ message: 'Card tokenization failed.',
59
+ errors: data.errors,
60
+ data: null,
61
+ });
62
+ return;
63
+ }
64
+ else {
65
+ emit(PublicEvent.TOKENIZATION_SUCCESS, {
66
+ message: 'Card tokenization success.',
67
+ data
68
+ });
69
+ }
70
+ };
71
+ handlers[PublicEvent.CLICK_TO_PAY_TOKENIZATION_ERROR] = (data) => {
72
+ emit(PublicEvent.CLICK_TO_PAY_TOKENIZATION_ERROR, {
73
+ message: 'Card tokenization failed.',
74
+ errors: data.errors,
75
+ data: null,
76
+ });
77
+ };
78
+ handlers[PublicEvent.CLICK_TO_PAY_TOKENIZATION_SUCCESS] = (data) => {
79
+ emit(PublicEvent.CLICK_TO_PAY_TOKENIZATION_SUCCESS, {
80
+ message: 'Card tokenization success.',
81
+ data
82
+ });
83
+ };
84
+ this.postMessageClient.setEventListeners(handlers);
40
85
  }
41
86
  purchase() {
42
87
  const message = {
package/dist/hpp/hpp.js CHANGED
@@ -154,6 +154,8 @@ class Hpp {
154
154
  }
155
155
  setPublicEventListeners() {
156
156
  const handler = (event) => {
157
+ if (this.hppOptions.tokenizeOnly)
158
+ return;
157
159
  const threedsData = event.detail.data;
158
160
  const extra = util.toObjectWithSnakeCaseKeys(threedsData);
159
161
  this.createPurchase(extra);
@@ -0,0 +1,91 @@
1
+ .checkout-button-wrapper {
2
+ display: flex;
3
+ justify-content: center;
4
+ align-items: center;
5
+ height: 200px;
6
+ }
7
+
8
+ .iframe-checkout {
9
+ flex: 1;
10
+ border: none;
11
+ width: 100%;
12
+ height: 100%;
13
+ min-height: 0;
14
+ overflow: auto;
15
+ -webkit-overflow-scrolling: touch;
16
+ }
17
+
18
+ .iframe-foreground,
19
+ .iframe-background {
20
+ top: 0;
21
+ left: 0;
22
+ right: 0;
23
+ bottom: 0;
24
+ flex-direction: column;
25
+ }
26
+
27
+ .iframe-foreground,
28
+ .iframe-background {
29
+ position: fixed;
30
+ }
31
+
32
+ .iframe-foreground {
33
+ z-index: -1;
34
+ }
35
+
36
+ .iframe-background {
37
+ background: rgba(0, 0, 0, 0.5);
38
+ }
39
+
40
+ .iframe-foreground {
41
+ flex-grow: 1;
42
+ top: auto;
43
+ width: 100%;
44
+ max-width: 480px;
45
+ height: 80vh;
46
+ background-color: #ffffff;
47
+ border-radius: 25px 25px 0 0;
48
+ }
49
+
50
+ .slide-in .iframe-foreground {
51
+ transform: translateY(100vh);
52
+ transition: transform 0.4s ease, z-index 0.3s ease 0.4s;
53
+ z-index: -1;
54
+ }
55
+
56
+ .slide-in .iframe-background {
57
+ opacity: 0;
58
+ z-index: -1;
59
+ transition: opacity 0.3s ease, z-index 0.3s ease 0.3s;
60
+ }
61
+
62
+ .slide-in.show .iframe-foreground {
63
+ transform: none;
64
+ transition: transform 0.4s ease;
65
+ z-index: 100;
66
+ }
67
+
68
+ .slide-in.show .iframe-background {
69
+ opacity: 1;
70
+ z-index: 0;
71
+ transition: opacity 0.3s ease;
72
+ }
73
+
74
+ @media only screen and (min-width: 480px) {
75
+ .iframe-foreground {
76
+ margin: 0 auto;
77
+ }
78
+ }
79
+
80
+ @media only screen and (min-width: 768px) {
81
+ .iframe-foreground {
82
+ margin: 0;
83
+ width: 400px;
84
+ height: 100vh;
85
+ left: 0;
86
+ }
87
+
88
+ .slide-in .iframe-foreground {
89
+ transform: translateX(-400px);
90
+ }
91
+ }