@tonder.io/ionic-full-sdk 0.0.46-beta.9 → 0.0.47-beta.DEV1406.152469c

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.
@@ -4,7 +4,7 @@ import {
4
4
  showMessage,
5
5
  mapCards,
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
@@ -183,8 +189,9 @@ 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
+ queryElement.innerHTML = cardItemsTemplate(!!this.customStyles, cards, {collectorIds: this.collectorIds, renderPaymentButton: this.renderPaymentButton})
187
193
  clearInterval(injectInterval)
194
+ this.#generateCardsAccordion()
188
195
  this.#mountRadioButtons(customerToken)
189
196
  this.cardsInjected = true
190
197
  }
@@ -192,24 +199,92 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
192
199
  }
193
200
  }
194
201
 
195
- #mountPayButton() {
202
+ #generateCardsAccordion(){
203
+ this.accordionC = new Accordion(".accordion-container", {
204
+ triggerClass: "card-item-label",
205
+ duration: 300,
206
+ collapse: true,
207
+ showMultiple: false,
208
+ onOpen: async (currentElement: any) => {
209
+ await this.#handleOpenCardAccordion(currentElement)
210
+ }
211
+ });
212
+ }
213
+
214
+ async #handleOpenCardAccordion(currentElement: any){
215
+ const { vault_id, vault_url } = this.merchantData!;
216
+ const container_radio_id = currentElement.id.replace("card_container-", "");
217
+
218
+ if (this.updateCollectContainer && "unmount" in this.updateCollectContainer?.elements?.cvvElement) {
219
+ this.updateCollectContainer.elements.cvvElement.unmount()
220
+ }
221
+
222
+ document.querySelectorAll(".cvvContainer").forEach((container) => {
223
+ container.classList.remove("show");
224
+ });
225
+
226
+ const radio_card = document.getElementById(container_radio_id) as HTMLInputElement;
227
+ if (radio_card) radio_card.checked = true;
228
+
229
+ try{
230
+ this.updateCollectContainer = await initUpdateSkyflow(
231
+ container_radio_id,
232
+ vault_id,
233
+ vault_url,
234
+ this.baseUrl,
235
+ this.abortController.signal,
236
+ this.customStyles,
237
+ this.collectorIds,
238
+ this.apiKeyTonder
239
+
240
+ );
241
+ setTimeout(() => {
242
+ const containerCvv = document.querySelector(`#cvvContainer${container_radio_id}`)
243
+ if(containerCvv) containerCvv.classList.add("show");
244
+ }, 5)
245
+ this.#mountPayButton(container_radio_id)
246
+ }catch (e){
247
+ console.error("Ha ocurrido un error", e);
248
+ }
249
+
250
+ if (radio_card) await this.#handleRadioButtonClick(radio_card)
251
+ }
252
+
253
+
254
+ #mountPayButton(cardId="") {
196
255
  if (!this.renderPaymentButton) return;
256
+ const btnID = `#${this.collectorIds.tonderPayButton}${cardId}`;
257
+ const payButton: HTMLElement | null = document.querySelector(btnID);
258
+ const containerID = `#acContainer${cardId}`;
259
+ const container = document.querySelector(containerID);
197
260
 
198
- const payButton: HTMLElement | null = document.querySelector(`#${this.collectorIds.tonderPayButton}`);
199
-
200
261
  if (!payButton) {
201
262
  console.error("Pay button not found");
202
263
  return;
203
264
  }
204
265
 
266
+ if (cardId !== "") {
267
+ const sdkPayButton: HTMLElement | null = document.querySelector(`#${this.collectorIds.tonderPayButton}`);
268
+ if(sdkPayButton){
269
+ sdkPayButton.style.display = "none";
270
+ }
271
+ }
272
+
205
273
  const LOCALE_MONEY = "en-Latn-US";
206
274
 
207
275
  payButton.style.display = "block";
208
-
276
+
209
277
  const inCartTotal = Intl.NumberFormat(LOCALE_MONEY, { minimumFractionDigits: 2 }).format(Number(this.cartTotal || 0));
210
-
278
+
211
279
  payButton.textContent = `Pagar $${inCartTotal}`;
