tonder-web-sdk 1.9.2 → 1.10.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.
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.10.2",
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
  }
@@ -24,6 +24,7 @@ import { ThreeDSHandler } from './3dsHandler.js';
24
24
  export class InlineCheckout {
25
25
  static injected = false;
26
26
  static cardsInjected = false
27
+ deletingCards = [];
27
28
  customer = {}
28
29
  items = []
29
30
  baseUrl = null
@@ -42,7 +43,6 @@ export class InlineCheckout {
42
43
  tonderPayButton: "tonderPayButton",
43
44
  msgError: "msgError",
44
45
  msgNotification: "msgNotification"
45
-
46
46
  }
47
47
 
48
48
  constructor({
@@ -64,6 +64,7 @@ export class InlineCheckout {
64
64
  this.baseUrl = this.#getBaseUrl()
65
65
 
66
66
  this.abortController = new AbortController()
67
+ this.abortRefreshCardsController = new AbortController()
67
68
  this.process3ds = new ThreeDSHandler(
68
69
  { apiKey: apiKey, baseUrl: this.baseUrl, successUrl: successUrl }
69
70
  )
@@ -76,7 +77,7 @@ export class InlineCheckout {
76
77
  'stage': 'https://stage.tonder.io',
77
78
  'development': 'http://localhost:8000',
78
79
  };
79
-
80
+
80
81
  return modeUrls[this.mode] || modeUrls['stage']
81
82
  }
82
83
 
@@ -110,6 +111,31 @@ export class InlineCheckout {
110
111
  }
111
112
  }
112
113
 
114
+ async handle3dsRedirect(response) {
115
+ const iframe = response?.next_action?.iframe_resources?.iframe
116
+
117
+ if (iframe) {
118
+ this.process3ds.loadIframe().then(() => {
119
+ //TODO: Check if this will be necessary on the frontend side
120
+ // after some the tests in production, since the 3DS process
121
+ // doesn't works properly on the sandbox environment
122
+ // setTimeout(() => {
123
+ // process3ds.verifyTransactionStatus();
124
+ // }, 10000);
125
+ this.process3ds.verifyTransactionStatus();
126
+ }).catch((error) => {
127
+ console.log('Error loading iframe:', error)
128
+ })
129
+ } else {
130
+ const redirectUrl = this.process3ds.getRedirectUrl()
131
+ if (redirectUrl) {
132
+ this.process3ds.redirectToChallenge()
133
+ } else {
134
+ return response;
135
+ }
136
+ }
137
+ }
138
+
113
139
  payment(data) {
114
140
  return new Promise(async (resolve, reject) => {
115
141
  try {
@@ -120,36 +146,12 @@ export class InlineCheckout {
120
146
  this.#handleCurrency(data)
121
147
  this.#handleCard(data)
122
148
  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
- }
149
+ this.process3ds.setPayload(response)
150
+ this.process3ds.saveCheckoutId(response.checkout_id)
151
+ this.callBack(response);
152
+ const payload = await this.handle3dsRedirect(response)
153
+ if (payload) {
154
+ resolve(response);
153
155
  }
154
156
  } catch (error) {
155
157
  reject(error);
@@ -158,7 +160,6 @@ export class InlineCheckout {
158
160
  }
159
161
 
160
162
  #handleCustomer(customer) {
161
- console.log('customer: ', customer)
162
163
  if (!customer) return
163
164
 
164
165
  this.firstName = customer?.firstName
@@ -186,15 +187,15 @@ export class InlineCheckout {
186
187
  }
187
188
 
188
189
  setCartItems(items) {
189
- console.log('items: ', items)
190
190
  this.cartItems = items
191
191
  }
192
192
 
193
- setCustomerEmail (email) {
194
- this.email = email
193
+ configureCheckout(data) {
194
+ if ('customer' in data)
195
+ this.#handleCustomer(data['customer'])
195
196
  }
197
+
196
198
  setCartTotal(total) {
197
- console.log('total: ', total)
198
199
  this.cartTotal = total
199
200
  this.#updatePayButton()
200
201
  }
@@ -211,7 +212,6 @@ export class InlineCheckout {
211
212
 
212
213
  injectCheckout() {
213
214
  if (InlineCheckout.injected) return
214
- this.process3ds.verifyTransactionStatus()
215
215
  const containerTonderCheckout = document.querySelector("#tonder-checkout");
216
216
  if (containerTonderCheckout) {
217
217
  this.#mount(containerTonderCheckout)
@@ -228,15 +228,40 @@ export class InlineCheckout {
228
228
  childList: true,
229
229
  subtree: true,
230
230
  attributeFilter: ['id']
231
- });
231
+ });
232
232
  }
233
233
 
234
+ async verify3dsTransaction () {
235
+ const result3ds = await this.process3ds.verifyTransactionStatus()
236
+ const resultCheckout = await this.resumeCheckout(result3ds)
237
+ this.process3ds.setPayload(resultCheckout)
238
+ if (resultCheckout?.is_route_finished && resultCheckout?.provider === 'tonder') {
239
+ return resultCheckout
240
+ }
241
+ return this.handle3dsRedirect(resultCheckout)
242
+ }
243
+
244
+ async resumeCheckout(response) {
245
+ if (["Failed", "Declined", "Cancelled"].includes(response?.status)) {
246
+ const routerItems = {
247
+ // TODO: Replace this with reponse.checkout_id
248
+ checkout_id: this.process3ds.getCurrentCheckoutId(),
249
+ };
250
+ const routerResponse = await startCheckoutRouter(
251
+ this.baseUrl,
252
+ this.apiKeyTonder,
253
+ routerItems
254
+ );
255
+ return routerResponse
256
+ }
257
+ return response
258
+ }
234
259
 
235
260
  #addGlobalLoader() {
236
261
  let checkoutContainer = document.querySelector("#global-loader");
237
262
  if (checkoutContainer) {
238
- checkoutContainer.innerHTML = cardTemplateSkeleton;
239
- checkoutContainer.style.display = 'block';
263
+ checkoutContainer.innerHTML = cardTemplateSkeleton;
264
+ checkoutContainer.style.display = 'block';
240
265
  }
241
266
  }
242
267
 
@@ -247,7 +272,7 @@ export class InlineCheckout {
247
272
  }
248
273
  }
249
274
 
250
- #mount(containerTonderCheckout){
275
+ #mount(containerTonderCheckout) {
251
276
  containerTonderCheckout.innerHTML = cardTemplate;
252
277
  this.#addGlobalLoader();
253
278
  this.#mountTonder();
@@ -269,20 +294,28 @@ export class InlineCheckout {
269
294
 
270
295
  async #mountTonder(getCards = true) {
271
296
  this.#mountPayButton()
272
- try{
297
+ try {
273
298
  const {
274
299
  vault_id,
275
300
  vault_url,
276
301
  } = await this.#fetchMerchantData();
277
- if(this.email && getCards){
278
- const customerResponse = await this.getCustomer({email: this.email});
279
- if("auth_token" in customerResponse) {
302
+ console.log("this.email : ", this.email )
303
+ if (this.email && getCards) {
304
+ const customerResponse = await this.getCustomer({ email: this.email });
305
+ if ("auth_token" in customerResponse) {
280
306
  const { auth_token } = customerResponse
281
- const cards = await getCustomerCards(this.baseUrl, auth_token);
307
+ const saveCardCheckbox = document.getElementById('save-card-container');
282
308
 
283
- if("cards" in cards) {
284
- const cardsMapped = cards.cards.map(mapCards)
285
- this.#loadCardsList(cardsMapped, auth_token)
309
+ saveCardCheckbox.style.display = 'none';
310
+ console.log("mode: ", this.mode)
311
+ if (this.mode !== 'production') {
312
+ const cards = await getCustomerCards(this.baseUrl, auth_token);
313
+ saveCardCheckbox.style.display = '';
314
+
315
+ if ("cards" in cards) {
316
+ const cardsMapped = cards.cards.map(mapCards)
317
+ this.#loadCardsList(cardsMapped, auth_token)
318
+ }
286
319
  }
287
320
  }
288
321
  }
@@ -299,7 +332,7 @@ export class InlineCheckout {
299
332
  setTimeout(() => {
300
333
  this.#removeGlobalLoader()
301
334
  }, 800)
302
- }catch(e){
335
+ } catch (e) {
303
336
  if (e && e.name !== 'AbortError') {
304
337
  this.#removeGlobalLoader()
305
338
  showError("No se pudieron cargar los datos del comercio.")
@@ -340,9 +373,9 @@ export class InlineCheckout {
340
373
  const total = Number(this.cartTotal)
341
374
 
342
375
  let cardTokens = null;
343
- if(this.radioChecked === "new" || this.radioChecked === undefined){
376
+ if (this.radioChecked === "new" || this.radioChecked === undefined) {
344
377
  cardTokens = await this.#getCardTokens();
345
- }else{
378
+ } else {
346
379
  cardTokens = {
347
380
  skyflow_id: this.radioChecked
348
381
  }
@@ -358,24 +391,24 @@ export class InlineCheckout {
358
391
  }
359
392
 
360
393
  const { id, auth_token } = await this.getCustomer(
361
- this.customer,
394
+ this.customer,
362
395
  this.abortController.signal
363
396
  )
364
- if(auth_token && this.email){
397
+ if (auth_token && this.email) {
365
398
  const saveCard = document.getElementById("save-checkout-card");
366
- if(saveCard && "checked" in saveCard && saveCard.checked){
399
+ if (saveCard && "checked" in saveCard && saveCard.checked) {
367
400
  await registerCard(this.baseUrl, auth_token, { skyflow_id: cardTokens.skyflow_id });
368
-
401
+
369
402
  this.cardsInjected = false;
370
403
 
371
404
  const cards = await getCustomerCards(this.baseUrl, auth_token);
372
- if("cards" in cards) {
405
+ if ("cards" in cards) {
373
406
  const cardsMapped = cards.cards.map((card) => mapCards(card))
374
407
  this.#loadCardsList(cardsMapped, auth_token)
375
408
  }
376
409
 
377
410
  showMessage("Tarjeta registrada con éxito", this.collectorIds.msgNotification);
378
-
411
+
379
412
  }
380
413
  }
381
414
  var orderItems = {
@@ -389,7 +422,6 @@ export class InlineCheckout {
389
422
  is_oneclick: true,
390
423
  items: this.cartItems,
391
424
  };
392
- console.log('orderItems: ', orderItems)
393
425
  const jsonResponseOrder = await createOrder(
394
426
  this.baseUrl,
395
427
  this.apiKeyTonder,
@@ -460,8 +492,8 @@ export class InlineCheckout {
460
492
  }
461
493
  };
462
494
 
463
- #loadCardsList (cards, token) {
464
- if(this.cardsInjected) return;
495
+ #loadCardsList(cards, token) {
496
+ if (this.cardsInjected) return;
465
497
  const injectInterval = setInterval(() => {
466
498
  const queryElement = document.querySelector(`#${this.collectorIds.cardsListContainer}`);
467
499
  if (queryElement && InlineCheckout.injected) {
@@ -473,7 +505,7 @@ export class InlineCheckout {
473
505
  }, 500);
474
506
  }
475
507
 
476
- #mountRadioButtons (token) {
508
+ #mountRadioButtons(token) {
477
509
  const radioButtons = document.getElementsByName(`card_selected`);
478
510
  for (const radio of radioButtons) {
479
511
  radio.style.display = "block";
@@ -490,14 +522,14 @@ export class InlineCheckout {
490
522
  }
491
523
  }
492
524
 
493
- async #handleRadioButtonClick (radio) {
494
- if(radio.id === this.radioChecked || ( radio.id === "new" && this.radioChecked === undefined)) return;
525
+ async #handleRadioButtonClick(radio) {
526
+ if (radio.id === this.radioChecked || (radio.id === "new" && this.radioChecked === undefined)) return;
495
527
  const containerForm = document.querySelector(".container-form");
496
- if(containerForm) {
528
+ if (containerForm) {
497
529
  containerForm.style.display = radio.id === "new" ? "block" : "none";
498
530
  }
499
- if(radio.id === "new") {
500
- if(this.radioChecked !== radio.id) {
531
+ if (radio.id === "new") {
532
+ if (this.radioChecked !== radio.id) {
501
533
  this.#addGlobalLoader()
502
534
  this.#mountTonder(false);
503
535
  InlineCheckout.injected = true;
@@ -508,32 +540,45 @@ export class InlineCheckout {
508
540
  this.radioChecked = radio.id;
509
541
  }
510
542
 
511
- async #handleDeleteCardButtonClick (customerToken, button) {
543
+ async #handleDeleteCardButtonClick(customerToken, button) {
512
544
  const id = button.attributes.getNamedItem("id")
513
545
  const skyflow_id = id?.value?.split("_")?.[2]
514
- if(skyflow_id) {
546
+ if (skyflow_id) {
515
547
  const cardClicked = document.querySelector(`#card_container-${skyflow_id}`);
516
- if(cardClicked) {
548
+ if (cardClicked) {
517
549
  cardClicked.style.display = "none"
518
550
  }
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)
551
+ try {
552
+ this.deletingCards.push(skyflow_id);
553
+ if (this.abortRefreshCardsController) {
554
+ this.abortRefreshCardsController.abort();
555
+ this.abortRefreshCardsController = new AbortController();
556
+ }
557
+ await deleteCustomerCard(this.baseUrl, customerToken, skyflow_id)
558
+ } catch {
559
+ } finally {
560
+ this.deletingCards = this.deletingCards.filter(id => id !== skyflow_id);
561
+ this.#refreshCardOnDelete(customerToken)
525
562
  }
526
563
  }
527
564
  }
528
-
529
- #unmountForm () {
565
+ async #refreshCardOnDelete(customerToken) {
566
+ if (this.deletingCards.length > 0) return;
567
+ this.cardsInjected = false
568
+ const cards = await getCustomerCards(this.baseUrl, customerToken, "", this.abortRefreshCardsController.signal)
569
+ if ("cards" in cards) {
570
+ const cardsMapped = cards.cards.map(mapCards)
571
+ this.#loadCardsList(cardsMapped, customerToken)
572
+ }
573
+ }
574
+ #unmountForm() {
530
575
  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()
576
+ if (this.collectContainer) {
577
+ if ("unmount" in this.collectContainer.elements.cardHolderNameElement) this.collectContainer.elements.cardHolderNameElement.unmount()
578
+ if ("unmount" in this.collectContainer.elements.cardNumberElement) this.collectContainer.elements.cardNumberElement.unmount()
579
+ if ("unmount" in this.collectContainer.elements.expiryYearElement) this.collectContainer.elements.expiryYearElement.unmount()
580
+ if ("unmount" in this.collectContainer.elements.expiryMonthElement) this.collectContainer.elements.expiryMonthElement.unmount()
581
+ if ("unmount" in this.collectContainer.elements.cvvElement) this.collectContainer.elements.cvvElement.unmount()
537
582
  }
538
583
  }
539
584
  }
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,7 @@ export async function getCustomerCards(baseUrlTonder, customerToken, query = "")
162
162
  'Authorization': `Token ${customerToken}`,
163
163
  'Content-Type': 'application/json'
164
164
  },
165
+ signal
165
166
  });
166
167
 
167
168
  if (response.ok) return await response.json();
@@ -19,7 +19,7 @@ export const cardTemplate = `
19
19
  <div id="collectExpirationYear" class="expiration-year"></div>
20
20
  <div id="collectCvv" class="empty-div"></div>
21
21
  </div>
22
- <div class="checkbox">
22
+ <div class="checkbox" id="save-card-container">
23
23
  <input id="save-checkout-card" type="checkbox">
24
24
  <label for="save-checkout-card">
25
25
  Guardar tarjeta para futuros pagos
package/src/index-dev.js CHANGED
@@ -97,21 +97,26 @@ const checkoutData = {
97
97
  };
98
98
 
99
99
  // localhost
100
- const apiKey = "4c87c36e697e65ddfe288be0afbe7967ea0ab865";
100
+ const apiKey = "11e3d3c3e95e0eaabbcae61ebad34ee5f93c3d27";
101
101
  const returnUrl = "http://127.0.0.1:8080/"
102
102
  const successUrl = "http://127.0.0.1:8080/success"
103
103
  // stage
104
104
  // const apiKey = "8365683bdc33dd6d50fe2397188d79f1a6765852";
105
105
 
106
106
  const inlineCheckout = new InlineCheckout({
107
- mode: 'development',
107
+ mode: 'stage',
108
108
  apiKey,
109
109
  returnUrl,
110
110
  successUrl,
111
111
  styles: customStyles
112
112
  });
113
- inlineCheckout.setCustomerEmail(checkoutData.customer.email)
113
+ inlineCheckout.configureCheckout({customer: checkoutData.customer})
114
114
  inlineCheckout.injectCheckout();
115
+ //
116
+ // ['Declined', 'Cancelled', 'Failed', 'Success', 'Pending', 'Authorized']
117
+ inlineCheckout.verify3dsTransaction().then(response => {
118
+ console.log('Verify 3ds response', response)
119
+ })
115
120
 
116
121
  document.addEventListener('DOMContentLoaded', function() {
117
122
  const payButton = document.getElementById('pay-button');