tonder-web-sdk 1.9.3-beta.1 → 1.11.0-beta.1
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 +168 -97
- package/src/data/api.js +20 -0
- package/src/helpers/constants.js +64 -0
- package/src/helpers/template.js +183 -16
- package/src/helpers/utils.js +246 -0
- package/src/index-dev.js +9 -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
|
}
|
|
@@ -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,8 @@ 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 = [];
|
|
27
31
|
deletingCards = [];
|
|
28
32
|
customer = {}
|
|
29
33
|
items = []
|
|
@@ -42,8 +46,8 @@ export class InlineCheckout {
|
|
|
42
46
|
cvv: "collectCvv",
|
|
43
47
|
tonderPayButton: "tonderPayButton",
|
|
44
48
|
msgError: "msgError",
|
|
45
|
-
msgNotification: "msgNotification"
|
|
46
|
-
|
|
49
|
+
msgNotification: "msgNotification",
|
|
50
|
+
apmsListContainer: "apmsListContainer"
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
constructor({
|
|
@@ -78,7 +82,7 @@ export class InlineCheckout {
|
|
|
78
82
|
'stage': 'https://stage.tonder.io',
|
|
79
83
|
'development': 'http://localhost:8000',
|
|
80
84
|
};
|
|
81
|
-
|
|
85
|
+
|
|
82
86
|
return modeUrls[this.mode] || modeUrls['stage']
|
|
83
87
|
}
|
|
84
88
|
|
|
@@ -112,6 +116,31 @@ export class InlineCheckout {
|
|
|
112
116
|
}
|
|
113
117
|
}
|
|
114
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
|
+
|
|
115
144
|
payment(data) {
|
|
116
145
|
return new Promise(async (resolve, reject) => {
|
|
117
146
|
try {
|
|
@@ -122,36 +151,12 @@ export class InlineCheckout {
|
|
|
122
151
|
this.#handleCurrency(data)
|
|
123
152
|
this.#handleCard(data)
|
|
124
153
|
const response = await this.#checkout()
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
this.callBack(response);
|
|
132
|
-
|
|
133
|
-
const iframe = response?.next_action?.iframe_resources?.iframe
|
|
134
|
-
|
|
135
|
-
if (iframe) {
|
|
136
|
-
process3ds.loadIframe().then(() => {
|
|
137
|
-
//TODO: Check if this will be necessary on the frontend side
|
|
138
|
-
// after some the tests in production, since the 3DS process
|
|
139
|
-
// doesn't works properly on the sandbox environment
|
|
140
|
-
// setTimeout(() => {
|
|
141
|
-
// process3ds.verifyTransactionStatus();
|
|
142
|
-
// }, 10000);
|
|
143
|
-
process3ds.verifyTransactionStatus();
|
|
144
|
-
}).catch((error) => {
|
|
145
|
-
console.log('Error loading iframe:', error)
|
|
146
|
-
})
|
|
147
|
-
} else {
|
|
148
|
-
const redirectUrl = process3ds.getRedirectUrl()
|
|
149
|
-
if (redirectUrl) {
|
|
150
|
-
process3ds.redirectToChallenge()
|
|
151
|
-
} else {
|
|
152
|
-
resolve(response);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
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);
|
|
155
160
|
}
|
|
156
161
|
} catch (error) {
|
|
157
162
|
reject(error);
|
|
@@ -160,7 +165,6 @@ export class InlineCheckout {
|
|
|
160
165
|
}
|
|
161
166
|
|
|
162
167
|
#handleCustomer(customer) {
|
|
163
|
-
console.log('customer: ', customer)
|
|
164
168
|
if (!customer) return
|
|
165
169
|
|
|
166
170
|
this.firstName = customer?.firstName
|
|
@@ -188,15 +192,15 @@ export class InlineCheckout {
|
|
|
188
192
|
}
|
|
189
193
|
|
|
190
194
|
setCartItems(items) {
|
|
191
|
-
console.log('items: ', items)
|
|
192
195
|
this.cartItems = items
|
|
193
196
|
}
|
|
194
197
|
|
|
195
|
-
|
|
196
|
-
|
|
198
|
+
configureCheckout(data) {
|
|
199
|
+
if ('customer' in data)
|
|
200
|
+
this.#handleCustomer(data['customer'])
|
|
197
201
|
}
|
|
202
|
+
|
|
198
203
|
setCartTotal(total) {
|
|
199
|
-
console.log('total: ', total)
|
|
200
204
|
this.cartTotal = total
|
|
201
205
|
this.#updatePayButton()
|
|
202
206
|
}
|
|
@@ -213,7 +217,6 @@ export class InlineCheckout {
|
|
|
213
217
|
|
|
214
218
|
injectCheckout() {
|
|
215
219
|
if (InlineCheckout.injected) return
|
|
216
|
-
this.process3ds.verifyTransactionStatus()
|
|
217
220
|
const containerTonderCheckout = document.querySelector("#tonder-checkout");
|
|
218
221
|
if (containerTonderCheckout) {
|
|
219
222
|
this.#mount(containerTonderCheckout)
|
|
@@ -230,15 +233,40 @@ export class InlineCheckout {
|
|
|
230
233
|
childList: true,
|
|
231
234
|
subtree: true,
|
|
232
235
|
attributeFilter: ['id']
|
|
233
|
-
|
|
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)
|
|
234
247
|
}
|
|
235
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
|
+
}
|
|
236
264
|
|
|
237
265
|
#addGlobalLoader() {
|
|
238
266
|
let checkoutContainer = document.querySelector("#global-loader");
|
|
239
267
|
if (checkoutContainer) {
|
|
240
|
-
|
|
241
|
-
|
|
268
|
+
checkoutContainer.innerHTML = cardTemplateSkeleton;
|
|
269
|
+
checkoutContainer.style.display = 'block';
|
|
242
270
|
}
|
|
243
271
|
}
|
|
244
272
|
|
|
@@ -249,8 +277,8 @@ export class InlineCheckout {
|
|
|
249
277
|
}
|
|
250
278
|
}
|
|
251
279
|
|
|
252
|
-
#mount(containerTonderCheckout){
|
|
253
|
-
containerTonderCheckout.innerHTML = cardTemplate;
|
|
280
|
+
#mount(containerTonderCheckout) {
|
|
281
|
+
containerTonderCheckout.innerHTML = cardTemplate({renderPaymentButton: this.renderPaymentButton, customStyles: this.customStyles});
|
|
254
282
|
this.#addGlobalLoader();
|
|
255
283
|
this.#mountTonder();
|
|
256
284
|
InlineCheckout.injected = true;
|
|
@@ -269,25 +297,45 @@ export class InlineCheckout {
|
|
|
269
297
|
return await customerRegister(this.baseUrl, this.apiKeyTonder, customer, signal);
|
|
270
298
|
}
|
|
271
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
|
+
}
|
|
272
311
|
async #mountTonder(getCards = true) {
|
|
273
312
|
this.#mountPayButton()
|
|
274
|
-
try{
|
|
313
|
+
try {
|
|
275
314
|
const {
|
|
276
315
|
vault_id,
|
|
277
316
|
vault_url,
|
|
278
317
|
} = await this.#fetchMerchantData();
|
|
279
|
-
if(this.email && getCards){
|
|
280
|
-
const customerResponse = await this.getCustomer({email: this.email});
|
|
281
|
-
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) {
|
|
282
321
|
const { auth_token } = customerResponse
|
|
283
|
-
const
|
|
322
|
+
const saveCardCheckbox = document.getElementById('save-card-container');
|
|
284
323
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
this
|
|
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
|
+
}
|
|
288
333
|
}
|
|
334
|
+
|
|
335
|
+
|
|
289
336
|
}
|
|
290
337
|
}
|
|
338
|
+
this.#mountAPMs();
|
|
291
339
|
|
|
292
340
|
this.collectContainer = await initSkyflow(
|
|
293
341
|
vault_id,
|
|
@@ -301,7 +349,7 @@ export class InlineCheckout {
|
|
|
301
349
|
setTimeout(() => {
|
|
302
350
|
this.#removeGlobalLoader()
|
|
303
351
|
}, 800)
|
|
304
|
-
}catch(e){
|
|
352
|
+
} catch (e) {
|
|
305
353
|
if (e && e.name !== 'AbortError') {
|
|
306
354
|
this.#removeGlobalLoader()
|
|
307
355
|
showError("No se pudieron cargar los datos del comercio.")
|
|
@@ -312,6 +360,7 @@ export class InlineCheckout {
|
|
|
312
360
|
removeCheckout() {
|
|
313
361
|
InlineCheckout.injected = false
|
|
314
362
|
InlineCheckout.cardsInjected = false
|
|
363
|
+
InlineCheckout.apmsInjected = false
|
|
315
364
|
// Cancel all requests
|
|
316
365
|
this.abortController.abort();
|
|
317
366
|
this.abortController = new AbortController();
|
|
@@ -342,9 +391,9 @@ export class InlineCheckout {
|
|
|
342
391
|
const total = Number(this.cartTotal)
|
|
343
392
|
|
|
344
393
|
let cardTokens = null;
|
|
345
|
-
if(this.radioChecked === "new" || this.radioChecked === undefined){
|
|
394
|
+
if (this.radioChecked === "new" || this.radioChecked === undefined) {
|
|
346
395
|
cardTokens = await this.#getCardTokens();
|
|
347
|
-
}else{
|
|
396
|
+
} else {
|
|
348
397
|
cardTokens = {
|
|
349
398
|
skyflow_id: this.radioChecked
|
|
350
399
|
}
|
|
@@ -360,24 +409,24 @@ export class InlineCheckout {
|
|
|
360
409
|
}
|
|
361
410
|
|
|
362
411
|
const { id, auth_token } = await this.getCustomer(
|
|
363
|
-
this.customer,
|
|
412
|
+
this.customer,
|
|
364
413
|
this.abortController.signal
|
|
365
414
|
)
|
|
366
|
-
if(auth_token && this.email){
|
|
415
|
+
if (auth_token && this.email) {
|
|
367
416
|
const saveCard = document.getElementById("save-checkout-card");
|
|
368
|
-
if(saveCard && "checked" in saveCard && saveCard.checked){
|
|
417
|
+
if (saveCard && "checked" in saveCard && saveCard.checked) {
|
|
369
418
|
await registerCard(this.baseUrl, auth_token, { skyflow_id: cardTokens.skyflow_id });
|
|
370
|
-
|
|
419
|
+
|
|
371
420
|
this.cardsInjected = false;
|
|
372
421
|
|
|
373
422
|
const cards = await getCustomerCards(this.baseUrl, auth_token);
|
|
374
|
-
if("cards" in cards) {
|
|
423
|
+
if ("cards" in cards) {
|
|
375
424
|
const cardsMapped = cards.cards.map((card) => mapCards(card))
|
|
376
425
|
this.#loadCardsList(cardsMapped, auth_token)
|
|
377
426
|
}
|
|
378
427
|
|
|
379
428
|
showMessage("Tarjeta registrada con éxito", this.collectorIds.msgNotification);
|
|
380
|
-
|
|
429
|
+
|
|
381
430
|
}
|
|
382
431
|
}
|
|
383
432
|
var orderItems = {
|
|
@@ -391,7 +440,6 @@ export class InlineCheckout {
|
|
|
391
440
|
is_oneclick: true,
|
|
392
441
|
items: this.cartItems,
|
|
393
442
|
};
|
|
394
|
-
console.log('orderItems: ', orderItems)
|
|
395
443
|
const jsonResponseOrder = await createOrder(
|
|
396
444
|
this.baseUrl,
|
|
397
445
|
this.apiKeyTonder,
|
|
@@ -415,9 +463,10 @@ export class InlineCheckout {
|
|
|
415
463
|
paymentItems
|
|
416
464
|
);
|
|
417
465
|
|
|
466
|
+
const selected_apm = this.apmsData ? this.apmsData.find((iapm) => iapm.pk === this.radioChecked):{};
|
|
467
|
+
|
|
418
468
|
// Checkout router
|
|
419
469
|
const routerItems = {
|
|
420
|
-
card: cardTokens,
|
|
421
470
|
name: this.firstName || "",
|
|
422
471
|
last_name: this.lastName || "",
|
|
423
472
|
email_client: this.email,
|
|
@@ -439,6 +488,10 @@ export class InlineCheckout {
|
|
|
439
488
|
metadata: this.metadata,
|
|
440
489
|
browser_info: getBrowserInfo(),
|
|
441
490
|
currency: this.currency,
|
|
491
|
+
...( !!selected_apm
|
|
492
|
+
? {payment_method: selected_apm.payment_method}
|
|
493
|
+
: {card: cardTokens}
|
|
494
|
+
)
|
|
442
495
|
};
|
|
443
496
|
const jsonResponseRouter = await startCheckoutRouter(
|
|
444
497
|
this.baseUrl,
|
|
@@ -462,8 +515,8 @@ export class InlineCheckout {
|
|
|
462
515
|
}
|
|
463
516
|
};
|
|
464
517
|
|
|
465
|
-
#loadCardsList
|
|
466
|
-
if(this.cardsInjected) return;
|
|
518
|
+
#loadCardsList(cards, token) {
|
|
519
|
+
if (this.cardsInjected) return;
|
|
467
520
|
const injectInterval = setInterval(() => {
|
|
468
521
|
const queryElement = document.querySelector(`#${this.collectorIds.cardsListContainer}`);
|
|
469
522
|
if (queryElement && InlineCheckout.injected) {
|
|
@@ -475,7 +528,25 @@ export class InlineCheckout {
|
|
|
475
528
|
}, 500);
|
|
476
529
|
}
|
|
477
530
|
|
|
478
|
-
#
|
|
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 = '') {
|
|
479
550
|
const radioButtons = document.getElementsByName(`card_selected`);
|
|
480
551
|
for (const radio of radioButtons) {
|
|
481
552
|
radio.style.display = "block";
|
|
@@ -492,14 +563,14 @@ export class InlineCheckout {
|
|
|
492
563
|
}
|
|
493
564
|
}
|
|
494
565
|
|
|
495
|
-
async #handleRadioButtonClick
|
|
496
|
-
if(radio.id === this.radioChecked ||
|
|
566
|
+
async #handleRadioButtonClick(radio) {
|
|
567
|
+
if (radio.id === this.radioChecked || (radio.id === "new" && this.radioChecked === undefined)) return;
|
|
497
568
|
const containerForm = document.querySelector(".container-form");
|
|
498
|
-
if(containerForm) {
|
|
569
|
+
if (containerForm) {
|
|
499
570
|
containerForm.style.display = radio.id === "new" ? "block" : "none";
|
|
500
571
|
}
|
|
501
|
-
if(radio.id === "new") {
|
|
502
|
-
if(this.radioChecked !== radio.id) {
|
|
572
|
+
if (radio.id === "new") {
|
|
573
|
+
if (this.radioChecked !== radio.id) {
|
|
503
574
|
this.#addGlobalLoader()
|
|
504
575
|
this.#mountTonder(false);
|
|
505
576
|
InlineCheckout.injected = true;
|
|
@@ -510,45 +581,45 @@ export class InlineCheckout {
|
|
|
510
581
|
this.radioChecked = radio.id;
|
|
511
582
|
}
|
|
512
583
|
|
|
513
|
-
async #handleDeleteCardButtonClick
|
|
584
|
+
async #handleDeleteCardButtonClick(customerToken, button) {
|
|
514
585
|
const id = button.attributes.getNamedItem("id")
|
|
515
586
|
const skyflow_id = id?.value?.split("_")?.[2]
|
|
516
|
-
if(skyflow_id) {
|
|
587
|
+
if (skyflow_id) {
|
|
517
588
|
const cardClicked = document.querySelector(`#card_container-${skyflow_id}`);
|
|
518
|
-
if(cardClicked) {
|
|
589
|
+
if (cardClicked) {
|
|
519
590
|
cardClicked.style.display = "none"
|
|
520
591
|
}
|
|
521
|
-
try{
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
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)
|
|
526
603
|
}
|
|
527
|
-
await deleteCustomerCard(this.baseUrl, customerToken, skyflow_id)
|
|
528
|
-
}catch{
|
|
529
|
-
} finally {
|
|
530
|
-
this.deletingCards = this.deletingCards.filter(id => id !== skyflow_id);
|
|
531
|
-
this.#refreshCardOnDelete(customerToken)
|
|
532
|
-
}
|
|
533
604
|
}
|
|
534
605
|
}
|
|
535
|
-
async #refreshCardOnDelete(customerToken){
|
|
536
|
-
if(this.deletingCards.length > 0) return;
|
|
606
|
+
async #refreshCardOnDelete(customerToken) {
|
|
607
|
+
if (this.deletingCards.length > 0) return;
|
|
537
608
|
this.cardsInjected = false
|
|
538
609
|
const cards = await getCustomerCards(this.baseUrl, customerToken, "", this.abortRefreshCardsController.signal)
|
|
539
|
-
if("cards" in cards) {
|
|
610
|
+
if ("cards" in cards) {
|
|
540
611
|
const cardsMapped = cards.cards.map(mapCards)
|
|
541
612
|
this.#loadCardsList(cardsMapped, customerToken)
|
|
542
613
|
}
|
|
543
614
|
}
|
|
544
|
-
#unmountForm
|
|
615
|
+
#unmountForm() {
|
|
545
616
|
InlineCheckout.injected = false
|
|
546
|
-
if(this.collectContainer) {
|
|
547
|
-
if("unmount" in this.collectContainer.elements.cardHolderNameElement) this.collectContainer.elements.cardHolderNameElement.unmount()
|
|
548
|
-
if("unmount" in this.collectContainer.elements.cardNumberElement) this.collectContainer.elements.cardNumberElement.unmount()
|
|
549
|
-
if("unmount" in this.collectContainer.elements.expiryYearElement) this.collectContainer.elements.expiryYearElement.unmount()
|
|
550
|
-
if("unmount" in this.collectContainer.elements.expiryMonthElement) this.collectContainer.elements.expiryMonthElement.unmount()
|
|
551
|
-
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()
|
|
552
623
|
}
|
|
553
624
|
}
|
|
554
625
|
}
|
package/src/data/api.js
CHANGED
|
@@ -165,6 +165,26 @@ export async function getCustomerCards(baseUrlTonder, customerToken, query = "",
|
|
|
165
165
|
signal
|
|
166
166
|
});
|
|
167
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
|
+
{
|
|
180
|
+
method: 'GET',
|
|
181
|
+
headers: {
|
|
182
|
+
Authorization: `Token ${apiKeyTonder}`,
|
|
183
|
+
'Content-Type': 'application/json'
|
|
184
|
+
},
|
|
185
|
+
signal
|
|
186
|
+
});
|
|
187
|
+
|
|
168
188
|
if (response.ok) return await response.json();
|
|
169
189
|
throw await buildErrorResponse(response);
|
|
170
190
|
} catch (error) {
|