212
-
280
+
281
+ document.querySelectorAll(".ac-card-panel-container").forEach((cont) => {
282
+ cont.classList.remove("show");
283
+ });
284
+ if (container) {
285
+ container.classList.add("show");
286
+ }
287
+
213
288
  payButton.onclick = async (event) => {
214
289
  event.preventDefault();
215
290
  await this.#handlePaymentClick(payButton);
@@ -221,7 +296,7 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
221
296
  const prevButtonContent = payButton.innerHTML;
222
297
  payButton.innerHTML = `<div class="lds-dual-ring"></div>`;
223
298
  try {
224
- await this.payment(this.paymentData as IProcessPaymentRequest);
299
+ await this.payment({} as IProcessPaymentRequest);
225
300
  } catch (error) {
226
301
  console.error("Payment error:", error);
227
302
  } finally {
@@ -264,10 +339,23 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
264
339
  }
265
340
  }
266
341
 
267
- #updatePayButton() {
268
- const payButton = document.querySelector(`#${this.collectorIds.tonderPayButton}`);
269
- if (!payButton) return
270
- payButton.textContent = `Pagar $${this.cartTotal}`;
342
+ #updatePayButton(data?: {cardId?: string | null; updatedTextContent?: boolean; textContent?: string; disabled?: boolean}) {
343
+ try{
344
+ const btnID = data?.cardId ? `#${this.collectorIds.tonderPayButton}${data.cardId}`: `#${this.collectorIds.tonderPayButton}`;
345
+ const updatedText = data?.updatedTextContent || true;
346
+ const btnTextContent = data?.textContent || `Pagar $${this.cartTotal}`;
347
+ const disabledBtn = data?.disabled;
348
+
349
+ const payButton: HTMLElement | null = document.querySelector(btnID);
350
+ if (!payButton) return
351
+ if (updatedText) payButton.textContent = btnTextContent;
352
+ if (disabledBtn !== undefined && 'disabled' in payButton) {
353
+ payButton.disabled = disabledBtn;
354
+ }
355
+ }catch (e){
356
+ console.error("Pay button not found due to update", e);
357
+ }
358
+
271
359
  }
272
360
 
273
361
  #mountRadioButtons (token: string = "") {
@@ -276,7 +364,8 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
276
364
  radio.style.display = "block";
277
365
  radio.onclick = async (event) => {
278
366
  //event.preventDefault();
279
- await this.#handleRadioButtonClick(radio);
367
+ const position = Array.from(radioButtons).indexOf(radio);
368
+ await this.#handleRadioButtonClick(radio, position);
280
369
  };
281
370
  }
282
371
  const cardsButtons: HTMLCollectionOf<Element> = document.getElementsByClassName("card-delete-button");
@@ -320,21 +409,30 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
320
409
  this.cardsInjected = false;
321
410
  await this.#loadCardsList(customerToken)
322
411
  }
323
- async #handleRadioButtonClick (radio: HTMLElement) {
412
+ async #handleRadioButtonClick (radio: HTMLElement, position: number | null = null) {
324
413
  const containerForm: HTMLElement | null = document.querySelector(".container-form");
325
414
  if(containerForm) {
326
415
  containerForm.style.display = radio.id === "new" ? "block" : "none";
327
416
  }
328
417
  if(radio.id === "new") {
418
+ this.#handleOpenCloseCardAccordion(null, true)
329
419
  if(this.radioChecked !== radio.id) {
330
420
  await this.#mountForm();
421
+ this.#mountPayButton()
331
422
  }
332
423
  } else {
424
+ this.#handleOpenCloseCardAccordion(position, position !== null)
333
425
  this.#unmountForm();
334
426
  }
335
427
  this.radioChecked = radio.id;
336
428
  }
337
429
 
430
+ #handleOpenCloseCardAccordion(position: number | null = null, closeAll = false){
431
+ if(closeAll && this.accordionC && 'closeAll' in this.accordionC) this.accordionC.closeAll();
432
+ if(position !== null && this.accordionC && 'open' in this.accordionC) {
433
+ this.accordionC.open(position)
434
+ }
435
+ }
338
436
  async #mountAPMs(){
