@tonder.io/ionic-full-sdk 0.0.46-beta.9 → 0.0.47-beta.DEV1406.3a5debd

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.
@@ -2,9 +2,9 @@ import { apmItemsTemplate, Card, cardItemsTemplate, cardTemplate, CollectorIds }
2
2
  import {
3
3
  showError,
4
4
  showMessage,
5
- mapCards,
5
+ mapCards, generateRandomString,
6
6
  } from '../helpers/utils';
7
- import { initSkyflow } from '../helpers/skyflow'
7
+ import {initSkyflow, initUpdateSkyflow} from '../helpers/skyflow'
8
8
  import { ErrorResponse } from '@tonder.io/ionic-lite-sdk/dist/classes/errorResponse';
9
9
  import { CustomerRegisterResponse } from '@tonder.io/ionic-lite-sdk/dist/types/responses';
10
10
  import {BaseInlineCheckout} from "@tonder.io/ionic-lite-sdk";
@@ -13,11 +13,13 @@ import {ISaveCardSkyflowRequest} from "@tonder.io/ionic-lite-sdk/dist/types/card
13
13
  import {ITonderPaymentMethod} from "@tonder.io/ionic-lite-sdk/dist/types/paymentMethod";
14
14
  import {IInlineCheckoutOptions, InCollectorContainer} from "../types/commons";
15
15
  import {IInlineCheckout} from "../types/inlineCheckout";
16
-
16
+ // @ts-ignore
17
+ import Accordion from "accordion-js";
17
18
 
