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

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