339
437
  try{
340
438
  const apms = await this._fetchCustomerPaymentMethods();
@@ -403,9 +501,9 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
403
501
  #unmountForm () {
404
502
 
405
503
  this.injected = false
406
-
504
+
407
505
  if(this.collectContainer) {
408
- if("unmount" in this.collectContainer.elements.cardHolderNameElement) this.collectContainer.elements.cardHolderNameElement.unmount()
506
+ if("unmount" in this.collectContainer.elements.cardHolderNameElement) this.collectContainer.elements.cardHolderNameElement.unmount()
409
507
  if("unmount" in this.collectContainer.elements.cardNumberElement) this.collectContainer.elements.cardNumberElement.unmount()
410
508
  if("unmount" in this.collectContainer.elements.expiryYearElement) this.collectContainer.elements.expiryYearElement.unmount()
411
509
  if("unmount" in this.collectContainer.elements.expiryMonthElement) this.collectContainer.elements.expiryMonthElement.unmount()
@@ -436,18 +534,19 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
436
534
 
437
535
  }
438
536
 
439
- async #getCardTokens(tonderButton: string){
440
- if(this.collectContainer && "container" in this.collectContainer && "collect" in this.collectContainer.container) {
537
+ async #getCardTokens(tonderButton: string, cardSelected: string | null = null){
441
538
  try {
442
- const collectResponseSkyflowTonder: any = await this.collectContainer?.container.collect();
443
- return await collectResponseSkyflowTonder["records"][0]["fields"];
539
+ const containerCollect = cardSelected && cardSelected !== "new" ? this.updateCollectContainer?.container:this.collectContainer?.container;
540
+ if(containerCollect && "collect" in containerCollect){
541
+ const collectResponseSkyflowTonder: any = await containerCollect.collect();
542
+ return await collectResponseSkyflowTonder["records"][0]["fields"];
543
+ }else{
544
+ showError("Por favor, verifica todos los campos de tu tarjeta", this.collectorIds.msgError, tonderButton)
545
+ }
444
546
  } catch (error) {
445
547
  showError("Por favor, verifica todos los campos de tu tarjeta", this.collectorIds.msgError, tonderButton)
446
548
  throw error;
447
549
  }
448
- } else {
449
- showError("Por favor, verifica todos los campos de tu tarjeta", this.collectorIds.msgError, tonderButton)
450
- }
451
550
  }
452
551
  async #updateSaveCardButton(disabled = false, text = "Guardar"){
453
552
  try {
@@ -491,17 +590,7 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
491
590
  async _checkout() {
492
591
 
493
592
  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) { }
593
+ this.#updatePayButton({textContent: "Cargando...", disabled: true});
505
594
 
506
595
  if(this.merchantData!) {
507
596
 
@@ -510,8 +599,10 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
510
599
  let cardTokensSkyflowTonder: any;
511
600
 
512
601
  if(this.radioChecked === "new" || this.radioChecked === undefined) {
513
- cardTokensSkyflowTonder = await this.#getCardTokens(this.collectorIds.tonderPayButton!)
602
+ cardTokensSkyflowTonder = await this.#getCardTokens(this.collectorIds.tonderPayButton!, this.radioChecked)
514
603
  } else {
604
+ this.#updatePayButton({cardId: this.radioChecked, textContent: "Cargando...", disabled: true});
605
+ await this.#getCardTokens(this.collectorIds.tonderPayButton!, this.radioChecked)
515
606
  cardTokensSkyflowTonder = {
516
607
  skyflow_id: this.radioChecked
517
608
  }
@@ -532,6 +623,8 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
532
623
  customer: customerResponse
533
624
  });
534
625
 
626
+
627
+ this.#updatePayButton({cardId: this.radioChecked, disabled: false});
535
628
  if (jsonResponseRouter) {
536
629
  return jsonResponseRouter;
537
630
  } else {
@@ -571,4 +664,4 @@ export class InlineCheckout extends BaseInlineCheckout implements IInlineCheckou
571
664
  }
572
665
  }
573
666
  }
574
- }
667
+ }