tonder-web-sdk 1.16.3 → 1.16.6-beta.DEV-1433.2

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 (106) hide show
  1. package/README.md +22 -25
  2. package/package.json +10 -3
  3. package/types/common.d.ts +4 -0
  4. package/v1/bundle.min.js +1 -18
  5. package/.env-example +0 -1
  6. package/.husky/pre-commit +0 -4
  7. package/.prettierignore +0 -8
  8. package/.prettierrc +0 -10
  9. package/cypress/e2e/1-getting-started/todo.cy.js +0 -143
  10. package/cypress/e2e/2-advanced-examples/actions.cy.js +0 -299
  11. package/cypress/e2e/2-advanced-examples/aliasing.cy.js +0 -39
  12. package/cypress/e2e/2-advanced-examples/assertions.cy.js +0 -176
  13. package/cypress/e2e/2-advanced-examples/connectors.cy.js +0 -98
  14. package/cypress/e2e/2-advanced-examples/cookies.cy.js +0 -118
  15. package/cypress/e2e/2-advanced-examples/cypress_api.cy.js +0 -185
  16. package/cypress/e2e/2-advanced-examples/files.cy.js +0 -85
  17. package/cypress/e2e/2-advanced-examples/location.cy.js +0 -32
  18. package/cypress/e2e/2-advanced-examples/misc.cy.js +0 -104
  19. package/cypress/e2e/2-advanced-examples/navigation.cy.js +0 -56
  20. package/cypress/e2e/2-advanced-examples/network_requests.cy.js +0 -163
  21. package/cypress/e2e/2-advanced-examples/querying.cy.js +0 -114
  22. package/cypress/e2e/2-advanced-examples/spies_stubs_clocks.cy.js +0 -201
  23. package/cypress/e2e/2-advanced-examples/storage.cy.js +0 -110
  24. package/cypress/e2e/2-advanced-examples/traversal.cy.js +0 -121
  25. package/cypress/e2e/2-advanced-examples/utilities.cy.js +0 -108
  26. package/cypress/e2e/2-advanced-examples/viewport.cy.js +0 -58
  27. package/cypress/e2e/2-advanced-examples/waiting.cy.js +0 -30
  28. package/cypress/e2e/2-advanced-examples/window.cy.js +0 -22
  29. package/cypress/fixtures/example.json +0 -5
  30. package/cypress/support/commands.js +0 -25
  31. package/cypress/support/e2e.js +0 -20
  32. package/cypress.config.js +0 -9
  33. package/eslint.config.mjs +0 -15
  34. package/index.js.example +0 -50
  35. package/samples/react/README.md +0 -70
  36. package/samples/react/build/asset-manifest.json +0 -16
  37. package/samples/react/build/favicon.ico +0 -0
  38. package/samples/react/build/index.html +0 -1
  39. package/samples/react/build/logo192.png +0 -0
  40. package/samples/react/build/logo512.png +0 -0
  41. package/samples/react/build/manifest.json +0 -25
  42. package/samples/react/build/robots.txt +0 -3
  43. package/samples/react/build/static/css/main.073c9b0a.css +0 -2
  44. package/samples/react/build/static/css/main.073c9b0a.css.map +0 -1
  45. package/samples/react/build/static/js/787.b83ed06f.chunk.js +0 -2
  46. package/samples/react/build/static/js/787.b83ed06f.chunk.js.map +0 -1
  47. package/samples/react/build/static/js/main.0a848807.js +0 -3
  48. package/samples/react/build/static/js/main.0a848807.js.LICENSE.txt +0 -39
  49. package/samples/react/build/static/js/main.0a848807.js.map +0 -1
  50. package/samples/react/build/static/media/sdk-icons.b491623214b2af4cccdb.png +0 -0
  51. package/samples/react/package-lock.json +0 -28973
  52. package/samples/react/package.json +0 -44
  53. package/samples/react/public/favicon.ico +0 -0
  54. package/samples/react/public/index.html +0 -43
  55. package/samples/react/public/logo192.png +0 -0
  56. package/samples/react/public/logo512.png +0 -0
  57. package/samples/react/public/manifest.json +0 -25
  58. package/samples/react/public/robots.txt +0 -3
  59. package/samples/react/src/App.css +0 -38
  60. package/samples/react/src/App.js +0 -22
  61. package/samples/react/src/App.test.js +0 -8
  62. package/samples/react/src/assets/img/sdk-icons.png +0 -0
  63. package/samples/react/src/components/Cart.js +0 -29
  64. package/samples/react/src/components/ProductCard.js +0 -27
  65. package/samples/react/src/context/CartContext.js +0 -116
  66. package/samples/react/src/index.css +0 -13
  67. package/samples/react/src/index.js +0 -17
  68. package/samples/react/src/logo.svg +0 -1
  69. package/samples/react/src/reportWebVitals.js +0 -13
  70. package/samples/react/src/screens/Checkout.js +0 -82
  71. package/samples/react/src/screens/Store.js +0 -21
  72. package/samples/react/src/setupTests.js +0 -5
  73. package/samples/react/src/storeProducts.js +0 -30
  74. package/src/classes/3dsHandler.js +0 -199
  75. package/src/classes/BaseInlineCheckout.js +0 -303
  76. package/src/classes/LiteInlineCheckout.js +0 -217
  77. package/src/classes/checkout.js +0 -129
  78. package/src/classes/globalLoader.js +0 -31
  79. package/src/classes/inlineCheckout.js +0 -713
  80. package/src/data/apmApi.js +0 -38
  81. package/src/data/businessApi.js +0 -16
  82. package/src/data/cardApi.js +0 -134
  83. package/src/data/checkoutApi.js +0 -92
  84. package/src/data/customerApi.js +0 -32
  85. package/src/data/index.js +0 -17
  86. package/src/data/openPayApi.js +0 -16
  87. package/src/data/skyflowApi.js +0 -16
  88. package/src/helpers/skyflow.js +0 -370
  89. package/src/helpers/styles.js +0 -90
  90. package/src/helpers/template-skeleton.js +0 -59
  91. package/src/helpers/template.js +0 -1104
  92. package/src/helpers/utils.js +0 -257
  93. package/src/helpers/validations.js +0 -53
  94. package/src/index-dev.js +0 -329
  95. package/src/index.html +0 -180
  96. package/src/index.js +0 -21
  97. package/src/shared/catalog/commonLogosCatalog.js +0 -7
  98. package/src/shared/catalog/paymentMethodsCatalog.js +0 -246
  99. package/src/shared/constants/colors.js +0 -15
  100. package/src/shared/constants/displayMode.js +0 -4
  101. package/src/shared/constants/fieldPathNames.js +0 -4
  102. package/src/shared/constants/htmlTonderIds.js +0 -18
  103. package/src/shared/constants/messages.js +0 -11
  104. package/src/shared/constants/paymentMethodAPM.js +0 -63
  105. package/src/shared/constants/tonderUrl.js +0 -8
  106. package/webpack.config.js +0 -77