18
19
  export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckout{
19
20
  paymentData = {}
20
21
  collectContainer: InCollectorContainer | null;
22
+ updateCollectContainer: InCollectorContainer | null;
21
23
  deletingCards: string[] = [];
22
24
  renderPaymentButton: boolean
23
25
  renderSaveCardButton?: boolean
@@ -25,6 +27,7 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
25
27
  injectInterval: any
26
28
  abortRefreshCardsController: AbortController;
27
29
  containerId: string
30
+ accordionC: {open: any; closeAll: any} | null = null;
28
31
  injected: boolean
29
32
  cardsInjected: boolean
30
33
  apmsInjected = false
@@ -49,12 +52,12 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
49
52
  customization,
50
53
  }: IInlineCheckoutOptions) {
51
54
  super({
52
- apiKey: apiKey,
53
- returnUrl: returnUrl,
54
- mode: mode,
55
- callBack: callBack,
56
- customization: customization,
57
- tdsIframeId: collectorIds && collectorIds?.tdsIframe ? collectorIds?.tdsIframe : "tdsIframe",
55
+ apiKey: apiKey,
56
+ returnUrl: returnUrl,
57
+ mode: mode,
58
+ callBack: callBack,
59
+ customization: customization,
60
+ tdsIframeId: collectorIds && 'tdsIframe' in collectorIds ? collectorIds?.tdsIframe : "tdsIframe",
58
61
  tonderPayButtonId: collectorIds ? collectorIds?.tonderPayButton : "tonderPayButton"
59
62
  });
60
63
  this.renderPaymentButton = renderPaymentButton || false;
@@ -65,7 +68,7 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
65
68
  this.containerId = containerId ? containerId : "tonder-checkout"
66
69
  this.injected = false;
67
70
  this.cardsInjected = false;
68
- this.collectorIds = collectorIds ? collectorIds : {
71
+ this.collectorIds = {
69
72
  cardsListContainer: "cardsListContainer",
70
73
  holderName: "collectCardholderName",
71
74
  cardNumber: "collectCardNumber",
@@ -79,8 +82,10 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
79
82
  apmsListContainer: "apmsListContainer",
80
83
  tdsIframe: "tdsIframe"
81
84
  }
85
+ this.collectorIds = collectorIds ? {...this.collectorIds, ...collectorIds} :this.collectorIds
82
86
  this.radioChecked = "new"
83
87
  this.collectContainer = null;
88
+ this.updateCollectContainer = null;
84
89
 
85
90
  this.isOpenPaySandbox = isOpenPaySandbox === undefined ? true : isOpenPaySandbox
86
91
  this.isEnrollmentCard = isEnrollmentCard === undefined ? false : isEnrollmentCard
@@ -92,6 +97,7 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
92
97
  this.customer = {...this.customer!, email}
93
98
  }
94
99
 
100
+ // TODO: DEPRECATED
95
101
  public setPaymentData (data: IProcessPaymentRequest) {
96
102
  if (!data) return
97
103
  this.paymentData = data
@@ -104,7 +110,7 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
104
110
  const containerTonderCheckout = document.querySelector(`#${this.containerId}`);
105
111
 
106
112
  if (containerTonderCheckout) {
107
- containerTonderCheckout.innerHTML = cardTemplate(!!this.customStyles, this.collectorIds, this.isEnrollmentCard, { renderPaymentButton: this.renderPaymentButton, customization: this.customization })
113
+ containerTonderCheckout.innerHTML = cardTemplate({ collectorIds: this.collectorIds, customStyles: this.customStyles, isEnrollmentCard: this.isEnrollmentCard, renderPaymentButton: this.renderPaymentButton, customization: this.customization })
108
114
  await this.#mountTonder();
109
115
  this.injected = true
110
116
  return;
@@ -112,7 +118,7 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
112
118
  const observer = new MutationObserver(async (mutations, obs) => {
113
119
  const containerTonderCheckout = document.querySelector(`#${this.containerId}`);
114
120
  if (containerTonderCheckout) {
115
- containerTonderCheckout.innerHTML = cardTemplate(!!this.customStyles, this.collectorIds, this.isEnrollmentCard, { renderPaymentButton: this.renderPaymentButton, customization: this.customization })
121
+ containerTonderCheckout.innerHTML = cardTemplate({collectorIds: this.collectorIds, customStyles: this.customStyles, isEnrollmentCard: this.isEnrollmentCard, renderPaymentButton: this.renderPaymentButton, customization: this.customization })
116
122
  await this.#mountTonder();
117
123
  // clearInterval(injectInterval);
118
124
  this.injected = true
@@ -183,8 +189,16 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
183
189
  const injectInterval = setInterval(() => {
184
190
  const queryElement = document.querySelector(`#${this.collectorIds.cardsListContainer}`);
185
191
  if (queryElement && this.injected) {
186
- queryElement.innerHTML = cardItemsTemplate(!!this.customStyles, cards)
192
+ const acId = generateRandomString(10)
193
+ queryElement.innerHTML = cardItemsTemplate({
194
+ cards,
195
+ acId: acId,
196
+ collectorIds: this.collectorIds,
197
+ renderPaymentButton: this.renderPaymentButton,
198
+ customStyles: this.customStyles,
199
+ })
187
200
  clearInterval(injectInterval)
201
+ this.#generateCardsAccordion(acId)
188
202
  this.#mountRadioButtons(customerToken)
189
203
  this.cardsInjected = true
190
204
  }
@@ -192,24 +206,92 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
192
206
  }
193
207
  }
194
208
 
195
- #mountPayButton() {
209
+ #generateCardsAccordion(acId: string){
210
+ this.accordionC = new Accordion(`.accordion-container${acId}`, {
211
+ triggerClass: "card-item-label",
212
+ duration: 300,
213
+ collapse: true,
214
+ showMultiple: false,
215
+ onOpen: async (currentElement: any) => {
216
+ await this.#handleOpenCardAccordion(currentElement)
217
+ }
218
+ });
219
+ }
220
+
221
+ async #handleOpenCardAccordion(currentElement: any){
222
+ const { vault_id, vault_url } = this.merchantData!;
223
+ const container_radio_id = currentElement.id.replace("card_container-", "");
224
+
225
+ if (this.updateCollectContainer && "unmount" in this.updateCollectContainer?.elements?.cvvElement) {
226
+ this.updateCollectContainer.elements.cvvElement.unmount()
227
+ }
228
+
229
+ document.querySelectorAll(".cvvContainer").forEach((container) => {
230
+ container.classList.remove("show");
231
+ });
232
+
233
+ const radio_card = document.getElementById(container_radio_id) as HTMLInputElement;
234
+ if (radio_card) radio_card.checked = true;
235
+
236
+ try{
237
+ this.updateCollectContainer = await initUpdateSkyflow(
238
+ container_radio_id,
239
+ vault_id,
240
+ vault_url,
241
+ this.baseUrl,
242
+ this.abortController.signal,
243
+ this.customStyles,
244
+ this.collectorIds,
245
+ this.apiKeyTonder
246
+
247
+ );
248
+ setTimeout(() => {
249
+ const containerCvv = document.querySelector(`#cvvContainer${container_radio_id}`)
250
+ if(containerCvv) containerCvv.classList.add("show");
251
+ }, 5)
252
+ this.#mountPayButton(container_radio_id)
253
+ }catch (e){
254
+ console.error("Ha ocurrido un error", e);
255
+ }
256
+
257
+ if (radio_card) await this.#handleRadioButtonClick(radio_card)
258
+ }
259
+
260
+
261
+ #mountPayButton(cardId="") {
196
262
  if (!this.renderPaymentButton) return;
263
+ const btnID = `#${this.collectorIds.tonderPayButton}${cardId}`;
264
+ const payButton: HTMLElement | null = document.querySelector(btnID);
265
+ const containerID = `#acContainer${cardId}`;
266
+ const container = document.querySelector(containerID);
197
267
 
198
- const payButton: HTMLElement | null = document.querySelector(`#${this.collectorIds.tonderPayButton}`);
199
-
200
268
  if (!payButton) {
201
269
  console.error("Pay button not found");
202
270
  return;
203
271
  }
204
272
 
273
+ if (cardId !== "") {
274
+ const sdkPayButton: HTMLElement | null = document.querySelector(`#${this.collectorIds.tonderPayButton}`);
275
+ if(sdkPayButton){
276
+ sdkPayButton.style.display = "none";
277
+ }
278
+ }
279
+
205
280
  const LOCALE_MONEY = "en-Latn-US";
206
281
 
207
282
  payButton.style.display = "block";
208
-
283
+
209
284
  const inCartTotal = Intl.NumberFormat(LOCALE_MONEY, { minimumFractionDigits: 2 }).format(Number(this.cartTotal || 0));
210
-
285
+
211
286
  payButton.textContent = `Pagar $${inCartTotal}`;
212
-
287
+
288
+ document.querySelectorAll(".ac-card-panel-container").forEach((cont) => {
289
+ cont.classList.remove("show");
290
+ });
291
+ if (container) {
292
+ container.classList.add("show");
293
+ }
294
+
213
295
  payButton.onclick = async (event) => {
214
296
  event.preventDefault();
215
297
  await this.#handlePaymentClick(payButton);
@@ -218,14 +300,10 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
218
300
  }
219
301
 
220
302
  async #handlePaymentClick(payButton: any) {
221
- const prevButtonContent = payButton.innerHTML;
222
- payButton.innerHTML = `<div class="lds-dual-ring"></div>`;
223
303
  try {
224
- await this.payment(this.paymentData as IProcessPaymentRequest);
304
+ await this.payment({} as IProcessPaymentRequest);
225
305
  } catch (error) {
226
306
  console.error("Payment error:", error);
227
- } finally {
228
- payButton.innerHTML = prevButtonContent;
229
307
  }
230
308
  }
231
309
 
@@ -264,10 +342,23 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
264
342
  }
265
343
  }
266
344
 
267
- #updatePayButton() {
268
- const payButton = document.querySelector(`#${this.collectorIds.tonderPayButton}`);
269
- if (!payButton) return
270
- payButton.textContent = `Pagar $${this.cartTotal}`;
345
+ #updatePayButton(data?: {cardId?: string | null; updatedTextContent?: boolean; textContent?: string; disabled?: boolean}) {
346
+ try{
347
+ const btnID = data?.cardId && data?.cardId !== "new" ? `#${this.collectorIds.tonderPayButton}${data.cardId}`: `#${this.collectorIds.tonderPayButton}`;
348
+ const updatedText = data?.updatedTextContent || true;
349
+ const btnTextContent = data?.textContent || `Pagar $${this.cartTotal}`;
350
+ const disabledBtn = data?.disabled;
351
+
352
+ const payButton: HTMLElement | null = document.querySelector(btnID);
353
+ if (!payButton) return
354
+ if (updatedText) payButton.textContent = btnTextContent;
355
+ if (disabledBtn !== undefined && 'disabled' in payButton) {
356
+ payButton.disabled = disabledBtn;
357
+ }
358
+ }catch (e){
359
+ console.error("Pay button not found due to update", e);
360
+ }
361
+
271
362
  }
