tonder-web-sdk 1.9.2 → 1.11.0-beta.0

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/README.md CHANGED
@@ -139,6 +139,7 @@ const checkoutData = {
139
139
  const apiKey = "4c87c36e697e65ddfe288be0afbe7967ea0ab865";
140
140
  const returnUrl = "http://my-website:8080/checkout"
141
141
  const successUrl = "http://my-website:8080/success"
142
+
142
143
  // if using script tag, it should be initialized like this
143
144
  // new TonderSdk.InlineCheckout
144
145
  const inlineCheckout = new InlineCheckout({
@@ -148,8 +149,22 @@ const inlineCheckout = new InlineCheckout({
148
149
  styles: customStyles
149
150
  });
150
151
 
152
+ // The configureCheckout function allows you to set initial information,
153
+ // such as the customer's email, which is used to retrieve a list of saved cards.
154
+ inlineCheckout.configureCheckout({customer: {email: "example@email.com"}});
155
+
156
+
151
157
  inlineCheckout.injectCheckout();
152
158
 
159
+ // To verify a 3ds transaction you can use the following method
160
+ // It should be called after the injectCheckout method
161
+ // The response status will be one of the following
162
+ // ['Declined', 'Cancelled', 'Failed', 'Success', 'Pending', 'Authorized']
163
+
164
+ inlineCheckout.verify3dsTransaction().then(response => {
165
+ console.log('Verify 3ds response', response)
166
+ })
167
+
153
168
  const response = await inlineCheckout.payment(checkoutData);
154
169
  ```
155
170
 
@@ -163,7 +178,7 @@ const response = await inlineCheckout.payment(checkoutData);
163
178
  | mode | string | 'stage' 'production' 'sandbox', default 'stage' |
164
179
  | apiKey | string | You can take this from you Tonder Dashboard |
165
180
  | backgroundColor | string | Hex color #000000 |
166
- | returnUrl | string | |
181
+ | returnUrl | string | url where the checkout form is mounted (3ds) |
167
182
  | successUrl | string | |
168
183
  | backgroundColor | string | |
169
184
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tonder-web-sdk",
3
- "version": "1.9.2",
3
+ "version": "1.11.0-beta.0",
4
4
  "description": "tonder sdk for integrations",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -39,6 +39,18 @@ export class ThreeDSHandler {
39
39
  }
40
40
  }
41
41
 
42
+ saveCheckoutId(checkoutId) {
43
+ localStorage.setItem('checkout_id', JSON.stringify(checkoutId))
44
+ }
45
+
46
+ removeCheckoutId() {
47
+ localStorage.removeItem("checkout_id")
48
+ }
49
+
50
+ getCurrentCheckoutId() {
51
+ return JSON.parse(localStorage.getItem("checkout_id"));
52
+ }
53
+
42
54
  getUrlWithExpiration() {
43
55
  const item = JSON.parse(localStorage.getItem("verify_transaction_status"))
44
56
  if (!item) return
@@ -117,17 +129,17 @@ export class ThreeDSHandler {
117
129
  return parameters;
118
130
  }
119
131
 
132
+ // TODO: Remove this duplication
120
133
  handleSuccessTransaction(response) {
121
134
  this.removeVerifyTransactionUrl();
122
- window.location = this.successUrl
123
- console.log('Transacción autorizada exitosamente.');
135
+ // window.location = this.successUrl
136
+ console.log('Transacción autorizada');
124
137
  return response;
125
138
  }
126
139
 
127
140
  handleDeclinedTransaction(response) {
128
141
  this.removeVerifyTransactionUrl();
129
- console.log('Transacción rechazada.');
130
- throw new Error("Transacción rechazada.");
142
+ return response;
131
143
  }
132
144
 
133
145
  // TODO: the method below needs to be tested with a real 3DS challenge
@@ -159,15 +171,18 @@ export class ThreeDSHandler {
159
171
  await this.verifyTransactionStatus();
160
172
  }
161
173
 
174
+ // TODO: This method could be removed
162
175
  async handleTransactionResponse(response) {
163
176
  const response_json = await response.json();
164
177
 
165
- if (response_json.status === "Pending") {
178
+ // Azul property
179
+ if (response_json.status === "Pending" && response_json.redirect_post_url) {
166
180
  return await this.handle3dsChallenge(response_json);
167
181
  } else if (["Success", "Authorized"].includes(response_json.status)) {
168
- return this.handleSuccessTransaction(response);
182
+ return this.handleSuccessTransaction(response_json);
169
183
  } else {
170
- return this.handleDeclinedTransaction(response);
184
+ this.handleDeclinedTransaction();
185
+ return response_json
171
186
  }
172
187
  }
173
188
 
@@ -185,19 +200,23 @@ export class ThreeDSHandler {
185
200
  },
186
201
  // body: JSON.stringify(data),
187
202
  });
188
-
189
203
  if (response.status !== 200) {
190
204
  console.error('La verificación de la transacción falló.');
191
- return
205
+ this.removeVerifyTransactionUrl();
206
+ return response
192
207
  }
193
208
 
194
209
  return await this.handleTransactionResponse(response);
195
210
  } catch (error) {
196
211
  console.error('Error al verificar la transacción:', error);
197
- return error;
212
+ this.removeVerifyTransactionUrl();
198
213
  }
199
214
  } else {
200
215
  console.log('No verify_transaction_status_url found');
201
216
  }
202
217
  }
218
+
219
+ setPayload = (payload) => {
220
+ this.payload = payload
221
+ }
203
222
  }
@@ -1,4 +1,4 @@
1
- import { cardItemsTemplate, cardTemplate } from '../helpers/template.js'
1
+ import { apmItemsTemplate, cardItemsTemplate, cardTemplate } from '../helpers/template.js'
2
2
  import { cardTemplateSkeleton } from '../helpers/template-skeleton.js'
3
3
  import {
4
4
  getBusiness,
@@ -9,13 +9,15 @@ import {
9
9
  getOpenpayDeviceSessionID,
10
10
  getCustomerCards,
11
11
  registerCard,
12
- deleteCustomerCard
12
+ deleteCustomerCard,
13
+ getCustomerAPMs
13
14
  } from '../data/api';
14
15
  import {
15
16
  showError,
16
17
  getBrowserInfo,
17
18
  mapCards,
18
19
  showMessage,
20
+ clearSpace
19
21
  } from '../helpers/utils';
20
22
  import { initSkyflow } from '../helpers/skyflow'
21
23
  import { ThreeDSHandler } from './3dsHandler.js';
@@ -24,6 +26,9 @@ import { ThreeDSHandler } from './3dsHandler.js';
24
26
  export class InlineCheckout {
25
27
  static injected = false;
26
28
  static cardsInjected = false
29
+ static apmsInjected = false
30
+ static apmsData = [];
31
+ deletingCards = [];
27
32
  customer = {}
28
33
  items = []
29
34
  baseUrl = null
@@ -41,8 +46,8 @@ export class InlineCheckout {
41
46
  cvv: "collectCvv",
42
47
  tonderPayButton: "tonderPayButton",
43
48
  msgError: "msgError",
44
- msgNotification: "msgNotification"
45
-
49
+ msgNotification: "msgNotification",
50
+ apmsListContainer: "apmsListContainer"
46
51
  }
47
52
 
48
53
  constructor({
@@ -64,6 +69,7 @@ export class InlineCheckout {
64
69
  this.baseUrl = this.#getBaseUrl()
65
70
 
66
71
  this.abortController = new AbortController()
72
+ this.abortRefreshCardsController = new AbortController()
67
73
  this.process3ds = new ThreeDSHandler(
68
74
  { apiKey: apiKey, baseUrl: this.baseUrl, successUrl: successUrl }
69
75
  )
@@ -76,7 +82,7 @@ export class InlineCheckout {
76
82
  'stage': 'https://stage.tonder.io',
77
83
  'development': 'http://localhost:8000',
78
84
  };
79
-
85
+
80
86
  return modeUrls[this.mode] || modeUrls['stage']
81
87
  }
82
88
 
@@ -110,6 +116,31 @@ export class InlineCheckout {
110
116
  }
111
117
  }
112
118
 
119
+ async handle3dsRedirect(response) {
120
+ const iframe = response?.next_action?.iframe_resources?.iframe
121
+
122
+ if (iframe) {
123
+ this.process3ds.loadIframe().then(() => {
124
+ //TODO: Check if this will be necessary on the frontend side
125
+ // after some the tests in production, since the 3DS process
126
+ // doesn't works properly on the sandbox environment
127
+ // setTimeout(() => {
128
+ // process3ds.verifyTransactionStatus();
129
+ // }, 10000);
130
+ this.process3ds.verifyTransactionStatus();
131
+ }).catch((error) => {
132
+ console.log('Error loading iframe:', error)
133
+ })
134
+ } else {
135
+ const redirectUrl = this.process3ds.getRedirectUrl()
136
+ if (redirectUrl) {
137
+ this.process3ds.redirectToChallenge()
138
+ } else {
139
+ return response;
140
+ }
141
+ }
142
+ }
143
+
113
144
  payment(data) {
114
145
  return new Promise(async (resolve, reject) => {
115
146
  try {
@@ -120,36 +151,12 @@ export class InlineCheckout {
120
151
  this.#handleCurrency(data)
121
152
  this.#handleCard(data)
122
153
  const response = await this.#checkout()
123
- if (response) {
124
- const process3ds = new ThreeDSHandler({
125
- baseUrl: this.baseUrl,
126
- apiKey: this.apiKeyTonder,
127
- payload: response,
128
- });
129
- this.callBack(response);
130
-
131
- const iframe = response?.next_action?.iframe_resources?.iframe
132
-
133
- if (iframe) {
134
- process3ds.loadIframe().then(() => {
135
- //TODO: Check if this will be necessary on the frontend side
136
- // after some the tests in production, since the 3DS process
137
- // doesn't works properly on the sandbox environment
138
- // setTimeout(() => {
139
- // process3ds.verifyTransactionStatus();
140
- // }, 10000);
141
- process3ds.verifyTransactionStatus();
142
- }).catch((error) => {
143
- console.log('Error loading iframe:', error)
144
- })
145
- } else {
146
- const redirectUrl = process3ds.getRedirectUrl()
147
- if (redirectUrl) {
148
- process3ds.redirectToChallenge()
149
- } else {
150
- resolve(response);
151
- }
152
- }
154
+ this.process3ds.setPayload(response)
155
+ this.process3ds.saveCheckoutId(response.checkout_id)
156
+ this.callBack(response);
157
+ const payload = await this.handle3dsRedirect(response)
158
+ if (payload) {
159
+ resolve(response);
153
160
  }
154
161
  } catch (error) {
155
162
  reject(error);
@@ -158,7 +165,6 @@ export class InlineCheckout {
158
165
  }
159
166
 
160
167
  #handleCustomer(customer) {
161
- console.log('customer: ', customer)
162
168
  if (!customer) return
163
169
 
164
170
  this.firstName = customer?.firstName
@@ -186,15 +192,15 @@ export class InlineCheckout {
186
192
  }
187
193
 
188
194
  setCartItems(items) {
189
- console.log('items: ', items)
190
195
  this.cartItems = items
191
196
  }
192
197
 
193
- setCustomerEmail (email) {
194
- this.email = email
198
+ configureCheckout(data) {
199
+ if ('customer' in data)
200
+ this.#handleCustomer(data['customer'])
195
201
  }
202
+
196
203
  setCartTotal(total) {
197
- console.log('total: ', total)
198
204
  this.cartTotal = total
199
205
  this.#updatePayButton()
200
206
  }
@@ -211,7 +217,6 @@ export class InlineCheckout {
211
217
 
212
218
  injectCheckout() {
213
219
  if (InlineCheckout.injected) return
214
- this.process3ds.verifyTransactionStatus()
215
220
  const containerTonderCheckout = document.querySelector("#tonder-checkout");
216
221
  if (containerTonderCheckout) {
217
222
  this.#mount(containerTonderCheckout)
@@ -228,15 +233,40 @@ export class InlineCheckout {
228
233
  childList: true,
229
234
  subtree: true,
230
235
  attributeFilter: ['id']
231
- });
236
+ });
237
+ }
238
+
239
+ async verify3dsTransaction () {
240
+ const result3ds = await this.process3ds.verifyTransactionStatus()
241
+ const resultCheckout = await this.resumeCheckout(result3ds)
242
+ this.process3ds.setPayload(resultCheckout)
243
+ if (resultCheckout?.is_route_finished && resultCheckout?.provider === 'tonder') {
244
+ return resultCheckout
245
+ }
246
+ return this.handle3dsRedirect(resultCheckout)
232
247
  }
233
248
 
249
+ async resumeCheckout(response) {
250
+ if (["Failed", "Declined", "Cancelled"].includes(response?.status)) {
251
+ const routerItems = {
252
+ // TODO: Replace this with reponse.checkout_id
253
+ checkout_id: this.process3ds.getCurrentCheckoutId(),
254
+ };
255
+ const routerResponse = await startCheckoutRouter(
256
+ this.baseUrl,
257
+ this.apiKeyTonder,
258
+ routerItems
259
+ );
260
+ return routerResponse
261
+ }
262
+ return response
263
+ }
234
264
 
235
265
  #addGlobalLoader() {
236
266
  let checkoutContainer = document.querySelector("#global-loader");
237
267
  if (checkoutContainer) {
238
- checkoutContainer.innerHTML = cardTemplateSkeleton;
239
- checkoutContainer.style.display = 'block';
268
+ checkoutContainer.innerHTML = cardTemplateSkeleton;
269
+ checkoutContainer.style.display = 'block';
240
270
  }
241
271
  }
242
272
 
@@ -247,8 +277,8 @@ export class InlineCheckout {
247
277
  }
248
278
  }
249
279
 
250
- #mount(containerTonderCheckout){
251
- containerTonderCheckout.innerHTML = cardTemplate;
280
+ #mount(containerTonderCheckout) {
281
+ containerTonderCheckout.innerHTML = cardTemplate({renderPaymentButton: this.renderPaymentButton, customStyles: this.customStyles});
252
282
  this.#addGlobalLoader();
253
283
  this.#mountTonder();
254
284
  InlineCheckout.injected = true;
@@ -267,25 +297,45 @@ export class InlineCheckout {
267
297
  return await customerRegister(this.baseUrl, this.apiKeyTonder, customer, signal);
268
298
  }
269
299
 
300
+ async #mountAPMs(){
301
+ try{
302
+ const apms = await getCustomerAPMs(this.baseUrl, this.apiKeyTonder, "?status=active&page_size=10000");
303
+ if(apms && apms['results'] && apms['results'].length > 0){
304
+ this.apmsData = apms['results']
305
+ this.#loadAPMList(apms['results'])
306
+ }
307
+ }catch(e){
308
+ console.warn("Error getting APMS")
309
+ }
310
+ }
270
311
  async #mountTonder(getCards = true) {
271
312
  this.#mountPayButton()
272
- try{
313
+ try {
273
314
  const {
274
315
  vault_id,
275
316
  vault_url,
276
317
  } = await this.#fetchMerchantData();
277
- if(this.email && getCards){
278
- const customerResponse = await this.getCustomer({email: this.email});
279
- if("auth_token" in customerResponse) {
318
+ if (this.email && getCards) {
319
+ const customerResponse = await this.getCustomer({ email: this.email });
320
+ if ("auth_token" in customerResponse) {
280
321
  const { auth_token } = customerResponse
281
- const cards = await getCustomerCards(this.baseUrl, auth_token);
322
+ const saveCardCheckbox = document.getElementById('save-card-container');
282
323
 
283
- if("cards" in cards) {
284
- const cardsMapped = cards.cards.map(mapCards)
285
- this.#loadCardsList(cardsMapped, auth_token)
324
+ saveCardCheckbox.style.display = 'none';
325
+ if (this.mode !== 'production') {
326
+ const cards = await getCustomerCards(this.baseUrl, auth_token);
327
+ saveCardCheckbox.style.display = '';
328
+
329
+ if ("cards" in cards) {
330
+ const cardsMapped = cards.cards.map(mapCards)
331
+ this.#loadCardsList(cardsMapped, auth_token)
332
+ }
286
333
  }
334
+
335
+
287
336
  }
288
337
  }
338
+ this.#mountAPMs();
289
339
 
290
340
  this.collectContainer = await initSkyflow(
291
341
  vault_id,
@@ -299,7 +349,7 @@ export class InlineCheckout {
299
349
  setTimeout(() => {
300
350
  this.#removeGlobalLoader()
301
351
  }, 800)
302
- }catch(e){
352
+ } catch (e) {
303
353
  if (e && e.name !== 'AbortError') {
304
354
  this.#removeGlobalLoader()
305
355
  showError("No se pudieron cargar los datos del comercio.")
@@ -310,6 +360,7 @@ export class InlineCheckout {
310
360
  removeCheckout() {
311
361
  InlineCheckout.injected = false
312
362
  InlineCheckout.cardsInjected = false
363
+ InlineCheckout.apmsInjected = false
313
364
  // Cancel all requests
314
365
  this.abortController.abort();
315
366
  this.abortController = new AbortController();
@@ -340,9 +391,9 @@ export class InlineCheckout {
340
391
  const total = Number(this.cartTotal)
341
392
 
342
393
  let cardTokens = null;
343
- if(this.radioChecked === "new" || this.radioChecked === undefined){
394
+ if (this.radioChecked === "new" || this.radioChecked === undefined) {
344
395
  cardTokens = await this.#getCardTokens();
345
- }else{
396
+ } else {
346
397
  cardTokens = {
347
398
  skyflow_id: this.radioChecked
348
399
  }
@@ -358,24 +409,24 @@ export class InlineCheckout {
358
409
  }
359
410
 
360
411
  const { id, auth_token } = await this.getCustomer(
361
- this.customer,
412
+ this.customer,
362
413
  this.abortController.signal
363
414
  )
364
- if(auth_token && this.email){
415
+ if (auth_token && this.email) {
365
416
  const saveCard = document.getElementById("save-checkout-card");
366
- if(saveCard && "checked" in saveCard && saveCard.checked){
417
+ if (saveCard && "checked" in saveCard && saveCard.checked) {
367
418
  await registerCard(this.baseUrl, auth_token, { skyflow_id: cardTokens.skyflow_id });
368
-
419
+
369
420
  this.cardsInjected = false;
370
421
 
371
422
  const cards = await getCustomerCards(this.baseUrl, auth_token);
372
- if("cards" in cards) {
423
+ if ("cards" in cards) {
373
424
  const cardsMapped = cards.cards.map((card) => mapCards(card))
374
425
  this.#loadCardsList(cardsMapped, auth_token)
375
426
  }
376
427
 
377
428
  showMessage("Tarjeta registrada con éxito", this.collectorIds.msgNotification);
378
-
429
+
379
430
  }
380
431
  }
381
432
  var orderItems = {
@@ -389,7 +440,6 @@ export class InlineCheckout {
389
440
  is_oneclick: true,
390
441
  items: this.cartItems,
391
442
  };
392
- console.log('orderItems: ', orderItems)
393
443
  const jsonResponseOrder = await createOrder(
394
444
  this.baseUrl,
395
445
  this.apiKeyTonder,
@@ -413,9 +463,10 @@ export class InlineCheckout {
413
463
  paymentItems
414
464
  );
415
465
 
466
+ const selected_apm = this.apmsData ? this.apmsData.find((iapm) => iapm.pk === this.radioChecked):{};
467
+
416
468
  // Checkout router
417
469
  const routerItems = {
418
- card: cardTokens,
419
470
  name: this.firstName || "",
420
471
  last_name: this.lastName || "",
421
472
  email_client: this.email,
@@ -437,6 +488,10 @@ export class InlineCheckout {
437
488
  metadata: this.metadata,
438
489
  browser_info: getBrowserInfo(),
439
490
  currency: this.currency,
491
+ ...( !!selected_apm
492
+ ? {payment_method: selected_apm.payment_method}
493
+ : {card: cardTokens}
494
+ )
440
495
  };
441
496
  const jsonResponseRouter = await startCheckoutRouter(
442
497
  this.baseUrl,
@@ -460,8 +515,8 @@ export class InlineCheckout {
460
515
  }
461
516
  };
462
517
 
463
- #loadCardsList (cards, token) {
464
- if(this.cardsInjected) return;
518
+ #loadCardsList(cards, token) {
519
+ if (this.cardsInjected) return;
465
520
  const injectInterval = setInterval(() => {
466
521
  const queryElement = document.querySelector(`#${this.collectorIds.cardsListContainer}`);
467
522
  if (queryElement && InlineCheckout.injected) {
@@ -473,7 +528,25 @@ export class InlineCheckout {
473
528
  }, 500);
474
529
  }
475
530
 
476
- #mountRadioButtons (token) {
531
+ #loadAPMList(apms) {
532
+ if (this.apmsInjected) return;
533
+ const injectInterval = setInterval(() => {
534
+ const queryElement = document.querySelector(`#${this.collectorIds.apmsListContainer}`);
535
+ if (queryElement && InlineCheckout.injected) {
536
+ const filteredAndSortedApms = apms
537
+ .filter((apm) =>
538
+ clearSpace(apm.category.toLowerCase()) !== 'cards' && apm.status.toLowerCase() === 'active')
539
+ .sort((a, b) => a.priority - b.priority);
540
+
541
+ queryElement.innerHTML = apmItemsTemplate(filteredAndSortedApms);
542
+ clearInterval(injectInterval);
543
+ this.#mountRadioButtons();
544
+ this.apmsInjected = true;
545
+ }
546
+ }, 500);
547
+ }
548
+
549
+ #mountRadioButtons(token = '') {
477
550
  const radioButtons = document.getElementsByName(`card_selected`);
478
551
  for (const radio of radioButtons) {
479
552
  radio.style.display = "block";
@@ -490,14 +563,14 @@ export class InlineCheckout {
490
563
  }
491
564
  }
492
565
 
493
- async #handleRadioButtonClick (radio) {
494
- if(radio.id === this.radioChecked || ( radio.id === "new" && this.radioChecked === undefined)) return;
566
+ async #handleRadioButtonClick(radio) {
567
+ if (radio.id === this.radioChecked || (radio.id === "new" && this.radioChecked === undefined)) return;
495
568
  const containerForm = document.querySelector(".container-form");
496
- if(containerForm) {
569
+ if (containerForm) {
497
570
  containerForm.style.display = radio.id === "new" ? "block" : "none";
498
571
  }
499
- if(radio.id === "new") {
500
- if(this.radioChecked !== radio.id) {
572
+ if (radio.id === "new") {
573
+ if (this.radioChecked !== radio.id) {
501
574
  this.#addGlobalLoader()
502
575
  this.#mountTonder(false);
503
576
  InlineCheckout.injected = true;
@@ -508,32 +581,45 @@ export class InlineCheckout {
508
581
  this.radioChecked = radio.id;
509
582
  }
510
583
 
511
- async #handleDeleteCardButtonClick (customerToken, button) {
584
+ async #handleDeleteCardButtonClick(customerToken, button) {
512
585
  const id = button.attributes.getNamedItem("id")
513
586
  const skyflow_id = id?.value?.split("_")?.[2]
514
- if(skyflow_id) {
587
+ if (skyflow_id) {
515
588
  const cardClicked = document.querySelector(`#card_container-${skyflow_id}`);
516
- if(cardClicked) {
589
+ if (cardClicked) {
517
590
  cardClicked.style.display = "none"
518
591
  }
519
- await deleteCustomerCard(this.baseUrl, customerToken, skyflow_id)
520
- this.cardsInjected = false
521
- const cards = await getCustomerCards(this.baseUrl, customerToken)
522
- if("cards" in cards) {
523
- const cardsMapped = cards.cards.map(mapCards)
524
- this.#loadCardsList(cardsMapped, customerToken)
592
+ try {
593
+ this.deletingCards.push(skyflow_id);
594
+ if (this.abortRefreshCardsController) {
595
+ this.abortRefreshCardsController.abort();
596
+ this.abortRefreshCardsController = new AbortController();
597
+ }
598
+ await deleteCustomerCard(this.baseUrl, customerToken, skyflow_id)
599
+ } catch {
600
+ } finally {
601
+ this.deletingCards = this.deletingCards.filter(id => id !== skyflow_id);
602
+ this.#refreshCardOnDelete(customerToken)
525
603
  }
526
604
  }
527
605
  }
528
-
529
- #unmountForm () {
606
+ async #refreshCardOnDelete(customerToken) {
607
+ if (this.deletingCards.length > 0) return;
608
+ this.cardsInjected = false
609
+ const cards = await getCustomerCards(this.baseUrl, customerToken, "", this.abortRefreshCardsController.signal)
610
+ if ("cards" in cards) {
611
+ const cardsMapped = cards.cards.map(mapCards)
612
+ this.#loadCardsList(cardsMapped, customerToken)
613
+ }
614
+ }
615
+ #unmountForm() {
530
616
  InlineCheckout.injected = false
531
- if(this.collectContainer) {
532
- if("unmount" in this.collectContainer.elements.cardHolderNameElement) this.collectContainer.elements.cardHolderNameElement.unmount()
533
- if("unmount" in this.collectContainer.elements.cardNumberElement) this.collectContainer.elements.cardNumberElement.unmount()
534
- if("unmount" in this.collectContainer.elements.expiryYearElement) this.collectContainer.elements.expiryYearElement.unmount()
535
- if("unmount" in this.collectContainer.elements.expiryMonthElement) this.collectContainer.elements.expiryMonthElement.unmount()
536
- if("unmount" in this.collectContainer.elements.cvvElement) this.collectContainer.elements.cvvElement.unmount()
617
+ if (this.collectContainer) {
618
+ if ("unmount" in this.collectContainer.elements.cardHolderNameElement) this.collectContainer.elements.cardHolderNameElement.unmount()
619
+ if ("unmount" in this.collectContainer.elements.cardNumberElement) this.collectContainer.elements.cardNumberElement.unmount()
620
+ if ("unmount" in this.collectContainer.elements.expiryYearElement) this.collectContainer.elements.expiryYearElement.unmount()
621
+ if ("unmount" in this.collectContainer.elements.expiryMonthElement) this.collectContainer.elements.expiryMonthElement.unmount()
622
+ if ("unmount" in this.collectContainer.elements.cvvElement) this.collectContainer.elements.cvvElement.unmount()
537
623
  }
538
624
  }
539
625
  }
package/src/data/api.js CHANGED
@@ -145,7 +145,7 @@ export async function deleteCustomerCard(baseUrlTonder, customerToken, skyflowId
145
145
  headers: {
146
146
  'Authorization': `Token ${customerToken}`,
147
147
  'Content-Type': 'application/json'
148
- },
148
+ }
149
149
  });
150
150
 
151
151
  if (response.ok) return true;
@@ -154,7 +154,7 @@ export async function deleteCustomerCard(baseUrlTonder, customerToken, skyflowId
154
154
  throw buildErrorResponseFromCatch(error);
155
155
  }
156
156
  }
157
- export async function getCustomerCards(baseUrlTonder, customerToken, query = "") {
157
+ export async function getCustomerCards(baseUrlTonder, customerToken, query = "", signal) {
158
158
  try {
159
159
  const response = await fetch(`${baseUrlTonder}/api/v1/cards/${query}`, {
160
160
  method: 'GET',
@@ -162,6 +162,28 @@ export async function getCustomerCards(baseUrlTonder, customerToken, query = "")
162
162
  'Authorization': `Token ${customerToken}`,
163
163
  'Content-Type': 'application/json'
164
164
  },
165
+ signal
166
+ });
167
+
168
+ if (response.ok) return await response.json();
169
+ throw await buildErrorResponse(response);
170
+ } catch (error) {
171
+ throw buildErrorResponseFromCatch(error);
172
+ }
173
+ }
174
+
175
+ export async function getCustomerAPMs(baseUrlTonder, apiKeyTonder, query = "", signal) {
176
+ try {
177
+ const response = await fetch(
178
+ // `${baseUrlTonder}/api/v1/payment_methods${query}`,
179
+ `http://localhost:8000/api/v1/payment_methods${query}`,
180
+ {
181
+ method: 'GET',
182
+ headers: {
183
+ Authorization: `Token ${apiKeyTonder}`,
184
+ 'Content-Type': 'application/json'
185
+ },
186
+ signal
165
187
  });
166
188
 
167
189
  if (response.ok) return await response.json();