tonder-web-sdk 1.12.0-beta.9 → 1.12.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tonder-web-sdk",
3
- "version": "1.12.0-beta.9",
3
+ "version": "1.12.3",
4
4
  "description": "tonder sdk for integrations",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -17,6 +17,7 @@
17
17
  "devDependencies": {
18
18
  "@babel/core": "^7.20.12",
19
19
  "@babel/preset-env": "^7.20.2",
20
+ "@maskito/core": "^3.0.1",
20
21
  "babel-loader": "^9.1.2",
21
22
  "css-loader": "^6.7.3",
22
23
  "cypress": "^13.6.2",
@@ -13,12 +13,7 @@ import { getBrowserInfo, injectMercadoPagoSecurity } from "../helpers/utils";
13
13
  export class BaseInlineCheckout {
14
14
  baseUrl = "";
15
15
  cartTotal = "0";
16
- constructor({
17
- mode = "stage",
18
- apiKey,
19
- returnUrl,
20
- callBack = () => {},
21
- }) {
16
+ constructor({ mode = "stage", apiKey, returnUrl, callBack = () => {} }) {
22
17
  this.apiKeyTonder = apiKey;
23
18
  this.returnUrl = returnUrl;
24
19
  this.callBack = callBack;
@@ -34,7 +29,7 @@ export class BaseInlineCheckout {
34
29
  /**
35
30
  * The configureCheckout function allows you to set initial information, such as the customer's email, which is used to retrieve a list of saved cards.
36
31
  * @param {import("../../types").IConfigureCheckout} data - Configuration data including customer information and potentially other settings.
37
- * @returns {Promise<void>}.
32
+ * @returns {void}.
38
33
  * @public
39
34
  */
40
35
  configureCheckout(data) {
@@ -75,7 +70,6 @@ export class BaseInlineCheckout {
75
70
  this.#handleMetadata(data);
76
71
  this.#handleCurrency(data);
77
72
  this.#handleCard(data);
78
- console.log("data", data)
79
73
  const response = await this._checkout(data);
80
74
  this.process3ds.setPayload(response);
81
75
  this.callBack(response);
@@ -121,7 +115,6 @@ export class BaseInlineCheckout {
121
115
  async _handleCheckout({ card, payment_method, customer }) {
122
116
  const { openpay_keys, reference, business } = this.merchantData;
123
117
  const total = Number(this.cartTotal);
124
-
125
118
  try {
126
119
  let deviceSessionIdTonder;
127
120
  if (
@@ -8,13 +8,12 @@ import {
8
8
  } from "../data";
9
9
  import { getSkyflowTokens } from "../helpers/skyflow";
10
10
  import { getPaymentMethodDetails } from "../shared/catalog/paymentMethodsCatalog";
11
- import { formatPublicErrorResponse } from "../helpers/utils";
11
+ import { formatPublicErrorResponse, getCardType } from "../helpers/utils";
12
12
  import { MESSAGES } from "../shared/constants/messages";
13
13
 
14
14
  export class LiteInlineCheckout extends BaseInlineCheckout {
15
15
  #customerData;
16
16
  constructor({ mode = "stage", apiKey, returnUrl, callBack = () => {} }) {
17
-
18
17
  super({ mode, apiKey, returnUrl, callBack });
19
18
  }
20
19
 
@@ -40,11 +39,18 @@ export class LiteInlineCheckout extends BaseInlineCheckout {
40
39
  async getCustomerCards() {
41
40
  try {
42
41
  const { auth_token } = await this.#getCustomer();
43
- return await fetchCustomerCards(
42
+ const response = await fetchCustomerCards(
44
43
  this.baseUrl,
45
44
  auth_token,
46
45
  this.merchantData.business.pk,
47
46
  );
47
+ return {
48
+ ...response,
49
+ cards: response.cards.map((ic) => ({
50
+ ...ic,
51
+ icon: getCardType(ic.fields.card_scheme),
52
+ })),
53
+ };
48
54
  } catch (error) {
49
55
  throw formatPublicErrorResponse(
50
56
  {
@@ -104,22 +110,22 @@ export class LiteInlineCheckout extends BaseInlineCheckout {
104
110
  * @public
105
111
  */
106
112
  async removeCustomerCard(skyflowId) {
107
- try{
113
+ try {
108
114
  const { auth_token } = await this.#getCustomer();
109
115
  const { business } = this.merchantData;
110
116
 
111
117
  return await removeCustomerCard(
112
- this.baseUrl,
113
- auth_token,
114
- skyflowId,
115
- business?.pk,
118
+ this.baseUrl,
119
+ auth_token,
120
+ skyflowId,
121
+ business?.pk,
116
122
  );
117
- }catch (error){
123
+ } catch (error) {
118
124
  throw formatPublicErrorResponse(
119
- {
120
- message: MESSAGES.removeCardError,
121
- },
122
- error,
125
+ {
126
+ message: MESSAGES.removeCardError,
127
+ },
128
+ error,
123
129
  );
124
130
  }
125
131
  }
@@ -137,29 +143,29 @@ export class LiteInlineCheckout extends BaseInlineCheckout {
137
143
  const response = await fetchCustomerAPMs(this.baseUrl, this.apiKeyTonder);
138
144
 
139
145
  const apms_results =
140
- response && "results" in response && response["results"].length > 0
141
- ? response["results"]
142
- : [];
146
+ response && "results" in response && response["results"].length > 0
147
+ ? response["results"]
148
+ : [];
143
149
 
144
150
  return apms_results
145
- .filter((apmItem) => apmItem.category.toLowerCase() !== "cards")
146
- .map((apmItem) => {
147
- const apm = {
148
- id: apmItem.pk,
149
- payment_method: apmItem.payment_method,
150
- priority: apmItem.priority,
151
- category: apmItem.category,
152
- ...getPaymentMethodDetails(apmItem.payment_method),
153
- };
154
- return apm;
155
- })
156
- .sort((a, b) => a.priority - b.priority);
157
- }catch (error){
151
+ .filter((apmItem) => apmItem.category.toLowerCase() !== "cards")
152
+ .map((apmItem) => {
153
+ const apm = {
154
+ id: apmItem.pk,
155
+ payment_method: apmItem.payment_method,
156
+ priority: apmItem.priority,
157
+ category: apmItem.category,
158
+ ...getPaymentMethodDetails(apmItem.payment_method),
159
+ };
160
+ return apm;
161
+ })
162
+ .sort((a, b) => a.priority - b.priority);
163
+ } catch (error) {
158
164
  throw formatPublicErrorResponse(
159
- {
160
- message: MESSAGES.getPaymentMethodsError,
161
- },
162
- error,
165
+ {
166
+ message: MESSAGES.getPaymentMethodsError,
167
+ },
168
+ error,
163
169
  );
164
170
  }
165
171
  }
@@ -169,7 +175,6 @@ export class LiteInlineCheckout extends BaseInlineCheckout {
169
175
  }
170
176
 
171
177
  async _checkout({ card, payment_method }) {
172
- console.log("_checkout", card, payment_method)
173
178
  const customer = await this._getCustomer(
174
179
  this.customer,
175
180
  this.abortController.signal,
@@ -177,7 +182,7 @@ export class LiteInlineCheckout extends BaseInlineCheckout {
177
182
  const { vault_id, vault_url } = this.merchantData;
178
183
  let skyflowTokens;
179
184
  if (!payment_method || payment_method !== "" || payment_method === null) {
180
- if (typeof payment_method === "string") {
185
+ if (typeof card === "string") {
181
186
  skyflowTokens = {
182
187
  skyflow_id: card,
183
188
  };
@@ -185,7 +190,7 @@ export class LiteInlineCheckout extends BaseInlineCheckout {
185
190
  skyflowTokens = await getSkyflowTokens({
186
191
  vault_id: vault_id,
187
192
  vault_url: vault_url,
188
- data: card,
193
+ data: {...card, card_number: card.card_number.replace(/\s+/g, '')},
189
194
  baseUrl: this.baseUrl,
190
195
  apiKey: this.apiKeyTonder,
191
196
  });
@@ -200,13 +205,13 @@ export class LiteInlineCheckout extends BaseInlineCheckout {
200
205
  }
201
206
 
202
207
  async #getCustomer() {
203
- if(!!this.#customerData) return this.#customerData;
208
+ if (!!this.#customerData) return this.#customerData;
204
209
 
205
210
  this.#customerData = await registerOrFetchCustomer(
206
- this.baseUrl,
207
- this.apiKeyTonder,
208
- this.customer,
211
+ this.baseUrl,
212
+ this.apiKeyTonder,
213
+ this.customer,
209
214
  );
210
- return this.#customerData
215
+ return this.#customerData;
211
216
  }
212
217
  }
@@ -1,4 +1,4 @@
1
- import {apmItemsTemplate, cardItemsTemplate, cardTemplate} from '../helpers/template.js'
1
+ import { apmItemsTemplate, cardItemsTemplate, cardTemplate } from '../helpers/template.js'
2
2
  import {
3
3
  clearSpace,
4
4
  injectMercadoPagoSecurity,
@@ -6,18 +6,18 @@ import {
6
6
  showError,
7
7
  showMessage
8
8
  } from '../helpers/utils';
9
- import {initSkyflow} from '../helpers/skyflow'
10
- import {globalLoader} from './globalLoader.js';
11
- import {BaseInlineCheckout} from "./BaseInlineCheckout";
9
+ import { initSkyflow } from '../helpers/skyflow'
10
+ import { globalLoader } from './globalLoader.js';
11
+ import { BaseInlineCheckout } from "./BaseInlineCheckout";
12
12
  import {
13
13
  fetchCustomerCards,
14
14
  removeCustomerCard,
15
15
  saveCustomerCard,
16
16
  fetchCustomerAPMs
17
17
  } from "../data";
18
- import {MESSAGES} from "../shared/constants/messages";
18
+ import { MESSAGES } from "../shared/constants/messages";
19
19
 
20
- export class InlineCheckout extends BaseInlineCheckout{
20
+ export class InlineCheckout extends BaseInlineCheckout {
21
21
  static injected = false;
22
22
  static cardsInjected = false
23
23
  static apmsInjected = false
@@ -42,19 +42,35 @@ export class InlineCheckout extends BaseInlineCheckout{
42
42
  msgNotification: "msgNotification",
43
43
  apmsListContainer: "apmsListContainer"
44
44
  }
45
-
45
+ customization = {
46
+ saveCards: {
47
+ showSaveCardOption: false,
48
+ showSaved: false,
49
+ autoSave: false
50
+ }
51
+ }
46
52
  constructor({
47
53
  mode = "stage",
48
54
  apiKey,
49
55
  returnUrl,
50
56
  renderPaymentButton = false,
51
57
  callBack = () => { },
52
- styles
58
+ styles,
59
+ customization,
53
60
  }) {
54
61
  super({ mode, apiKey, returnUrl, callBack });
55
62
  this.renderPaymentButton = renderPaymentButton;
56
63
  this.customStyles = styles
57
- this.abortRefreshCardsController = new AbortController()
64
+ this.abortRefreshCardsController = new AbortController();
65
+ // TODO: Wait until SaveCards is ready (server token).
66
+ // this.customization = {
67
+ // ...this.customization,
68
+ // ...(customization || {}),
69
+ // saveCards: {
70
+ // ...this.customization.saveCards,
71
+ // ...(customization?.saveCards || {}),
72
+ // },
73
+ // }
58
74
  }
59
75
 
60
76
  #mountPayButton() {
@@ -130,20 +146,20 @@ export class InlineCheckout extends BaseInlineCheckout{
130
146
  }
131
147
 
132
148
  async #mount(containerTonderCheckout) {
133
- containerTonderCheckout.innerHTML = cardTemplate({renderPaymentButton: this.renderPaymentButton, customStyles: this.customStyles});
149
+ containerTonderCheckout.innerHTML = cardTemplate({ renderPaymentButton: this.renderPaymentButton, customStyles: this.customStyles, customization: this.customization });
134
150
  globalLoader.show()
135
151
  await this.#mountTonder();
136
152
  InlineCheckout.injected = true;
137
153
  }
138
154
 
139
155
  async #mountAPMs() {
140
- try{
156
+ try {
141
157
  const apms = await fetchCustomerAPMs(this.baseUrl, this.apiKeyTonder);
142
- if(apms && apms['results'] && apms['results'].length > 0){
158
+ if (apms && apms['results'] && apms['results'].length > 0) {
143
159
  this.apmsData = apms['results']
144
160
  this.#loadAPMList(apms['results'])
145
161
  }
146
- }catch(e){
162
+ } catch (e) {
147
163
  console.warn("Error getting APMS")
148
164
  }
149
165
  }
@@ -160,16 +176,7 @@ export class InlineCheckout extends BaseInlineCheckout{
160
176
  const customerResponse = await this._getCustomer({ email: this.email });
161
177
  if ("auth_token" in customerResponse) {
162
178
  const { auth_token } = customerResponse
163
- const cards = await fetchCustomerCards(
164
- this.baseUrl,
165
- auth_token,
166
- this.merchantData.business.pk
167
- );
168
-
169
- if ("cards" in cards) {
170
- const cardsMapped = cards.cards.map(mapCards)
171
- this.#loadCardsList(cardsMapped, auth_token)
172
- }
179
+ await this.#loadCardsList(auth_token)
173
180
  }
174
181
  }
175
182
 
@@ -256,39 +263,15 @@ export class InlineCheckout extends BaseInlineCheckout{
256
263
  )
257
264
  const { auth_token } = customerData;
258
265
  if (auth_token && this.email) {
259
- const saveCard = document.getElementById("save-checkout-card");
260
- if (saveCard && "checked" in saveCard && saveCard.checked) {
261
- try {
262
- await saveCustomerCard(this.baseUrl, auth_token, business.pk, {
263
- skyflow_id: cardTokens.skyflow_id,
264
- });
265
- showMessage(MESSAGES.cardSaved, this.collectorIds.msgNotification);
266
- } catch (error) {
267
- if (error?.message) {
268
- showError(error.message)
269
- }
270
- }
271
-
272
- this.cardsInjected = false;
273
-
274
- const cards = await fetchCustomerCards(
275
- this.baseUrl,
276
- auth_token,
277
- this.merchantData.business.pk,
278
- );
279
- if ("cards" in cards) {
280
- const cardsMapped = cards.cards.map((card) => mapCards(card))
281
- this.#loadCardsList(cardsMapped, auth_token)
282
- }
283
- }
266
+ await this.#handleSaveCard(auth_token, business.pk, cardTokens)
284
267
  }
285
268
 
286
- const selected_apm = this.apmsData ? this.apmsData.find((iapm) => iapm.pk === this.radioChecked):{};
269
+ const selected_apm = this.apmsData ? this.apmsData.find((iapm) => iapm.pk === this.radioChecked) : {};
287
270
 
288
271
  const jsonResponseRouter = await this._handleCheckout({
289
- ...( selected_apm && Object.keys(selected_apm).length > 0
290
- ? {payment_method: selected_apm.payment_method}
291
- : {card: cardTokens}),
272
+ ...(selected_apm && Object.keys(selected_apm).length > 0
273
+ ? { payment_method: selected_apm.payment_method }
274
+ : { card: cardTokens }),
292
275
  customer: customerData
293
276
  });
294
277
 
@@ -308,17 +291,44 @@ export class InlineCheckout extends BaseInlineCheckout{
308
291
  }
309
292
  };
310
293
 
311
- #loadCardsList(cards, token) {
312
- if (this.cardsInjected) return;
313
- const injectInterval = setInterval(() => {
314
- const queryElement = document.querySelector(`#${this.collectorIds.cardsListContainer}`);
315
- if (queryElement && InlineCheckout.injected) {
316
- queryElement.innerHTML = cardItemsTemplate(cards)
317
- clearInterval(injectInterval)
318
- this.#mountRadioButtons(token)
319
- this.cardsInjected = true
294
+ async #handleSaveCard(auth_token, businessId, cardTokens) {
295
+ const saveCard = document.getElementById("save-checkout-card");
296
+ if ((saveCard && "checked" in saveCard && saveCard.checked) || !!this.customization.saveCards?.autoSave) {
297
+ try {
298
+ await saveCustomerCard(this.baseUrl, auth_token, businessId, {
299
+ skyflow_id: cardTokens.skyflow_id,
300
+ });
301
+ showMessage(MESSAGES.cardSaved, this.collectorIds.msgNotification);
302
+ } catch (error) {
303
+ if (error?.message) {
304
+ showError(error.message)
305
+ }
320
306
  }
321
- }, 500);
307
+
308
+ await this.#loadCardsList(auth_token)
309
+ }
310
+ }
311
+ async #loadCardsList(token) {
312
+ if(this.cardsInjected || !this.customization.saveCards?.showSaved) return;
313
+ this.cardsInjected = false
314
+ const cardsResponse = await fetchCustomerCards(
315
+ this.baseUrl,
316
+ token,
317
+ this.merchantData.business.pk,
318
+ );
319
+ let cards = []
320
+ if("cards" in cardsResponse) {
321
+ cards = cardsResponse.cards.map(mapCards)
322
+ const injectInterval = setInterval(() => {
323
+ const queryElement = document.querySelector(`#${this.collectorIds.cardsListContainer}`);
324
+ if (queryElement && InlineCheckout.injected) {
325
+ queryElement.innerHTML = cardItemsTemplate(cards)
326
+ clearInterval(injectInterval)
327
+ this.#mountRadioButtons(token)
328
+ this.cardsInjected = true
329
+ }
330
+ }, 500);
331
+ }
322
332
  }
323
333
 
324
334
  #loadAPMList(apms) {
@@ -391,7 +401,7 @@ export class InlineCheckout extends BaseInlineCheckout{
391
401
  }
392
402
  const businessId = this.merchantData.business.pk
393
403
  await removeCustomerCard(this.baseUrl, customerToken, skyflow_id, businessId)
394
- } catch(error) {} finally {
404
+ } catch (error) { } finally {
395
405
  this.deletingCards = this.deletingCards.filter(id => id !== skyflow_id);
396
406
  this.#refreshCardOnDelete(customerToken)
397
407
  }
@@ -399,17 +409,7 @@ export class InlineCheckout extends BaseInlineCheckout{
399
409
  }
400
410
  async #refreshCardOnDelete(customerToken) {
401
411
  if (this.deletingCards.length > 0) return;
402
- this.cardsInjected = false
403
- const cards = await fetchCustomerCards(
404
- this.baseUrl,
405
- customerToken,
406
- this.merchantData.business.pk,
407
- this.abortRefreshCardsController.signal
408
- )
409
- if ("cards" in cards) {
410
- const cardsMapped = cards.cards.map(mapCards)
411
- this.#loadCardsList(cardsMapped, customerToken)
412
- }
412
+ await this.#loadCardsList(customerToken)
413
413
  }
414
414
  #unmountForm() {
415
415
  InlineCheckout.injected = false
@@ -3,7 +3,10 @@ import {getPaymentMethodDetails} from "../shared/catalog/paymentMethodsCatalog";
3
3
 
4
4
  export const cardTemplate = (data) => `
5
5
  <div class="container-tonder">
6
- <div id="cardsListContainer" class="cards-list-container"></div>
6
+ ${ data.customization?.saveCards?.showSaved ?
7
+ `<div id="cardsListContainer" class="cards-list-container"></div>`
8
+ :``
9
+ }
7
10
  <div class="pay-new-card">
8
11
  <input checked id="new" class="card_selected" name="card_selected" type="radio"/>
9
12
  <label class="card-item-label-new" for="new">
@@ -20,12 +23,17 @@ export const cardTemplate = (data) => `
20
23
  <div id="collectExpirationYear" class="expiration-year"></div>
21
24
  <div id="collectCvv" class="empty-div"></div>
22
25
  </div>
26
+ ${!!data.customization?.saveCards?.showSaveCardOption
27
+ ? `
23
28
  <div class="checkbox" id="save-card-container">
24
29
  <input id="save-checkout-card" type="checkbox">
25
30
  <label for="save-checkout-card">
26
31
  Guardar tarjeta para futuros pagos
27
32
  </label>
28
33
  </div>
34
+ `
35
+ :``}
36
+
29
37
  <div id="msgError"></div>
30
38
  <div id="msgNotification"></div>
31
39
  </div>