272
363
 
273
364
  #mountRadioButtons (token: string = "") {
@@ -276,7 +367,8 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
276
367
  radio.style.display = "block";
277
368
  radio.onclick = async (event) => {
278
369
  //event.preventDefault();
279
- await this.#handleRadioButtonClick(radio);
370
+ const position = Array.from(radioButtons).indexOf(radio);
371
+ await this.#handleRadioButtonClick(radio, position);
280
372
  };
281
373
  }
282
374
  const cardsButtons: HTMLCollectionOf<Element> = document.getElementsByClassName("card-delete-button");
@@ -320,21 +412,30 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
320
412
  this.cardsInjected = false;
321
413
  await this.#loadCardsList(customerToken)
322
414
  }
323
- async #handleRadioButtonClick (radio: HTMLElement) {
415
+ async #handleRadioButtonClick (radio: HTMLElement, position: number | null = null) {
324
416
  const containerForm: HTMLElement | null = document.querySelector(".container-form");
325
417
  if(containerForm) {
326
418
  containerForm.style.display = radio.id === "new" ? "block" : "none";
327
419
  }
328
420
  if(radio.id === "new") {
421
+ this.#handleOpenCloseCardAccordion(null, true)
329
422
  if(this.radioChecked !== radio.id) {
330
423
  await this.#mountForm();
424
+ this.#mountPayButton()
331
425
  }
332
426
  } else {
427
+ this.#handleOpenCloseCardAccordion(position, position !== null)
333
428
  this.#unmountForm();
334
429
  }
