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.
Files changed (46) hide show
  1. package/.husky/pre-commit +4 -0
  2. package/.prettierignore +8 -0
  3. package/.prettierrc +10 -0
  4. package/README.md +189 -35
  5. package/eslint.config.mjs +15 -0
  6. package/package.json +21 -4
  7. package/src/classes/3dsHandler.js +58 -62
  8. package/src/classes/BaseInlineCheckout.js +21 -36
  9. package/src/classes/LiteInlineCheckout.js +8 -8
  10. package/src/classes/checkout.js +75 -71
  11. package/src/classes/globalLoader.js +9 -7
  12. package/src/classes/inlineCheckout.js +528 -250
  13. package/src/data/apmApi.js +8 -14
  14. package/src/data/businessApi.js +5 -8
  15. package/src/data/cardApi.js +5 -14
  16. package/src/data/checkoutApi.js +54 -54
  17. package/src/data/customerApi.js +1 -6
  18. package/src/data/index.js +15 -15
  19. package/src/data/openPayApi.js +7 -7
  20. package/src/data/skyflowApi.js +14 -16
  21. package/src/helpers/skyflow.js +210 -119
  22. package/src/helpers/styles.js +56 -27
  23. package/src/helpers/template-skeleton.js +1 -1
  24. package/src/helpers/template.js +984 -541
  25. package/src/helpers/utils.js +152 -58
  26. package/src/helpers/validations.js +34 -35
  27. package/src/index-dev.js +38 -11
  28. package/src/index.html +20 -12
  29. package/src/index.js +19 -13
  30. package/src/shared/catalog/commonLogosCatalog.js +7 -0
  31. package/src/shared/catalog/paymentMethodsCatalog.js +242 -243
  32. package/src/shared/constants/colors.js +15 -0
  33. package/src/shared/constants/displayMode.js +4 -0
  34. package/src/shared/constants/fieldPathNames.js +4 -0
  35. package/src/shared/constants/htmlTonderIds.js +18 -0
  36. package/src/shared/constants/messages.js +10 -9
  37. package/types/card.d.ts +17 -17
  38. package/types/checkout.d.ts +85 -87
  39. package/types/common.d.ts +4 -1
  40. package/types/customer.d.ts +10 -10
  41. package/types/index.d.ts +9 -11
  42. package/types/inlineCheckout.d.ts +81 -61
  43. package/types/liteInlineCheckout.d.ts +78 -83
  44. package/types/paymentMethod.d.ts +17 -17
  45. package/types/transaction.d.ts +94 -94
  46. 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.#handleCustomer(data.customer);
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('Handling 3DS redirect...');
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((ic) => ({
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((apmItem) => apmItem.category.toLowerCase() !== "cards")
152
- .map((apmItem) => {
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
  });
@@ -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 = (buttonText) => {
25
- this.buttonText = buttonText ? buttonText : this.buttonText
26
- this.tonderButton = document.createElement('button');
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 = (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
- }
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, 'url-params-encrypt').toString()
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(this.url + this.params, '_blank', `width=1200,height=$800,left=0,top=0`);
80
- this.tonderButton.disabled = true
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 '../helpers/template-skeleton.js'
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("#global-loader");
11
+ const checkoutContainer = document.querySelector(`#${HTML_IDS.globalLoader}`);
11
12
  if (checkoutContainer) {
12
13
  checkoutContainer.innerHTML = cardTemplateSkeleton;
13
- checkoutContainer.style.display = 'block';
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 loader = document.querySelector('#global-loader');
22
- if (loader) {
23
- loader.style.display = 'none';
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
  }