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 +16 -1
- package/package.json +1 -1
- package/src/classes/3dsHandler.js +29 -10
- package/src/classes/inlineCheckout.js +176 -90
- package/src/data/api.js +24 -2
- 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,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
|
-
|
|
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
|
-
}
|
|
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
|
-
|
|
194
|
-
|
|
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
|
-
|
|
239
|
-
|
|
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
|
|
322
|
+
const saveCardCheckbox = document.getElementById('save-card-container');
|
|
282
323
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
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
|
+
}
|
|
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
|
|
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
|
-
#
|
|
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
|
|
494
|
-
if(radio.id === this.radioChecked ||
|
|
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
|
|
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
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
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
|
-
|
|
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();
|