335
430
  this.radioChecked = radio.id;
336
431
  }
337
432
 
433
+ #handleOpenCloseCardAccordion(position: number | null = null, closeAll = false){
434
+ if(closeAll && this.accordionC && 'closeAll' in this.accordionC) this.accordionC.closeAll();
435
+ if(position !== null && this.accordionC && 'open' in this.accordionC) {
436
+ this.accordionC.open(position)
437
+ }
438
+ }
338
439
  async #mountAPMs(){
339
440
  try{
340
441
  const apms = await this._fetchCustomerPaymentMethods();
@@ -403,9 +504,9 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
403
504
  #unmountForm () {
404
505
 
405
506
  this.injected = false
406
-
507
+
407
508
  if(this.collectContainer) {
408
- if("unmount" in this.collectContainer.elements.cardHolderNameElement) this.collectContainer.elements.cardHolderNameElement.unmount()
509
+ if("unmount" in this.collectContainer.elements.cardHolderNameElement) this.collectContainer.elements.cardHolderNameElement.unmount()
409
510
  if("unmount" in this.collectContainer.elements.cardNumberElement) this.collectContainer.elements.cardNumberElement.unmount()
410
511
  if("unmount" in this.collectContainer.elements.expiryYearElement) this.collectContainer.elements.expiryYearElement.unmount()
411
512
  if("unmount" in this.collectContainer.elements.expiryMonthElement) this.collectContainer.elements.expiryMonthElement.unmount()
@@ -436,18 +537,19 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
436
537
 
437
538
  }
438
539
 
439
- async #getCardTokens(tonderButton: string){
440
- if(this.collectContainer && "container" in this.collectContainer && "collect" in this.collectContainer.container) {
540
+ async #getCardTokens(tonderButton: string, cardSelected: string | null = null){
441
541
  try {
442
- const collectResponseSkyflowTonder: any = await this.collectContainer?.container.collect();
443
- return await collectResponseSkyflowTonder["records"][0]["fields"];
542
+ const containerCollect = cardSelected && cardSelected !== "new" ? this.updateCollectContainer?.container:this.collectContainer?.container;
543
+ if(containerCollect && "collect" in containerCollect){
544
+ const collectResponseSkyflowTonder: any = await containerCollect.collect();
545
+ return await collectResponseSkyflowTonder["records"][0]["fields"];
546
+ }else{
547
+ showError("Por favor, verifica todos los campos de tu tarjeta", this.collectorIds.msgError, tonderButton)
548
+ }
444
549
  } catch (error) {
445
550
  showError("Por favor, verifica todos los campos de tu tarjeta", this.collectorIds.msgError, tonderButton)
446
551
  throw error;
447
552
  }
448
- } else {
449
- showError("Por favor, verifica todos los campos de tu tarjeta", this.collectorIds.msgError, tonderButton)
450
- }
451
553
  }
