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 +16 -1
- package/package.json +1 -1
- package/src/classes/3dsHandler.js +29 -10
- package/src/classes/inlineCheckout.js +130 -85
- package/src/data/api.js +3 -2
- package/src/helpers/template.js +1 -1
- package/src/index-dev.js +8 -3
- package/v1/bundle.min.js +3 -3
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
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
182
|
+
return this.handleSuccessTransaction(response_json);
|
|
169
183
|
} else {
|
|
170
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
-
|
|
194
|
-
|
|
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
|
-
|
|
239
|
-
|
|
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
|
-
|
|
278
|
-
|
|
279
|
-
|
|
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
|
|
307
|
+
const saveCardCheckbox = document.getElementById('save-card-container');
|
|
282
308
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
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
|
|
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
|
|
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
|
|
494
|
-
if(radio.id === this.radioChecked ||
|
|
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
|
|
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
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
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
|
-
|
|
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();
|
package/src/helpers/template.js
CHANGED
|
@@ -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 = "
|
|
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: '
|
|
107
|
+
mode: 'stage',
|
|
108
108
|
apiKey,
|
|
109
109
|
returnUrl,
|
|
110
110
|
successUrl,
|
|
111
111
|
styles: customStyles
|
|
112
112
|
});
|
|
113
|
-
inlineCheckout.
|
|
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');
|