@@ -1,713 +0,0 @@
1
- import {
2
- apmItemsTemplate,
3
- cardItemsTemplate,
4
- cardTemplate,
5
- containerCheckoutTemplate,
6
- } from "../helpers/template.js";
7
- import { clearSpace, executeCallback, mapCards, showError, showMessage } from "../helpers/utils";
8
- import { initSkyflow, initUpdateSkyflow } from "../helpers/skyflow";
9
- import { globalLoader } from "./globalLoader.js";
10
- import { BaseInlineCheckout } from "./BaseInlineCheckout";
11
- import {
12
- fetchCustomerAPMs,
13
- fetchCustomerCards,
14
- removeCustomerCard,
15
- saveCustomerCard,
16
- } from "../data";
17
- import { MESSAGES } from "../shared/constants/messages";
18
- import Accordion from "accordion-js";
19
- import get from "lodash.get";
20
- import { HTML_IDS } from "../shared/constants/htmlTonderIds";
21
- import { DISPLAY_MODE } from "../shared/constants/displayMode";
22
-
23
- export class InlineCheckout extends BaseInlineCheckout {
24
- static injected = false;
25
- static cardsInjected = false;
26
- static apmsInjected = false;
27
- #cardsData = [];
28
- #paymentMethodsData = [];
29
- #customerData = {};
30
- accordionCards = null;
31
- accordionPaymentMethods = null;
32
-
33
- deletingCards = [];
34
- customer = {};
35
- items = [];
36
- collectContainer = null;
37
- updateCollectContainer = null;
38
- merchantData = {};
39
- cartTotal = null;
40
- metadata = {};
41
- card = {};
42
- collectorIds = {
43
- cardsListContainer: HTML_IDS.cardsListContainer,
44
- holderName: HTML_IDS.collectCardholderName,
45
- cardNumber: HTML_IDS.collectCardNumber,
46
- expirationMonth: HTML_IDS.collectExpirationMonth,
47
- expirationYear: HTML_IDS.collectExpirationYear,
48
- cvv: HTML_IDS.collectCvv,
49
- tonderPayButton: HTML_IDS.tonderPayButton,
50
- tonderCancelButton: HTML_IDS.tonderCancelButton,
51
- msgError: HTML_IDS.msgError,
52
- msgNotification: HTML_IDS.msgNotification,
53
- msgErrorText: HTML_IDS.msgErrorText,
54
- msgNotificationText: HTML_IDS.msgNotificationText,
55
- apmsListContainer: HTML_IDS.apmsListContainer,
56
- };
57
- customization = {
58
- displayMode: DISPLAY_MODE.light,
59
- saveCards: {
60
- showSaveCardOption: false,
61
- showSaved: false,
62
- autoSave: false,
63
- },
64
- paymentButton: {
65
- show: false,
66
- text: "Pagar",
67
- showAmount: true,
68
- },
69
- cancelButton: {
70
- show: false,
71
- text: "Cancelar",
72
- },
73
- paymentMethods: {
74
- show: true,
75
- },
76
- cardForm: {
77
- show: true,
78
- },
79
- showMessages: true,
80
- };
81
- callbacks = {
82
- onCancel: () => {},
83
- };
84
- constructor({
85
- mode = "stage",
86
- apiKey,
87
- returnUrl,
88
- callBack = () => {},
89
- styles,
90
- customization,
91
- callbacks,
92
- }) {
93
- super({ mode, apiKey, returnUrl, callBack });
94
- this.customStyles = styles;
95
- this.callbacks = { ...this.callbacks, ...(callbacks ? { ...callbacks } : {}) };
96
- this.abortRefreshCardsController = new AbortController();
97
- // TODO: Wait until SaveCards is ready (server token).
98
- this.customization = {
99
- ...this.customization,
100
- ...(customization || {}),
101
- saveCards: {
102
- ...this.customization.saveCards,
103
- ...(customization?.saveCards || {}),
104
- },
105
- paymentButton: {
106
- ...this.customization.paymentButton,
107
- ...(customization?.paymentButton || {}),
108
- },
109
- paymentMethods: {
110
- ...this.customization.paymentMethods,
111
- ...(customization?.paymentMethods || {}),
112
- },
113
- cardForm: {
114
- ...this.customization.cardForm,
115
- ...(customization?.cardForm || {}),
116
- },
117
- };
118
- }
119
-
120
- /**
121
- * Injects the checkout into the DOM and initializes it.
122
- * Checks for an existing container and sets up an observer if needed.
123
- * @returns {void}
124
- * @public
125
- */
126
- async injectCheckout() {
127
- if (InlineCheckout.injected) return;
128
- const containerTonderCheckout = document.querySelector(`#${HTML_IDS.tonderCheckout}`);
129
- if (containerTonderCheckout) {
130
- await this.#mount(containerTonderCheckout);
131
- return;
132
- }
133
- const observer = new MutationObserver(async (mutations, obs) => {
134
- const containerTonderCheckout = document.querySelector(`#${HTML_IDS.tonderCheckout}`);
135
- if (containerTonderCheckout) {
136
- await this.#mount(containerTonderCheckout);
137
- obs.disconnect();
138
- }
139
- });
140
- observer.observe(document.body, {
141
- childList: true,
142
- subtree: true,
143
- attributeFilter: ["id"],
144
- });
145
- }
146
-
147
- setCallback(cb) {
148
- this.cb = cb;
149
- }
150
-
151
- /**
152
- * Removes the checkout from the DOM and cleans up associated resources.
153
- *
154
- * This method performs the following actions:
155
- * 1. Resets the injection status flags for the checkout, cards, and APMs.
156
- * 2. Aborts any ongoing requests using the AbortController.
157
- * 3. Creates a new AbortController for future use.
158
- * 4. Clears any existing injection intervals.
159
- *
160
- * Note: This method should be called when you want to completely remove
161
- * the checkout from the page and reset its state.
162
- *
163
- * @returns {void}
164
- * @public
165
- */
166
- removeCheckout() {
167
- InlineCheckout.injected = false;
168
- InlineCheckout.cardsInjected = false;
169
- InlineCheckout.apmsInjected = false;
170
- // Cancel all requests
171
- this.abortController.abort();
172
- this.abortController = new AbortController();
173
-
174
- clearInterval(this.injectInterval);
175
- console.log("InlineCheckout removed from DOM and cleaned up.");
176
- }
177
-
178
- async #mount(containerTonderCheckout) {
179
- containerTonderCheckout.innerHTML = containerCheckoutTemplate({
180
- customStyles: this.customStyles,
181
- customization: this.customization,
182
- });
183
- globalLoader.show();
184
- await this._initializeCheckout();
185
- await this.#loadInitialData();
186
- const currentContent = document.querySelector(`#${HTML_IDS.tonderContainer}`);
187
- currentContent.innerHTML = `
188
- ${currentContent.innerHTML}
189
- ${cardTemplate({
190
- customStyles: this.customStyles,
191
- customization: this.customization,
192
- cardsData: this.#cardsData,
193
- paymentMethodsData: this.#paymentMethodsData,
194
- collectorIds: this.collectorIds,
195
- })}
196
- `;
197
- await this.#mountTonder();
198
- InlineCheckout.injected = true;
199
- }
200
-
201
- async #mountTonder() {
202
- try {
203
- const { vault_id, vault_url } = this.merchantData;
204
-
205
- if (this.email && this.#cardsData.length > 0) {
206
- await this.#loadCardsList();
207
- }
208
- this.#mountButtons();
209
- await this.#loadAPMList();
210
-
211
- this.collectContainer = await initSkyflow(
212
- vault_id,
213
- vault_url,
214
- this.baseUrl,
215
- this.apiKeyTonder,
216
- this.abortController.signal,
217
- this.customStyles,
218
- this.collectorIds,
219
- this.customization.displayMode,
220
- );
221
-
222
- setTimeout(() => {
223
- globalLoader.remove();
224
- }, 800);
225
- } catch (e) {
226
- if (e && e.name !== "AbortError") {
227
- globalLoader.remove();
228
- showError("No se pudieron cargar los datos del comercio.", this.radioChecked);
229
- }
230
- }
231
- }
232
-
233
- #mountButtons(cardId = "") {
234
- if (this.customization.paymentButton.show) {
235
- this.#mountButton(this.collectorIds.tonderPayButton, cardId, this.#handlePaymentClick);
236
- }
237
- if (this.customization.cancelButton.show) {
238
- this.#mountButton(this.collectorIds.tonderCancelButton, cardId, async () => {
239
- await executeCallback({
240
- callbacks: this.callbacks,
241
- callback: "onCancel",
242
- throwError: true,
243
- });
244
- });
245
- }
246
- const containerID = `#acContainer${cardId}`;
247
- const container = document.querySelector(containerID);
248
- document.querySelectorAll(".ac-option-panel-container").forEach(cont => {
249
- cont.classList.remove("show");
250
- });
251
-
252
- if (container) {
253
- container.classList.add("show");
254
- }
255
- }
256
-
257
- #mountButton(buttonId = "", cardId = "", fn = () => {}) {
258
- if (!this.customization.paymentButton.show) return;
259
-
260
- const btnID = `#${buttonId}${cardId}`;
261
- const findButton = document.querySelector(btnID);
262
-
263
- if (!findButton) {
264
- console.error(`${buttonId} not found`);
265
- return;
266
- }
267
-
268
- this.#updateButton({
269
- style: { display: "block" },
270
- buttonId,
271
- ...(cardId ? { cardId } : {}),
272
- });
273
-
274
- findButton.onclick = async event => {
275
- event.preventDefault();
276
- await fn();
277
- };
278
- }
279
-
280
- #handlePaymentClick = async () => {
281
- try {
282
- const response = await this.payment();
283
- this.callBack(response);
284
- } catch (error) {
285
- console.error("Payment error:", error);
286
- }
287
- };
288
-
289
- _setCartTotal(total) {
290
- this.cartTotal = total;
291
- this.#updateButton();
292
- }
293
-
294
- #updateButton(data) {
295
- try {
296
- const buttonDataId = data?.buttonId || this.collectorIds.tonderPayButton;
297
- const btnID =
298
- data?.cardId && data?.cardId !== "new"
299
- ? `#${buttonDataId}${data.cardId}`
300
- : `#${buttonDataId}`;
301
- const textButton =
302
- buttonDataId === this.collectorIds.tonderPayButton
303
- ? `<div class="pay-button-text">${this.customization.paymentButton.text}${this.customization.paymentButton.showAmount ? ` $${this.cartTotal}` : ""}</div>`
304
- : `<div class="cancel-button-text">${this.customization.cancelButton.text}</div>`;
305
-
306
- const btnTextContent = data?.textContent || textButton;
307
- const disabledBtn = data?.disabled;
308
- const loadingHtml = data?.loading ? `<div class="spinner-tndr"></div>` : "";
309
- const btnStyle = data?.style || {};
310
- const payButton = document.querySelector(btnID);
311
- if (!payButton) return;
312
- if (loadingHtml !== "") {
313
- payButton.innerHTML = loadingHtml;
314
- } else {
315
- payButton.innerHTML = btnTextContent;
316
- }
317
- if (btnStyle) {
318
- Object.keys(btnStyle).forEach(btn => {
319
- payButton.style[btn] = btnStyle[btn];
320
- });
321
- }
322
- if (disabledBtn !== undefined && "disabled" in payButton) {
323
- payButton.disabled = disabledBtn;
324
- }
325
- } catch (e) {
326
- console.error("Pay button not found due to update", e);
327
- }
328
- }
329
-
330
- async #getCardTokens(cardSelected) {
331
- if (this.card?.skyflow_id) return this.card;
332
- try {
333
- const collectResponse =
334
- cardSelected && cardSelected !== "new"
335
- ? await this.updateCollectContainer.container.collect()
336
- : await this.collectContainer.container.collect();
337
- return await collectResponse["records"][0]["fields"];
338
- } catch (error) {
339
- showError("Por favor, verifica todos los campos de tu tarjeta", this.radioChecked);
340
- throw error;
341
- }
342
- }
343
-
344
- async _checkout() {
345
- this.#updateButton({
346
- cardId: this.radioChecked,
347
- loading: true,
348
- disabled: true,
349
- });
350
- try {
351
- const { business } = this.merchantData;
352
- let cardTokens;
353
- const selected_apm = this.#paymentMethodsData
354
- ? this.#paymentMethodsData.find(iapm => iapm.pk === this.radioChecked)
355
- : {};
356
-
357
- if (this.radioChecked === "new" || this.radioChecked === undefined) {
358
- cardTokens = await this.#getCardTokens(this.radioChecked);
359
- } else {
360
- if (!selected_apm) {
361
- await this.#getCardTokens(this.radioChecked);
362
- }
363
- cardTokens = {
364
- skyflow_id: this.radioChecked,
365
- };
366
- }
367
-
368
- this.#customerData = await this._getCustomer(this.customer, this.abortController.signal);
369
- if (this.email) {
370
- await this.#handleSaveCard(business.pk, cardTokens);
371
- }
372
-
373
- const jsonResponseRouter = await this._handleCheckout({
374
- ...(selected_apm && Object.keys(selected_apm).length > 0
375
- ? { payment_method: selected_apm.payment_method }
376
- : { card: cardTokens }),
377
- customer: this.#customerData,
378
- });
379
-
380
- if (jsonResponseRouter) {
381
- return jsonResponseRouter;
382
- } else {
383
- showError("No se ha podido procesar el pago", this.radioChecked);
384
- return false;
385
- }
386
- } catch (error) {
387
- console.log("Error payment", error);
388
-
389
- showError("Ha ocurrido un error", this.radioChecked);
390
- throw error;
391
- } finally {
392
- this.#updateButton({ cardId: this.radioChecked, disabled: false });
393
- }
394
- }
395
-
396
- async #handleSaveCard(businessId, cardTokens) {
397
- if (!this.#customerData.auth_token) return;
398
- const saveCard = document.getElementById("save-checkout-card");
399
- if (
400
- (saveCard && "checked" in saveCard && saveCard.checked) ||
401
- !!this.customization.saveCards?.autoSave
402
- ) {
403
- try {
404
- await saveCustomerCard(
405
- this.baseUrl,
406
- this.#customerData.auth_token,
407
- this.secureToken,
408
- businessId,
409
- {
410
- skyflow_id: cardTokens.skyflow_id,
411
- },
412
- );
413
- showMessage(MESSAGES.cardSaved, this.radioChecked);
414
- } catch (error) {
415
- if (error?.message) {
416
- showError(error.message, this.radioChecked);
417
- }
418
- }
419
-
420
- await this.#loadCardsList();
421
- }
422
- }
423
-
424
- async #loadCardsList() {
425
- try {
426
- if (this.cardsInjected || !this.customization.saveCards?.showSaved) return;
427
- this.cardsInjected = false;
428
- let cards = [];
429
- cards = this.#cardsData.map(mapCards);
430
- const injectInterval = setInterval(() => {
431
- const queryElement = document.querySelector(`#${this.collectorIds.cardsListContainer}`);
432
- if (queryElement && InlineCheckout.injected) {
433
- queryElement.innerHTML = cardItemsTemplate({
434
- cards: cards,
435
- customization: this.customization,
436
- collectorIds: this.collectorIds,
437
- customStyles: this.customStyles,
438
- });
439
- clearInterval(injectInterval);
440
- this.#generateAccordion();
441
- this.#mountRadioButtons();
442
- this.cardsInjected = true;
443
- }
444
- }, 500);
445
- } catch (error) {
446
- console.warn("Error mount Customer Cards", error);
447
- }
448
- }
449
-
450
- #loadAPMList() {
451
- try {
452
- if (this.apmsInjected || !this.customization.paymentMethods?.show) return;
453
- const injectInterval = setInterval(() => {
454
- const queryElement = document.querySelector(`#${this.collectorIds.apmsListContainer}`);
455
- if (queryElement && InlineCheckout.injected) {
456
- const filteredAndSortedApms = this.#paymentMethodsData
457
- .filter(
458
- apm =>
459
- clearSpace(apm.category.toLowerCase()) !== "cards" &&
460
- apm.status.toLowerCase() === "active",
461
- )
462
- .sort((a, b) => a.priority - b.priority);
463
- queryElement.innerHTML = apmItemsTemplate({
464
- paymentMethods: filteredAndSortedApms,
465
- customization: this.customization,
466
- collectorIds: this.collectorIds,
467
- });
468
- clearInterval(injectInterval);
469
- this.#generateAccordion("paymentMethods");
470
- this.#mountRadioButtons();
471
- this.apmsInjected = true;
472
- }
473
- }, 500);
474
- } catch (error) {
475
- console.warn("Error mount Payment Methods", error);
476
- }
477
- }
478
-
479
- async #loadInitialData() {
480
- try {
481
- const canGetCards = this.email && this.customization.saveCards?.showSaved;
482
- const pmResponsePromise = this.customization.paymentMethods?.show
483
- ? fetchCustomerAPMs(this.baseUrl, this.apiKeyTonder)
484
- : Promise.resolve(null);
485
- const customerDataPromise = canGetCards
486
- ? this._getCustomer({ email: this.email })
487
- : Promise.resolve(null);
488
-
489
- const [pmResponse, customerData] = await Promise.all([
490
- pmResponsePromise,
491
- customerDataPromise,
492
- ]);
493
-
494
- this.#paymentMethodsData = get(pmResponse, "results", []);
495
- this.#customerData = customerData;
496
-
497
- if (canGetCards && customerData && "auth_token" in customerData) {
498
- const { auth_token } = customerData;
499
- const cardsResponse = await fetchCustomerCards(
500
- this.baseUrl,
501
- auth_token,
502
- this.secureToken,
503
- this.merchantData.business.pk,
504
- );
505
- this.#cardsData = get(cardsResponse, "cards", []);
506
- }
507
- } catch (e) {
508
- console.warn("Error loading initial data", e);
509
- }
510
- }
511
- #mountRadioButtons() {
512
- const radioButtons = document.getElementsByName(`card_selected`);
513
- for (const radio of radioButtons) {
514
- radio.style.display = "block";
515
- radio.onclick = async event => {
516
- const position = Array.from(radioButtons).indexOf(radio);
517
- const classType = radio.classList[0];
518
- await this.#handleRadioButtonClick(radio, position, classType);
519
- };
520
- }
521
- const cardsButtons = document.getElementsByClassName("card-delete-button");
522
- for (const cardButton of cardsButtons) {
523
- cardButton.addEventListener(
524
- "click",
525
- event => {
526
- event.preventDefault();
527
- event.stopImmediatePropagation();
528
- this.#handleDeleteCardButtonClick(cardButton);
529
- },
530
- false,
531
- );
532
- }
533
- }
534
-
535
- async #handleRadioButtonClick(radio, position = null, type = "") {
536
- if (radio.id === this.radioChecked || (radio.id === "new" && this.radioChecked === undefined))
537
- return;
538
- const containerForm = document.querySelector(".container-form");
539
- if (containerForm) {
540
- containerForm.style.display = radio.id === "new" ? "block" : "none";
541
- }
542
-
543
- if (radio.id === "new") {
544
- this.#removeClass(["cvvContainer", "cvvContainerCard"]);
545
- this.#handleOpenCloseAccordion("", null, true);
546
- if (this.radioChecked !== radio.id) {
547
- globalLoader.show();
548
- await this.#mountTonder();
549
- InlineCheckout.injected = true;
550
- }
551
- } else {
552
- this.#handleOpenCloseAccordion(type, null, false, true);
553
- if (position !== null) {
554
- this.#handleOpenCloseAccordion(type, position, true);
555
- }
556
- this.#unmountForm();
557
- }
558
- this.radioChecked = radio.id;
559
- }
560
-
561
- async #handleDeleteCardButtonClick(button) {
562
- if (!this.#customerData.auth_token) return;
563
-
564
- const id = button.attributes.getNamedItem("id");
565
- const skyflow_id = id?.value?.split("_")?.[2];
566
-
567
- if (skyflow_id) {
568
- const cardClicked = document.querySelector(`#option_container-${skyflow_id}`);
569
- if (cardClicked) {
570
- cardClicked.style.display = "none";
571
- }
572
- try {
573
- this.deletingCards.push(skyflow_id);
574
- if (this.abortRefreshCardsController) {
575
- this.abortRefreshCardsController.abort();
576
- this.abortRefreshCardsController = new AbortController();
577
- }
578
- const businessId = this.merchantData.business.pk;
579
- await removeCustomerCard(
580
- this.baseUrl,
581
- this.#customerData.auth_token,
582
- this.secureToken,
583
- skyflow_id,
584
- businessId,
585
- );
586
- } catch (error) {
587
- } finally {
588
- this.deletingCards = this.deletingCards.filter(id => id !== skyflow_id);
589
- this.#refreshCardOnDelete();
590
- }
591
- }
592
- }
593
-
594
- async #refreshCardOnDelete() {
595
- if (this.deletingCards.length > 0) return;
596
- await this.#loadCardsList();
597
- }
598
-
599
- #generateAccordion(type = "cards") {
600
- const accordionByType = {
601
- cards: {
602
- accClass: "accordion-container",
603
- triggerClass: "card-item-label",
604
- },
605
- paymentMethods: {
606
- accClass: "accordion-container-apm",
607
- triggerClass: "apm-item-label",
608
- },
609
- };
610
- const accordion = new Accordion("." + accordionByType[type].accClass, {
611
- triggerClass: accordionByType[type].triggerClass,
612
- duration: 300,
613
- collapse: true,
614
- showMultiple: false,
615
- onOpen: async currentElement => {
616
- await this.#handleOpenCardAccordion(currentElement, type);
617
- },
618
- });
619
-
620
- if (type === "cards") {
621
- this.accordionCards = accordion;
622
- } else if (type === "paymentMethods") {
623
- this.accordionPaymentMethods = accordion;
624
- }
625
- }
626
-
627
- #removeClass(selectors = [], className = "show") {
628
- selectors.forEach(slcItem => {
629
- document.querySelectorAll("." + slcItem).forEach(container => {
630
- container.classList.remove(className);
631
- });
632
- });
633
- }
634
-
635
- async #handleOpenCardAccordion(currentElement, type = "cards") {
636
- const { vault_id, vault_url } = this.merchantData;
637
- const container_radio_id = currentElement.id.replace("option_container-", "");
638
-
639
- if (
640
- this.updateCollectContainer &&
641
- "unmount" in this.updateCollectContainer?.elements?.cvvElement
642
- ) {
643
- await this.updateCollectContainer.elements.cvvElement.unmount();
644
- }
645
- this.#removeClass(["cvvContainer", "cvvContainerCard"]);
646
-
647
- const radio_card = document.getElementById(container_radio_id);
648
- radio_card.checked = true;
649
-
650
- try {
651
- if (type === "cards") {
652
- this.updateCollectContainer = await initUpdateSkyflow(
653
- container_radio_id,
654
- vault_id,
655
- vault_url,
656
- this.baseUrl,
657
- this.apiKeyTonder,
658
- this.abortController.signal,
659
- this.customStyles,
660
- this.customization.displayMode,
661
- );
662
- setTimeout(() => {
663
- document.querySelector(`#cvvContainer${container_radio_id}`).classList.add("show");
664
- }, 5);
665
- }
666
-
667
- this.#mountButtons(container_radio_id);
668
- } catch (e) {
669
- console.error("Ha ocurrido un error", e);
670
- }
671
- await this.#handleRadioButtonClick(radio_card, null, type);
672
- }
673
-
674
- #handleOpenCloseAccordion(type = "", position = null, closeAll = false, closeOthers = false) {
675
- const accordions = [
676
- { type: "cards", accordion: this.accordionCards },
677
- { type: "paymentMethods", accordion: this.accordionPaymentMethods },
678
- ];
679
- accordions.forEach(({ accordion, type: currentType }) => {
680
- if (!accordion) return;
681
-
682
- if (closeAll && accordion.closeAll) {
683
- accordion.closeAll();
684
- }
685
-
686
- if (closeOthers && currentType !== type && accordion.closeAll) {
687
- accordion.closeAll();
688
- }
689
-
690
- if (position !== null && currentType === type && accordion.open) {
691
- accordion.open(
692
- currentType !== "paymentMethods" ? position : position - (this.#cardsData.length + 1),
693
- );
694
- }
695
- });
696
- }
697
-
698
- #unmountForm() {
699
- InlineCheckout.injected = false;
700
- if (this.collectContainer) {
701
- if ("unmount" in this.collectContainer.elements.cardHolderNameElement)
702
- this.collectContainer.elements.cardHolderNameElement.unmount();
703
- if ("unmount" in this.collectContainer.elements.cardNumberElement)
704
- this.collectContainer.elements.cardNumberElement.unmount();
705
- if ("unmount" in this.collectContainer.elements.expiryYearElement)
706
- this.collectContainer.elements.expiryYearElement.unmount();
707
- if ("unmount" in this.collectContainer.elements.expiryMonthElement)
708
- this.collectContainer.elements.expiryMonthElement.unmount();
709
- if ("unmount" in this.collectContainer.elements.cvvElement)
710
- this.collectContainer.elements.cvvElement.unmount();
711
- }
712
- }
713
- }