tonder-web-sdk 1.15.2 → 1.16.3
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.
- package/.husky/pre-commit +4 -0
- package/.prettierignore +8 -0
- package/.prettierrc +10 -0
- package/README.md +189 -35
- package/eslint.config.mjs +15 -0
- package/package.json +21 -4
- package/src/classes/3dsHandler.js +58 -62
- package/src/classes/BaseInlineCheckout.js +21 -36
- package/src/classes/LiteInlineCheckout.js +8 -8
- package/src/classes/checkout.js +75 -71
- package/src/classes/globalLoader.js +9 -7
- package/src/classes/inlineCheckout.js +528 -250
- package/src/data/apmApi.js +8 -14
- package/src/data/businessApi.js +5 -8
- package/src/data/cardApi.js +5 -14
- package/src/data/checkoutApi.js +54 -54
- package/src/data/customerApi.js +1 -6
- package/src/data/index.js +15 -15
- package/src/data/openPayApi.js +7 -7
- package/src/data/skyflowApi.js +14 -16
- package/src/helpers/skyflow.js +210 -119
- package/src/helpers/styles.js +56 -27
- package/src/helpers/template-skeleton.js +1 -1
- package/src/helpers/template.js +984 -541
- package/src/helpers/utils.js +152 -58
- package/src/helpers/validations.js +34 -35
- package/src/index-dev.js +38 -11
- package/src/index.html +20 -12
- package/src/index.js +19 -13
- package/src/shared/catalog/commonLogosCatalog.js +7 -0
- package/src/shared/catalog/paymentMethodsCatalog.js +242 -243
- package/src/shared/constants/colors.js +15 -0
- package/src/shared/constants/displayMode.js +4 -0
- package/src/shared/constants/fieldPathNames.js +4 -0
- package/src/shared/constants/htmlTonderIds.js +18 -0
- package/src/shared/constants/messages.js +10 -9
- package/types/card.d.ts +17 -17
- package/types/checkout.d.ts +85 -87
- package/types/common.d.ts +4 -1
- package/types/customer.d.ts +10 -10
- package/types/index.d.ts +9 -11
- package/types/inlineCheckout.d.ts +81 -61
- package/types/liteInlineCheckout.d.ts +78 -83
- package/types/paymentMethod.d.ts +17 -17
- package/types/transaction.d.ts +94 -94
- package/v1/bundle.min.js +3 -3
|
@@ -13,6 +13,7 @@ import { getBrowserInfo, injectMercadoPagoSecurity } from "../helpers/utils";
|
|
|
13
13
|
export class BaseInlineCheckout {
|
|
14
14
|
baseUrl = "";
|
|
15
15
|
cartTotal = "0";
|
|
16
|
+
secureToken = "";
|
|
16
17
|
constructor({ mode = "stage", apiKey, returnUrl, callBack = () => {} }) {
|
|
17
18
|
this.apiKeyTonder = apiKey;
|
|
18
19
|
this.returnUrl = returnUrl;
|
|
@@ -33,8 +34,8 @@ export class BaseInlineCheckout {
|
|
|
33
34
|
* @public
|
|
34
35
|
*/
|
|
35
36
|
configureCheckout(data) {
|
|
36
|
-
if ("customer" in data) this.#handleCustomer(data["customer"]);
|
|
37
37
|
if ("secureToken" in data) this.#handleSecureToken(data["secureToken"]);
|
|
38
|
+
this.#setCheckoutData(data);
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
/**
|
|
@@ -49,7 +50,7 @@ export class BaseInlineCheckout {
|
|
|
49
50
|
this.process3ds.setPayload(resultCheckout);
|
|
50
51
|
const response = await this.#handle3dsRedirect(resultCheckout);
|
|
51
52
|
globalLoader.remove();
|
|
52
|
-
return response
|
|
53
|
+
return response;
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
/**
|
|
@@ -66,12 +67,7 @@ export class BaseInlineCheckout {
|
|
|
66
67
|
payment(data) {
|
|
67
68
|
return new Promise(async (resolve, reject) => {
|
|
68
69
|
try {
|
|
69
|
-
this.#
|
|
70
|
-
this._setCartTotal(data.cart?.total);
|
|
71
|
-
this.#setCartItems(data.cart?.items);
|
|
72
|
-
this.#handleMetadata(data);
|
|
73
|
-
this.#handleCurrency(data);
|
|
74
|
-
this.#handleCard(data);
|
|
70
|
+
this.#setCheckoutData(data);
|
|
75
71
|
const response = await this._checkout(data);
|
|
76
72
|
this.process3ds.setPayload(response);
|
|
77
73
|
this.callBack(response);
|
|
@@ -94,24 +90,15 @@ export class BaseInlineCheckout {
|
|
|
94
90
|
}
|
|
95
91
|
|
|
96
92
|
async _getCustomer(customer, signal) {
|
|
97
|
-
return await registerOrFetchCustomer(
|
|
98
|
-
this.baseUrl,
|
|
99
|
-
this.apiKeyTonder,
|
|
100
|
-
customer,
|
|
101
|
-
signal,
|
|
102
|
-
);
|
|
93
|
+
return await registerOrFetchCustomer(this.baseUrl, this.apiKeyTonder, customer, signal);
|
|
103
94
|
}
|
|
104
95
|
|
|
105
96
|
async _checkout() {
|
|
106
|
-
throw new Error(
|
|
107
|
-
"The #checkout method should be implement in child classes.",
|
|
108
|
-
);
|
|
97
|
+
throw new Error("The #checkout method should be implement in child classes.");
|
|
109
98
|
}
|
|
110
99
|
|
|
111
100
|
_setCartTotal(total) {
|
|
112
|
-
throw new Error(
|
|
113
|
-
"The #setCartTotal method should be implement in child classes.",
|
|
114
|
-
);
|
|
101
|
+
throw new Error("The #setCartTotal method should be implement in child classes.");
|
|
115
102
|
}
|
|
116
103
|
|
|
117
104
|
async _handleCheckout({ card, payment_method, customer }) {
|
|
@@ -119,11 +106,7 @@ export class BaseInlineCheckout {
|
|
|
119
106
|
const total = Number(this.cartTotal);
|
|
120
107
|
try {
|
|
121
108
|
let deviceSessionIdTonder;
|
|
122
|
-
if (
|
|
123
|
-
!deviceSessionIdTonder &&
|
|
124
|
-
openpay_keys.merchant_id &&
|
|
125
|
-
openpay_keys.public_key
|
|
126
|
-
) {
|
|
109
|
+
if (!deviceSessionIdTonder && openpay_keys.merchant_id && openpay_keys.public_key) {
|
|
127
110
|
deviceSessionIdTonder = await getOpenpayDeviceSessionID(
|
|
128
111
|
openpay_keys.merchant_id,
|
|
129
112
|
openpay_keys.public_key,
|
|
@@ -144,11 +127,7 @@ export class BaseInlineCheckout {
|
|
|
144
127
|
is_oneclick: true,
|
|
145
128
|
items: this.cartItems,
|
|
146
129
|
};
|
|
147
|
-
const jsonResponseOrder = await createOrder(
|
|
148
|
-
this.baseUrl,
|
|
149
|
-
this.apiKeyTonder,
|
|
150
|
-
orderItems,
|
|
151
|
-
);
|
|
130
|
+
const jsonResponseOrder = await createOrder(this.baseUrl, this.apiKeyTonder, orderItems);
|
|
152
131
|
|
|
153
132
|
// Create payment
|
|
154
133
|
const now = new Date();
|
|
@@ -214,6 +193,16 @@ export class BaseInlineCheckout {
|
|
|
214
193
|
}
|
|
215
194
|
}
|
|
216
195
|
|
|
196
|
+
#setCheckoutData(data) {
|
|
197
|
+
if (!data) return;
|
|
198
|
+
this.#handleCustomer(data.customer);
|
|
199
|
+
this._setCartTotal(data.cart?.total);
|
|
200
|
+
this.#setCartItems(data.cart?.items);
|
|
201
|
+
this.#handleMetadata(data);
|
|
202
|
+
this.#handleCurrency(data);
|
|
203
|
+
this.#handleCard(data);
|
|
204
|
+
}
|
|
205
|
+
|
|
217
206
|
async #fetchMerchantData() {
|
|
218
207
|
this.merchantData = await fetchBusiness(
|
|
219
208
|
this.baseUrl,
|
|
@@ -239,11 +228,7 @@ export class BaseInlineCheckout {
|
|
|
239
228
|
checkout_id: response?.checkout?.id,
|
|
240
229
|
};
|
|
241
230
|
try {
|
|
242
|
-
return await startCheckoutRouter(
|
|
243
|
-
this.baseUrl,
|
|
244
|
-
this.apiKeyTonder,
|
|
245
|
-
routerItems,
|
|
246
|
-
);
|
|
231
|
+
return await startCheckoutRouter(this.baseUrl, this.apiKeyTonder, routerItems);
|
|
247
232
|
} catch (error) {
|
|
248
233
|
// throw error
|
|
249
234
|
} finally {
|
|
@@ -290,7 +275,7 @@ export class BaseInlineCheckout {
|
|
|
290
275
|
}
|
|
291
276
|
|
|
292
277
|
async #handle3dsRedirect(response) {
|
|
293
|
-
console.log(
|
|
278
|
+
console.log("Handling 3DS redirect...");
|
|
294
279
|
const iframe = response?.next_action?.iframe_resources?.iframe;
|
|
295
280
|
const threeDsChallenge = response?.next_action?.three_ds_challenge;
|
|
296
281
|
|
|
@@ -42,11 +42,12 @@ export class LiteInlineCheckout extends BaseInlineCheckout {
|
|
|
42
42
|
const response = await fetchCustomerCards(
|
|
43
43
|
this.baseUrl,
|
|
44
44
|
auth_token,
|
|
45
|
+
this.secureToken,
|
|
45
46
|
this.merchantData.business.pk,
|
|
46
47
|
);
|
|
47
48
|
return {
|
|
48
49
|
...response,
|
|
49
|
-
cards: response.cards.map(
|
|
50
|
+
cards: response.cards.map(ic => ({
|
|
50
51
|
...ic,
|
|
51
52
|
icon: getCardType(ic.fields.card_scheme),
|
|
52
53
|
})),
|
|
@@ -87,6 +88,7 @@ export class LiteInlineCheckout extends BaseInlineCheckout {
|
|
|
87
88
|
return await saveCustomerCard(
|
|
88
89
|
this.baseUrl,
|
|
89
90
|
auth_token,
|
|
91
|
+
this.secureToken,
|
|
90
92
|
business?.pk,
|
|
91
93
|
skyflowTokens,
|
|
92
94
|
);
|
|
@@ -117,6 +119,7 @@ export class LiteInlineCheckout extends BaseInlineCheckout {
|
|
|
117
119
|
return await removeCustomerCard(
|
|
118
120
|
this.baseUrl,
|
|
119
121
|
auth_token,
|
|
122
|
+
this.secureToken,
|
|
120
123
|
skyflowId,
|
|
121
124
|
business?.pk,
|
|
122
125
|
);
|
|
@@ -148,8 +151,8 @@ export class LiteInlineCheckout extends BaseInlineCheckout {
|
|
|
148
151
|
: [];
|
|
149
152
|
|
|
150
153
|
return apms_results
|
|
151
|
-
.filter(
|
|
152
|
-
.map(
|
|
154
|
+
.filter(apmItem => apmItem.category.toLowerCase() !== "cards")
|
|
155
|
+
.map(apmItem => {
|
|
153
156
|
const apm = {
|
|
154
157
|
id: apmItem.pk,
|
|
155
158
|
payment_method: apmItem.payment_method,
|
|
@@ -175,10 +178,7 @@ export class LiteInlineCheckout extends BaseInlineCheckout {
|
|
|
175
178
|
}
|
|
176
179
|
|
|
177
180
|
async _checkout({ card, payment_method }) {
|
|
178
|
-
const customer = await this._getCustomer(
|
|
179
|
-
this.customer,
|
|
180
|
-
this.abortController.signal,
|
|
181
|
-
);
|
|
181
|
+
const customer = await this._getCustomer(this.customer, this.abortController.signal);
|
|
182
182
|
const { vault_id, vault_url } = this.merchantData;
|
|
183
183
|
let skyflowTokens;
|
|
184
184
|
if (!payment_method || payment_method !== "" || payment_method === null) {
|
|
@@ -190,7 +190,7 @@ export class LiteInlineCheckout extends BaseInlineCheckout {
|
|
|
190
190
|
skyflowTokens = await getSkyflowTokens({
|
|
191
191
|
vault_id: vault_id,
|
|
192
192
|
vault_url: vault_url,
|
|
193
|
-
data: {...card, card_number: card.card_number.replace(/\s+/g,
|
|
193
|
+
data: { ...card, card_number: card.card_number.replace(/\s+/g, "") },
|
|
194
194
|
baseUrl: this.baseUrl,
|
|
195
195
|
apiKey: this.apiKeyTonder,
|
|
196
196
|
});
|
package/src/classes/checkout.js
CHANGED
|
@@ -4,80 +4,84 @@ export class Checkout {
|
|
|
4
4
|
constructor({
|
|
5
5
|
apiKey,
|
|
6
6
|
type = "payment",
|
|
7
|
-
backgroundColor="#141414",
|
|
8
|
-
color="#EBEBEB",
|
|
9
|
-
cb=()=>{},
|
|
10
|
-
url="http://checkout.tonder.io/#/"
|
|
7
|
+
backgroundColor = "#141414",
|
|
8
|
+
color = "#EBEBEB",
|
|
9
|
+
cb = () => {},
|
|
10
|
+
url = "http://checkout.tonder.io/#/",
|
|
11
11
|
}) {
|
|
12
|
-
this.url = url
|
|
13
|
-
this.apiKey = apiKey
|
|
14
|
-
this.type = type
|
|
15
|
-
this.backgroundColor = backgroundColor
|
|
16
|
-
this.color = color
|
|
17
|
-
this.params = ""
|
|
18
|
-
this.order = {}
|
|
19
|
-
this.buttonText = "Proceder al pago"
|
|
20
|
-
this.cb = cb
|
|
12
|
+
this.url = url;
|
|
13
|
+
this.apiKey = apiKey;
|
|
14
|
+
this.type = type;
|
|
15
|
+
this.backgroundColor = backgroundColor;
|
|
16
|
+
this.color = color;
|
|
17
|
+
this.params = "";
|
|
18
|
+
this.order = {};
|
|
19
|
+
this.buttonText = "Proceder al pago";
|
|
20
|
+
this.cb = cb;
|
|
21
21
|
|
|
22
22
|
window.addEventListener("message", this.receiveMessage.bind(this), false);
|
|
23
23
|
}
|
|
24
|
-
generateButton =
|
|
25
|
-
this.buttonText = buttonText ? buttonText : this.buttonText
|
|
26
|
-
this.tonderButton = document.createElement(
|
|
24
|
+
generateButton = buttonText => {
|
|
25
|
+
this.buttonText = buttonText ? buttonText : this.buttonText;
|
|
26
|
+
this.tonderButton = document.createElement("button");
|
|
27
27
|
this.tonderButton.innerHTML = this.buttonText;
|
|
28
|
-
this.stylishButton(this.tonderButton)
|
|
29
|
-
this.tonderButton.onclick = this.openCheckout
|
|
30
|
-
}
|
|
31
|
-
getButton = ({buttonText}) => {
|
|
32
|
-
this.generateButton(buttonText)
|
|
33
|
-
return this.tonderButton
|
|
34
|
-
}
|
|
35
|
-
mountButton = ({buttonText}) => {
|
|
36
|
-
this.generateButton(buttonText)
|
|
37
|
-
const entryPoint = document.getElementById("tonder-checkout")
|
|
28
|
+
this.stylishButton(this.tonderButton);
|
|
29
|
+
this.tonderButton.onclick = this.openCheckout;
|
|
30
|
+
};
|
|
31
|
+
getButton = ({ buttonText }) => {
|
|
32
|
+
this.generateButton(buttonText);
|
|
33
|
+
return this.tonderButton;
|
|
34
|
+
};
|
|
35
|
+
mountButton = ({ buttonText }) => {
|
|
36
|
+
this.generateButton(buttonText);
|
|
37
|
+
const entryPoint = document.getElementById("tonder-checkout");
|
|
38
38
|
try {
|
|
39
|
-
entryPoint.innerHTML = ""
|
|
40
|
-
entryPoint.append(this.tonderButton)
|
|
41
|
-
} catch(error) {
|
|
42
|
-
console.error(error)
|
|
39
|
+
entryPoint.innerHTML = "";
|
|
40
|
+
entryPoint.append(this.tonderButton);
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.error(error);
|
|
43
43
|
}
|
|
44
|
-
}
|
|
45
|
-
stylishButton =
|
|
46
|
-
element.style.backgroundColor = this.backgroundColor
|
|
47
|
-
element.style.color = this.color
|
|
48
|
-
element.style.display =
|
|
49
|
-
element.style.justifyContent =
|
|
50
|
-
element.style.border =
|
|
51
|
-
element.style.padding =
|
|
52
|
-
element.style.borderRadius =
|
|
53
|
-
element.style.fontSize =
|
|
54
|
-
element.style.width =
|
|
55
|
-
element.style.boxShadow =
|
|
56
|
-
}
|
|
57
|
-
setOrder = ({products, email, shippingCost }) => {
|
|
58
|
-
let _order = {}
|
|
59
|
-
if (products) _order.products = products
|
|
60
|
-
if (email) _order.email = email
|
|
61
|
-
if (shippingCost) _order.shippingCost = shippingCost
|
|
62
|
-
this.order = {...this.order, ..._order}
|
|
63
|
-
return this.order
|
|
64
|
-
}
|
|
44
|
+
};
|
|
45
|
+
stylishButton = element => {
|
|
46
|
+
element.style.backgroundColor = this.backgroundColor;
|
|
47
|
+
element.style.color = this.color;
|
|
48
|
+
element.style.display = "flex";
|
|
49
|
+
element.style.justifyContent = "center";
|
|
50
|
+
element.style.border = "none";
|
|
51
|
+
element.style.padding = "1rem";
|
|
52
|
+
element.style.borderRadius = "10px";
|
|
53
|
+
element.style.fontSize = "1rem";
|
|
54
|
+
element.style.width = "100%";
|
|
55
|
+
element.style.boxShadow = "0 3px 6px 0 rgba(0,0,0,0.16)";
|
|
56
|
+
};
|
|
57
|
+
setOrder = ({ products, email, shippingCost }) => {
|
|
58
|
+
let _order = {};
|
|
59
|
+
if (products) _order.products = products;
|
|
60
|
+
if (email) _order.email = email;
|
|
61
|
+
if (shippingCost) _order.shippingCost = shippingCost;
|
|
62
|
+
this.order = { ...this.order, ..._order };
|
|
63
|
+
return this.order;
|
|
64
|
+
};
|
|
65
65
|
openTabListener = (tab, button) => {
|
|
66
66
|
const tabInterval = setInterval(() => {
|
|
67
67
|
if (tab.closed) {
|
|
68
68
|
clearInterval(tabInterval);
|
|
69
|
-
button.disabled = false
|
|
70
|
-
button.innerHTML = this.buttonText
|
|
69
|
+
button.disabled = false;
|
|
70
|
+
button.innerHTML = this.buttonText;
|
|
71
71
|
}
|
|
72
|
-
}, 500)
|
|
73
|
-
}
|
|
72
|
+
}, 500);
|
|
73
|
+
};
|
|
74
74
|
openCheckout = () => {
|
|
75
|
-
const queryString = this.getUrlParams()
|
|
76
|
-
const encrypted = AES.encrypt(queryString,
|
|
75
|
+
const queryString = this.getUrlParams();
|
|
76
|
+
const encrypted = AES.encrypt(queryString, "url-params-encrypt").toString();
|
|
77
77
|
const encodedURL = encodeURIComponent(encrypted);
|
|
78
78
|
this.params = "?" + encodedURL;
|
|
79
|
-
const newWindow = window.open(
|
|
80
|
-
|
|
79
|
+
const newWindow = window.open(
|
|
80
|
+
this.url + this.params,
|
|
81
|
+
"_blank",
|
|
82
|
+
`width=1200,height=$800,left=0,top=0`,
|
|
83
|
+
);
|
|
84
|
+
this.tonderButton.disabled = true;
|
|
81
85
|
this.tonderButton.innerHTML = `
|
|
82
86
|
<div class="loader"></div>
|
|
83
87
|
<style>
|
|
@@ -102,24 +106,24 @@ export class Checkout {
|
|
|
102
106
|
100% { transform: rotate(360deg); }
|
|
103
107
|
}
|
|
104
108
|
</style>
|
|
105
|
-
|
|
106
|
-
this.openTabListener(newWindow, this.tonderButton)
|
|
107
|
-
}
|
|
109
|
+
`;
|
|
110
|
+
this.openTabListener(newWindow, this.tonderButton);
|
|
111
|
+
};
|
|
108
112
|
getUrlParams = () => {
|
|
109
|
-
const params = { apiKey: this.apiKey, ...this.order, type: this.type}
|
|
113
|
+
const params = { apiKey: this.apiKey, ...this.order, type: this.type };
|
|
110
114
|
if (params.products) {
|
|
111
|
-
params.products = JSON.stringify(params.products)
|
|
115
|
+
params.products = JSON.stringify(params.products);
|
|
112
116
|
}
|
|
113
117
|
const queryString = new URLSearchParams(params).toString();
|
|
114
|
-
return queryString
|
|
115
|
-
}
|
|
118
|
+
return queryString;
|
|
119
|
+
};
|
|
116
120
|
receiveMessage(event) {
|
|
117
121
|
// Parse data if it is possible, in case of error it will return the raw data.
|
|
118
122
|
try {
|
|
119
|
-
const data = JSON.parse(event.data)
|
|
120
|
-
this.cb(data)
|
|
121
|
-
} catch(error) {
|
|
122
|
-
this.cb(event.data)
|
|
123
|
+
const data = JSON.parse(event.data);
|
|
124
|
+
this.cb(data);
|
|
125
|
+
} catch (error) {
|
|
126
|
+
this.cb(event.data);
|
|
123
127
|
}
|
|
124
128
|
}
|
|
125
|
-
}
|
|
129
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { cardTemplateSkeleton } from
|
|
1
|
+
import { cardTemplateSkeleton } from "../helpers/template-skeleton.js";
|
|
2
|
+
import { HTML_IDS } from "../shared/constants/htmlTonderIds";
|
|
2
3
|
|
|
3
4
|
class GlobalLoader {
|
|
4
5
|
constructor() {
|
|
@@ -7,10 +8,10 @@ class GlobalLoader {
|
|
|
7
8
|
|
|
8
9
|
show() {
|
|
9
10
|
this.requestCount++;
|
|
10
|
-
const checkoutContainer = document.querySelector(
|
|
11
|
+
const checkoutContainer = document.querySelector(`#${HTML_IDS.globalLoader}`);
|
|
11
12
|
if (checkoutContainer) {
|
|
12
13
|
checkoutContainer.innerHTML = cardTemplateSkeleton;
|
|
13
|
-
checkoutContainer.style.display =
|
|
14
|
+
checkoutContainer.style.display = "block";
|
|
14
15
|
}
|
|
15
16
|
}
|
|
16
17
|
|
|
@@ -18,10 +19,11 @@ class GlobalLoader {
|
|
|
18
19
|
this.requestCount--;
|
|
19
20
|
if (this.requestCount <= 0) {
|
|
20
21
|
this.requestCount = 0;
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
const loaders = document.querySelectorAll(`#${HTML_IDS.globalLoader}`);
|
|
23
|
+
|
|
24
|
+
loaders.forEach(loader => {
|
|
25
|
+
loader.style.display = "none";
|
|
26
|
+
});
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
}
|