452
554
  async #updateSaveCardButton(disabled = false, text = "Guardar"){
453
555
  try {
@@ -491,17 +593,7 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
491
593
  async _checkout() {
492
594
 
493
595
  try {
494
-
495
- try {
496
-
497
- const selector: any = document.querySelector(`#${this.collectorIds.tonderPayButton}`);
498
-
499
- if(selector){
500
- selector.disabled = true;
501
- selector.innerHTML = "Cargando..."
502
- }
503
-
504
- } catch (error) { }
596
+ this.#updatePayButton({cardId: this.radioChecked, textContent: "Cargando...", disabled: true});
505
597
 
506
598
  if(this.merchantData!) {
507
599
 
@@ -510,8 +602,9 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
510
602
  let cardTokensSkyflowTonder: any;
511
603
 
512
604
  if(this.radioChecked === "new" || this.radioChecked === undefined) {
513
- cardTokensSkyflowTonder = await this.#getCardTokens(this.collectorIds.tonderPayButton!)
605
+ cardTokensSkyflowTonder = await this.#getCardTokens(this.collectorIds.tonderPayButton!, this.radioChecked)
514
606
  } else {
607
+ await this.#getCardTokens(this.collectorIds.tonderPayButton!, this.radioChecked)
515
608
  cardTokensSkyflowTonder = {
516
609
  skyflow_id: this.radioChecked
517
610
  }
@@ -532,6 +625,8 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
532
625
  customer: customerResponse
533
626
  });
534
627
 
628
+
629
+ this.#updatePayButton({cardId: this.radioChecked, disabled: false});
535
630
  if (jsonResponseRouter) {
536
631
  return jsonResponseRouter;
537
632
  } else {
@@ -547,6 +642,7 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
547
642
  showError("Ha ocurrido un error", this.collectorIds.msgError, this.collectorIds.tonderPayButton)
548
643
  throw error;
549
644
  } finally {
645
+ this.#updatePayButton({cardId: this.radioChecked, disabled: false});
550
646
  }
551
647
  };
552
648
 
@@ -571,4 +667,4 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
571
667
  }
572
668
  }
573
669
  }
574
- }
670
+ }