tonder-web-sdk 1.14.0 → 1.16.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 +82 -25
- package/package.json +2 -1
- package/src/classes/3dsHandler.js +5 -20
- package/src/classes/BaseInlineCheckout.js +22 -10
- package/src/classes/LiteInlineCheckout.js +3 -0
- package/src/classes/inlineCheckout.js +90 -10
- package/src/helpers/skyflow.js +121 -39
- package/src/helpers/template.js +103 -21
- package/src/index-dev.js +11 -4
- package/types/common.d.ts +2 -1
- package/v1/bundle.min.js +3 -3
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Tonder SDK helps to integrate the services Tonder offers in your own website
|
|
|
7
7
|
1. [Installation](#installation)
|
|
8
8
|
2. [Usage](#usage)
|
|
9
9
|
- [InlineCheckout](#inlinecheckout)
|
|
10
|
-
- [
|
|
10
|
+
- [LiteInlineCheckout](#Liteinlinecheckout)
|
|
11
11
|
3. [Configuration Options](#configuration-options)
|
|
12
12
|
4. [Styling InlineCheckout](#styling-inlinecheckout)
|
|
13
13
|
5. [Payment Data Structure](#payment-data-structure)
|
|
@@ -96,16 +96,16 @@ inlineCheckout.verify3dsTransaction().then((response) => {
|
|
|
96
96
|
const response = await inlineCheckout.payment(checkoutData);
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
###
|
|
99
|
+
### LiteInlineCheckout
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
LiteInlineCheckout allows you to build a custom checkout interface using Tonder's core functionality.
|
|
102
102
|
|
|
103
103
|
```javascript
|
|
104
|
-
import {
|
|
104
|
+
import { LiteInlineCheckout } from "tonder-web-sdk";
|
|
105
105
|
```
|
|
106
106
|
|
|
107
107
|
```javascript
|
|
108
|
-
const
|
|
108
|
+
const LiteInlineCheckout = new LiteInlineCheckout({
|
|
109
109
|
apiKey: "your-api-key", // Your api key getted from Tonder Dashboard
|
|
110
110
|
returnUrl: "http://your-website.com/checkout",
|
|
111
111
|
});
|
|
@@ -115,54 +115,58 @@ const liteCheckout = new LiteCheckout({
|
|
|
115
115
|
inlineCheckout.configureCheckout({ customer: { email: "example@email.com" } });
|
|
116
116
|
|
|
117
117
|
// Initialize the checkout
|
|
118
|
-
await
|
|
118
|
+
await LiteInlineCheckout.injectCheckout();
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
```javascript
|
|
122
122
|
// Retrieve customer's saved cards
|
|
123
|
-
const cards = await
|
|
123
|
+
const cards = await LiteInlineCheckout.getCustomerCards();
|
|
124
124
|
```
|
|
125
125
|
|
|
126
126
|
```javascript
|
|
127
127
|
// Save a new card
|
|
128
|
-
const newCard = await
|
|
128
|
+
const newCard = await LiteInlineCheckout.saveCustomerCard(cardData);
|
|
129
129
|
```
|
|
130
130
|
|
|
131
131
|
```javascript
|
|
132
132
|
// Remove a saved card
|
|
133
|
-
await
|
|
133
|
+
await LiteInlineCheckout.removeCustomerCard(cardId);
|
|
134
134
|
```
|
|
135
135
|
|
|
136
136
|
```javascript
|
|
137
137
|
// Get available payment methods
|
|
138
|
-
const paymentMethods = await
|
|
138
|
+
const paymentMethods = await LiteInlineCheckout.getCustomerPaymentMethods();
|
|
139
139
|
```
|
|
140
140
|
|
|
141
141
|
```javascript
|
|
142
142
|
// Process a payment
|
|
143
|
-
const paymentResponse = await
|
|
143
|
+
const paymentResponse = await LiteInlineCheckout.payment(paymentData);
|
|
144
144
|
```
|
|
145
145
|
|
|
146
146
|
```javascript
|
|
147
147
|
// Verify a 3DS transaction
|
|
148
|
-
const verificationResult = await
|
|
148
|
+
const verificationResult = await LiteInlineCheckout.verify3dsTransaction();
|
|
149
149
|
```
|
|
150
150
|
|
|
151
151
|
## Configuration Options
|
|
152
152
|
|
|
153
|
-
Both InlineCheckout and
|
|
153
|
+
Both InlineCheckout and LiteInlineCheckout accept the following configuration options:
|
|
154
154
|
|
|
155
155
|
| Property | Type | Description |
|
|
156
|
-
|
|
156
|
+
|:------------------------------------------:|:-------:|:-------------------------------------------------------------------------------------------------------------------------------------------:|
|
|
157
157
|
| mode | string | Environment mode. Options: 'stage', 'production', 'sandbox'. Default: 'stage' |
|
|
158
158
|
| apiKey | string | Your API key from the Tonder Dashboard |
|
|
159
159
|
| returnUrl | string | URL where the checkout form is mounted (used for 3DS) |
|
|
160
|
+
| renderPaymentButton | boolean | View the default Tonder payment button |
|
|
160
161
|
| styles | object | (InlineCheckout only) Custom styles for the checkout interface |
|
|
161
162
|
| customization | object | Object to customize the checkout behavior and UI. Default value `{saveCards: {showSaved: true, showSaveCardOption: true, autoSave: false}}` |
|
|
162
163
|
| customization.saveCards.showSaved | boolean | Show saved cards in the checkout UI. Default value: `true` |
|
|
163
164
|
| customization.saveCards.showSaveCardOption | object | Show the option to save the card for future payments. Default value: `true` |
|
|
164
165
|
| customization.saveCards.autoSave | object | Automatically save the card without showing the option to the user. Default value: `false` |
|
|
165
166
|
|
|
167
|
+
> **Important Note about SaveCard functionality**:
|
|
168
|
+
> To properly implement the SaveCard feature, you must use a SecureToken. For detailed implementation instructions and best practices, please refer to our official documentation on [How to use SecureToken for secure card saving](https://docs.tonder.io/integration/sdks/secure-token#how-to-use-securetoken-for-secure-card-saving).
|
|
169
|
+
|
|
166
170
|
## Styling InlineCheckout
|
|
167
171
|
|
|
168
172
|
You can customize the appearance of InlineCheckout by passing a `styles` object:
|
|
@@ -252,15 +256,15 @@ When calling the `payment` method, use the following data structure:
|
|
|
252
256
|
|
|
253
257
|
- **metadata**: Object for including any additional information about the transaction. This can be used for internal references or tracking.
|
|
254
258
|
|
|
255
|
-
- **card**: (for
|
|
259
|
+
- **card**: (for LiteInlineCheckout) Object containing card information. This is used differently depending on whether it's a new card or a saved card:
|
|
256
260
|
|
|
257
261
|
- For a new card: Include `card_number`, `cvv`, `expiration_month`, `expiration_year`, and `cardholder_name`.
|
|
258
262
|
- For a saved card: Include only the `skyflow_id` of the saved card.
|
|
259
263
|
- This is only used when not paying with a payment_method.
|
|
260
264
|
|
|
261
|
-
- **payment_method**: (for
|
|
265
|
+
- **payment_method**: (for LiteInlineCheckout) String indicating the alternative payment method to be used (e.g., "Spei"). This is only used when not paying with a card.
|
|
262
266
|
|
|
263
|
-
Note: The exact fields required may vary depending on whether you're using InlineCheckout or
|
|
267
|
+
Note: The exact fields required may vary depending on whether you're using InlineCheckout or LiteInlineCheckout, and the specific payment method being used.
|
|
264
268
|
|
|
265
269
|
```javascript
|
|
266
270
|
const paymentData = {
|
|
@@ -312,7 +316,7 @@ const paymentData = {
|
|
|
312
316
|
|
|
313
317
|
## Field Validation Functions
|
|
314
318
|
|
|
315
|
-
For
|
|
319
|
+
For LiteInlineCheckout implementations, the SDK provides validation functions to ensure the integrity of card data before submitting:
|
|
316
320
|
|
|
317
321
|
- `validateCardNumber(cardNumber)`: Validates the card number using the Luhn algorithm.
|
|
318
322
|
- `validateCardholderName(name)`: Checks if the cardholder name is valid.
|
|
@@ -357,7 +361,7 @@ if (
|
|
|
357
361
|
- `payment(data)`: Process a payment
|
|
358
362
|
- `verify3dsTransaction()`: Verify a 3DS transaction
|
|
359
363
|
|
|
360
|
-
###
|
|
364
|
+
### LiteInlineCheckout Methods
|
|
361
365
|
|
|
362
366
|
- `configureCheckout(data)`: Set initial checkout data
|
|
363
367
|
- `injectCheckout()`: Initialize the checkout
|
|
@@ -434,6 +438,59 @@ document
|
|
|
434
438
|
});
|
|
435
439
|
```
|
|
436
440
|
|
|
441
|
+
|
|
442
|
+
#### InlineCheckout with default Tonder Payment button Example (your-script.js)
|
|
443
|
+
> 💡 **Note:** It is important to send all payment data (customer, cart, metadata, etc) when configuring the checkout; this is necessary when using Tonder's default payment button.
|
|
444
|
+
|
|
445
|
+
```javascript
|
|
446
|
+
import { InlineCheckout } from "tonder-web-sdk";
|
|
447
|
+
|
|
448
|
+
const apiKey = "your-api-key";
|
|
449
|
+
const returnUrl = "http://your-website.com/checkout";
|
|
450
|
+
|
|
451
|
+
const inlineCheckout = new InlineCheckout({
|
|
452
|
+
mode: "development",
|
|
453
|
+
apiKey,
|
|
454
|
+
returnUrl,
|
|
455
|
+
styles: customStyles,
|
|
456
|
+
renderPaymentButton: true, // activate default Tonder Payment button
|
|
457
|
+
callBack: (response) => {
|
|
458
|
+
console.log('Payment response', response)
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
// It is important to send all payment data (customer, cart, metadata, etc) when configuring the checkout; this is necessary when using Tonder's default payment button.
|
|
463
|
+
inlineCheckout.configureCheckout(
|
|
464
|
+
{
|
|
465
|
+
customer: { email: "example@email.com" },
|
|
466
|
+
currency: "mxn",
|
|
467
|
+
cart: {
|
|
468
|
+
total: 399,
|
|
469
|
+
items: [
|
|
470
|
+
{
|
|
471
|
+
description: "Black T-Shirt",
|
|
472
|
+
quantity: 1,
|
|
473
|
+
price_unit: 1,
|
|
474
|
+
discount: 0,
|
|
475
|
+
taxes: 0,
|
|
476
|
+
product_reference: 1,
|
|
477
|
+
name: "T-Shirt",
|
|
478
|
+
amount_total: 399,
|
|
479
|
+
},
|
|
480
|
+
],
|
|
481
|
+
},
|
|
482
|
+
metadata: {}, // Optional
|
|
483
|
+
order_reference: "" // Optional
|
|
484
|
+
}
|
|
485
|
+
);
|
|
486
|
+
inlineCheckout.injectCheckout();
|
|
487
|
+
|
|
488
|
+
inlineCheckout.verify3dsTransaction().then((response) => {
|
|
489
|
+
console.log("Verify 3ds response", response);
|
|
490
|
+
});
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
|
|
437
494
|
#### LiteCheckout Example (your-script.js)
|
|
438
495
|
|
|
439
496
|
```javascript
|
|
@@ -442,16 +499,16 @@ import { LiteInlineCheckout } from "tonder-web-sdk";
|
|
|
442
499
|
const apiKey = "your-api-key";
|
|
443
500
|
const returnUrl = "http://your-website.com/checkout";
|
|
444
501
|
|
|
445
|
-
const
|
|
502
|
+
const LiteInlineCheckout = new LiteInlineCheckout({
|
|
446
503
|
mode: "development",
|
|
447
504
|
apiKey,
|
|
448
505
|
returnUrl,
|
|
449
506
|
});
|
|
450
507
|
|
|
451
|
-
|
|
452
|
-
|
|
508
|
+
LiteInlineCheckout.configureCheckout({ customer: { email: "example@email.com" } });
|
|
509
|
+
LiteInlineCheckout.injectCheckout();
|
|
453
510
|
|
|
454
|
-
|
|
511
|
+
LiteInlineCheckout.verify3dsTransaction().then((response) => {
|
|
455
512
|
console.log("Verify 3ds response", response);
|
|
456
513
|
});
|
|
457
514
|
|
|
@@ -469,7 +526,7 @@ document
|
|
|
469
526
|
|
|
470
527
|
try {
|
|
471
528
|
const paymentData = { ...checkoutData, card: cardData };
|
|
472
|
-
const response = await
|
|
529
|
+
const response = await LiteInlineCheckout.payment(paymentData);
|
|
473
530
|
console.log("Payment response:", response);
|
|
474
531
|
alert("Payment successful");
|
|
475
532
|
} catch (error) {
|
|
@@ -681,7 +738,7 @@ export class TonderService {
|
|
|
681
738
|
// Add more functions, for example for lite sdk: get payment methods
|
|
682
739
|
|
|
683
740
|
// getCustomerPaymentMethods(): Promise<IPaymentMethod[]> {
|
|
684
|
-
// return this.
|
|
741
|
+
// return this.LiteInlineCheckout.getCustomerPaymentMethods();
|
|
685
742
|
// }
|
|
686
743
|
}
|
|
687
744
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tonder-web-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.16.1",
|
|
4
4
|
"description": "tonder sdk for integrations",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"types": "types/index.d.ts",
|
|
12
12
|
"license": "ISC",
|
|
13
13
|
"dependencies": {
|
|
14
|
+
"accordion-js": "^3.4.0",
|
|
14
15
|
"crypto-js": "^4.1.1",
|
|
15
16
|
"dotenv": "^16.3.1"
|
|
16
17
|
},
|
|
@@ -4,10 +4,9 @@ export class ThreeDSHandler {
|
|
|
4
4
|
apiKey,
|
|
5
5
|
baseUrl,
|
|
6
6
|
}) {
|
|
7
|
-
this.baseUrl = baseUrl
|
|
8
|
-
this.apiKey = apiKey
|
|
9
|
-
this.payload = payload
|
|
10
|
-
this.isTransactionPending = false
|
|
7
|
+
this.baseUrl = baseUrl
|
|
8
|
+
this.apiKey = apiKey
|
|
9
|
+
this.payload = payload
|
|
11
10
|
}
|
|
12
11
|
|
|
13
12
|
saveVerifyTransactionUrl() {
|
|
@@ -61,12 +60,12 @@ export class ThreeDSHandler {
|
|
|
61
60
|
|
|
62
61
|
loadIframe() {
|
|
63
62
|
const iframe = this.payload?.next_action?.iframe_resources?.iframe
|
|
64
|
-
|
|
65
63
|
if (iframe) {
|
|
66
64
|
return new Promise((resolve, reject) => {
|
|
67
65
|
const iframe = this.payload?.next_action?.iframe_resources?.iframe
|
|
68
66
|
|
|
69
67
|
if (iframe) {
|
|
68
|
+
// TODO: This is not working for Azul
|
|
70
69
|
this.saveVerifyTransactionUrl()
|
|
71
70
|
const container = document.createElement('div')
|
|
72
71
|
container.innerHTML = iframe
|
|
@@ -153,14 +152,11 @@ export class ThreeDSHandler {
|
|
|
153
152
|
// Append the form to the body:
|
|
154
153
|
document.body.appendChild(form);
|
|
155
154
|
form.submit();
|
|
156
|
-
|
|
157
|
-
await this.verifyTransactionStatus();
|
|
158
155
|
}
|
|
159
156
|
|
|
160
|
-
// TODO: This
|
|
157
|
+
// TODO: This works for Azul
|
|
161
158
|
async handleTransactionResponse(response) {
|
|
162
159
|
const response_json = await response.json();
|
|
163
|
-
|
|
164
160
|
// Azul property
|
|
165
161
|
if (response_json.status === "Pending" && response_json.redirect_post_url) {
|
|
166
162
|
return await this.handle3dsChallenge(response_json);
|
|
@@ -173,16 +169,7 @@ export class ThreeDSHandler {
|
|
|
173
169
|
}
|
|
174
170
|
|
|
175
171
|
async verifyTransactionStatus() {
|
|
176
|
-
console.log('Verificando la transacción...');
|
|
177
|
-
|
|
178
|
-
if (this.isTransactionPending) {
|
|
179
|
-
console.log('La transacción ya está en proceso');
|
|
180
|
-
return
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
this.isTransactionPending = true
|
|
184
172
|
const verifyUrl = this.getUrlWithExpiration();
|
|
185
|
-
|
|
186
173
|
if (verifyUrl) {
|
|
187
174
|
const url = `${this.baseUrl}${verifyUrl}`;
|
|
188
175
|
try {
|
|
@@ -208,8 +195,6 @@ export class ThreeDSHandler {
|
|
|
208
195
|
} else {
|
|
209
196
|
console.log('No verify_transaction_status_url found');
|
|
210
197
|
}
|
|
211
|
-
|
|
212
|
-
this.isTransactionPending = false
|
|
213
198
|
}
|
|
214
199
|
|
|
215
200
|
setPayload = (payload) => {
|
|
@@ -13,6 +13,7 @@ import { getBrowserInfo, injectMercadoPagoSecurity } from "../helpers/utils";
|
|
|
13
13
|
export class BaseInlineCheckout {
|
|
14
14
|
baseUrl = "";
|
|
15
15
|
cartTotal = "0";
|
|
16
|
+
secureToken = "";
|
|
16
17
|
constructor({ mode = "stage", apiKey, returnUrl, callBack = () => {} }) {
|
|
17
18
|
this.apiKeyTonder = apiKey;
|
|
18
19
|
this.returnUrl = returnUrl;
|
|
@@ -33,8 +34,8 @@ export class BaseInlineCheckout {
|
|
|
33
34
|
* @public
|
|
34
35
|
*/
|
|
35
36
|
configureCheckout(data) {
|
|
36
|
-
if ("customer" in data) this.#handleCustomer(data["customer"]);
|
|
37
37
|
if ("secureToken" in data) this.#handleSecureToken(data["secureToken"]);
|
|
38
|
+
this.#setCheckoutData(data)
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
/**
|
|
@@ -47,8 +48,9 @@ export class BaseInlineCheckout {
|
|
|
47
48
|
const result3ds = await this.process3ds.verifyTransactionStatus();
|
|
48
49
|
const resultCheckout = await this.#resumeCheckout(result3ds);
|
|
49
50
|
this.process3ds.setPayload(resultCheckout);
|
|
51
|
+
const response = await this.#handle3dsRedirect(resultCheckout);
|
|
50
52
|
globalLoader.remove();
|
|
51
|
-
return
|
|
53
|
+
return response
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
/**
|
|
@@ -65,12 +67,7 @@ export class BaseInlineCheckout {
|
|
|
65
67
|
payment(data) {
|
|
66
68
|
return new Promise(async (resolve, reject) => {
|
|
67
69
|
try {
|
|
68
|
-
this.#
|
|
69
|
-
this._setCartTotal(data.cart?.total);
|
|
70
|
-
this.#setCartItems(data.cart?.items);
|
|
71
|
-
this.#handleMetadata(data);
|
|
72
|
-
this.#handleCurrency(data);
|
|
73
|
-
this.#handleCard(data);
|
|
70
|
+
this.#setCheckoutData(data)
|
|
74
71
|
const response = await this._checkout(data);
|
|
75
72
|
this.process3ds.setPayload(response);
|
|
76
73
|
this.callBack(response);
|
|
@@ -159,6 +156,7 @@ export class BaseInlineCheckout {
|
|
|
159
156
|
amount: total,
|
|
160
157
|
date: dateString,
|
|
161
158
|
order_id: jsonResponseOrder.id,
|
|
159
|
+
customer_order_reference: this.order_reference ? this.order_reference : reference,
|
|
162
160
|
};
|
|
163
161
|
const jsonResponsePayment = await createPayment(
|
|
164
162
|
this.baseUrl,
|
|
@@ -212,6 +210,16 @@ export class BaseInlineCheckout {
|
|
|
212
210
|
}
|
|
213
211
|
}
|
|
214
212
|
|
|
213
|
+
#setCheckoutData(data){
|
|
214
|
+
if(!data) return;
|
|
215
|
+
this.#handleCustomer(data.customer);
|
|
216
|
+
this._setCartTotal(data.cart?.total);
|
|
217
|
+
this.#setCartItems(data.cart?.items);
|
|
218
|
+
this.#handleMetadata(data);
|
|
219
|
+
this.#handleCurrency(data);
|
|
220
|
+
this.#handleCard(data);
|
|
221
|
+
}
|
|
222
|
+
|
|
215
223
|
async #fetchMerchantData() {
|
|
216
224
|
this.merchantData = await fetchBusiness(
|
|
217
225
|
this.baseUrl,
|
|
@@ -223,7 +231,7 @@ export class BaseInlineCheckout {
|
|
|
223
231
|
|
|
224
232
|
async #resumeCheckout(response) {
|
|
225
233
|
// Stop the routing process if the transaction is either hard declined or successful
|
|
226
|
-
if (response?.decline?.error_type === "Hard") {
|
|
234
|
+
if (response?.decline?.error_type === "Hard" || !!response?.checkout?.is_route_finished) {
|
|
227
235
|
return response;
|
|
228
236
|
}
|
|
229
237
|
|
|
@@ -272,6 +280,7 @@ export class BaseInlineCheckout {
|
|
|
272
280
|
|
|
273
281
|
#handleMetadata(data) {
|
|
274
282
|
this.metadata = data?.metadata;
|
|
283
|
+
this.order_reference = data?.order_reference;
|
|
275
284
|
}
|
|
276
285
|
|
|
277
286
|
#handleCurrency(data) {
|
|
@@ -294,12 +303,15 @@ export class BaseInlineCheckout {
|
|
|
294
303
|
if (iframe) {
|
|
295
304
|
try {
|
|
296
305
|
await this.process3ds.loadIframe();
|
|
297
|
-
await this.process3ds.verifyTransactionStatus();
|
|
306
|
+
const res = await this.process3ds.verifyTransactionStatus();
|
|
307
|
+
return res;
|
|
298
308
|
} catch (error) {
|
|
299
309
|
console.log("Error loading iframe:", error);
|
|
300
310
|
}
|
|
301
311
|
} else if (threeDsChallenge) {
|
|
302
312
|
await this.process3ds.handle3dsChallenge(threeDsChallenge);
|
|
313
|
+
const res = await this.process3ds.verifyTransactionStatus();
|
|
314
|
+
return res;
|
|
303
315
|
} else {
|
|
304
316
|
const redirectUrl = this.process3ds.getRedirectUrl();
|
|
305
317
|
if (redirectUrl) {
|
|
@@ -42,6 +42,7 @@ export class LiteInlineCheckout extends BaseInlineCheckout {
|
|
|
42
42
|
const response = await fetchCustomerCards(
|
|
43
43
|
this.baseUrl,
|
|
44
44
|
auth_token,
|
|
45
|
+
this.secureToken,
|
|
45
46
|
this.merchantData.business.pk,
|
|
46
47
|
);
|
|
47
48
|
return {
|
|
@@ -87,6 +88,7 @@ export class LiteInlineCheckout extends BaseInlineCheckout {
|
|
|
87
88
|
return await saveCustomerCard(
|
|
88
89
|
this.baseUrl,
|
|
89
90
|
auth_token,
|
|
91
|
+
this.secureToken,
|
|
90
92
|
business?.pk,
|
|
91
93
|
skyflowTokens,
|
|
92
94
|
);
|
|
@@ -117,6 +119,7 @@ export class LiteInlineCheckout extends BaseInlineCheckout {
|
|
|
117
119
|
return await removeCustomerCard(
|
|
118
120
|
this.baseUrl,
|
|
119
121
|
auth_token,
|
|
122
|
+
this.secureToken,
|
|
120
123
|
skyflowId,
|
|
121
124
|
business?.pk,
|
|
122
125
|
);
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
showError,
|
|
7
7
|
showMessage
|
|
8
8
|
} from '../helpers/utils';
|
|
9
|
-
import { initSkyflow } from '../helpers/skyflow'
|
|
9
|
+
import { initSkyflow, initUpdateSkyflow } from '../helpers/skyflow'
|
|
10
10
|
import { globalLoader } from './globalLoader.js';
|
|
11
11
|
import { BaseInlineCheckout } from "./BaseInlineCheckout";
|
|
12
12
|
import {
|
|
@@ -16,16 +16,20 @@ import {
|
|
|
16
16
|
fetchCustomerAPMs
|
|
17
17
|
} from "../data";
|
|
18
18
|
import { MESSAGES } from "../shared/constants/messages";
|
|
19
|
+
import Accordion from "accordion-js";
|
|
19
20
|
|
|
20
21
|
export class InlineCheckout extends BaseInlineCheckout {
|
|
21
22
|
static injected = false;
|
|
22
23
|
static cardsInjected = false
|
|
23
24
|
static apmsInjected = false
|
|
24
25
|
static apmsData = [];
|
|
26
|
+
accordionC = null;
|
|
27
|
+
|
|
25
28
|
deletingCards = [];
|
|
26
29
|
customer = {}
|
|
27
30
|
items = []
|
|
28
31
|
collectContainer = null
|
|
32
|
+
updateCollectContainer = null
|
|
29
33
|
merchantData = {}
|
|
30
34
|
cartTotal = null
|
|
31
35
|
metadata = {}
|
|
@@ -73,17 +77,36 @@ export class InlineCheckout extends BaseInlineCheckout {
|
|
|
73
77
|
}
|
|
74
78
|
}
|
|
75
79
|
|
|
76
|
-
#mountPayButton() {
|
|
80
|
+
#mountPayButton(cardId="") {
|
|
77
81
|
if (!this.renderPaymentButton) return;
|
|
78
82
|
|
|
79
|
-
const
|
|
83
|
+
const btnID = `#tonderPayButton${cardId}`;
|
|
84
|
+
const payButton = document.querySelector(btnID);
|
|
85
|
+
const containerID = `#acContainer${cardId}`;
|
|
86
|
+
const container = document.querySelector(containerID);
|
|
87
|
+
|
|
80
88
|
if (!payButton) {
|
|
81
89
|
console.error("Pay button not found");
|
|
82
90
|
return;
|
|
83
91
|
}
|
|
84
92
|
|
|
93
|
+
if (cardId !== "") {
|
|
94
|
+
const sdkPayButton = document.querySelector(`#tonderPayButton`);
|
|
95
|
+
if(sdkPayButton){
|
|
96
|
+
sdkPayButton.style.display = "none";
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
85
100
|
payButton.style.display = "block";
|
|
86
101
|
payButton.textContent = `Pagar $${this.cartTotal}`;
|
|
102
|
+
document.querySelectorAll(".ac-card-panel-container").forEach((cont) => {
|
|
103
|
+
cont.classList.remove("show");
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
if (container) {
|
|
107
|
+
container.classList.add("show");
|
|
108
|
+
}
|
|
109
|
+
|
|
87
110
|
payButton.onclick = async (event) => {
|
|
88
111
|
event.preventDefault();
|
|
89
112
|
await this.#handlePaymentClick(payButton);
|
|
@@ -94,7 +117,7 @@ export class InlineCheckout extends BaseInlineCheckout {
|
|
|
94
117
|
const prevButtonContent = payButton.innerHTML;
|
|
95
118
|
payButton.innerHTML = `<div class="lds-dual-ring"></div>`;
|
|
96
119
|
try {
|
|
97
|
-
const response = await this.payment(
|
|
120
|
+
const response = await this.payment();
|
|
98
121
|
this.callBack(response);
|
|
99
122
|
} catch (error) {
|
|
100
123
|
console.error("Payment error:", error);
|
|
@@ -229,10 +252,10 @@ export class InlineCheckout extends BaseInlineCheckout {
|
|
|
229
252
|
console.log("InlineCheckout removed from DOM and cleaned up.");
|
|
230
253
|
}
|
|
231
254
|
|
|
232
|
-
async #getCardTokens() {
|
|
255
|
+
async #getCardTokens(cardSelected) {
|
|
233
256
|
if (this.card?.skyflow_id) return this.card
|
|
234
257
|
try {
|
|
235
|
-
const collectResponse = await this.collectContainer.container.collect();
|
|
258
|
+
const collectResponse = cardSelected && cardSelected !== "new" ? await this.updateCollectContainer.container.collect():await this.collectContainer.container.collect();
|
|
236
259
|
const cardTokens = await collectResponse["records"][0]["fields"];
|
|
237
260
|
return cardTokens;
|
|
238
261
|
} catch (error) {
|
|
@@ -250,8 +273,9 @@ export class InlineCheckout extends BaseInlineCheckout {
|
|
|
250
273
|
let cardTokens;
|
|
251
274
|
|
|
252
275
|
if (this.radioChecked === "new" || this.radioChecked === undefined) {
|
|
253
|
-
cardTokens = await this.#getCardTokens();
|
|
276
|
+
cardTokens = await this.#getCardTokens(this.radioChecked);
|
|
254
277
|
} else {
|
|
278
|
+
await this.#getCardTokens(this.radioChecked);
|
|
255
279
|
cardTokens = {
|
|
256
280
|
skyflow_id: this.radioChecked
|
|
257
281
|
}
|
|
@@ -327,8 +351,9 @@ export class InlineCheckout extends BaseInlineCheckout {
|
|
|
327
351
|
const injectInterval = setInterval(() => {
|
|
328
352
|
const queryElement = document.querySelector(`#${this.collectorIds.cardsListContainer}`);
|
|
329
353
|
if (queryElement && InlineCheckout.injected) {
|
|
330
|
-
queryElement.innerHTML = cardItemsTemplate(cards)
|
|
354
|
+
queryElement.innerHTML = cardItemsTemplate(cards, {renderPaymentButton: this.renderPaymentButton})
|
|
331
355
|
clearInterval(injectInterval)
|
|
356
|
+
this.#generateCardsAccordion()
|
|
332
357
|
this.#mountRadioButtons(token)
|
|
333
358
|
this.cardsInjected = true
|
|
334
359
|
}
|
|
@@ -336,6 +361,54 @@ export class InlineCheckout extends BaseInlineCheckout {
|
|
|
336
361
|
}
|
|
337
362
|
}
|
|
338
363
|
|
|
364
|
+
#generateCardsAccordion(){
|
|
365
|
+
this.accordionC = new Accordion(".accordion-container", {
|
|
366
|
+
triggerClass: "card-item-label",
|
|
367
|
+
duration: 300,
|
|
368
|
+
collapse: true,
|
|
369
|
+
showMultiple: false,
|
|
370
|
+
onOpen: async (currentElement) => {
|
|
371
|
+
await this.#handleOpenCardAccordion(currentElement)
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
async #handleOpenCardAccordion(currentElement){
|
|
377
|
+
const { vault_id, vault_url } = this.merchantData;
|
|
378
|
+
const container_radio_id = currentElement.id.replace("card_container-", "");
|
|
379
|
+
|
|
380
|
+
if (this.updateCollectContainer && "unmount" in this.updateCollectContainer?.elements?.cvvElement) {
|
|
381
|
+
await this.updateCollectContainer.elements.cvvElement.unmount()
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
document.querySelectorAll(".cvvContainer").forEach((container) => {
|
|
385
|
+
container.classList.remove("show");
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
const radio_card = document.getElementById(container_radio_id);
|
|
389
|
+
radio_card.checked = true;
|
|
390
|
+
|
|
391
|
+
try{
|
|
392
|
+
this.updateCollectContainer = await initUpdateSkyflow(
|
|
393
|
+
container_radio_id,
|
|
394
|
+
vault_id,
|
|
395
|
+
vault_url,
|
|
396
|
+
this.baseUrl,
|
|
397
|
+
this.apiKeyTonder,
|
|
398
|
+
this.abortController.signal,
|
|
399
|
+
this.customStyles
|
|
400
|
+
);
|
|
401
|
+
setTimeout(() => {
|
|
402
|
+
document.querySelector(`#cvvContainer${container_radio_id}`).classList.add("show");
|
|
403
|
+
}, 5)
|
|
404
|
+
this.#mountPayButton(container_radio_id)
|
|
405
|
+
}catch (e){
|
|
406
|
+
console.error("Ha ocurrido un error", e);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
this.#handleRadioButtonClick(radio_card)
|
|
410
|
+
}
|
|
411
|
+
|
|
339
412
|
#loadAPMList(apms) {
|
|
340
413
|
if (this.apmsInjected) return;
|
|
341
414
|
const injectInterval = setInterval(() => {
|
|
@@ -359,7 +432,8 @@ export class InlineCheckout extends BaseInlineCheckout {
|
|
|
359
432
|
for (const radio of radioButtons) {
|
|
360
433
|
radio.style.display = "block";
|
|
361
434
|
radio.onclick = async (event) => {
|
|
362
|
-
|
|
435
|
+
const position = Array.from(radioButtons).indexOf(radio);
|
|
436
|
+
await this.#handleRadioButtonClick(radio, position);
|
|
363
437
|
};
|
|
364
438
|
}
|
|
365
439
|
const cardsButtons = document.getElementsByClassName("card-delete-button");
|
|
@@ -372,19 +446,25 @@ export class InlineCheckout extends BaseInlineCheckout {
|
|
|
372
446
|
}
|
|
373
447
|
}
|
|
374
448
|
|
|
375
|
-
async #handleRadioButtonClick(radio) {
|
|
449
|
+
async #handleRadioButtonClick(radio, position = null) {
|
|
376
450
|
if (radio.id === this.radioChecked || (radio.id === "new" && this.radioChecked === undefined)) return;
|
|
377
451
|
const containerForm = document.querySelector(".container-form");
|
|
378
452
|
if (containerForm) {
|
|
379
453
|
containerForm.style.display = radio.id === "new" ? "block" : "none";
|
|
380
454
|
}
|
|
455
|
+
|
|
381
456
|
if (radio.id === "new") {
|
|
457
|
+
this.accordionC.closeAll()
|
|
382
458
|
if (this.radioChecked !== radio.id) {
|
|
383
459
|
globalLoader.show()
|
|
384
460
|
this.#mountTonder(false);
|
|
385
461
|
InlineCheckout.injected = true;
|
|
386
462
|
}
|
|
387
463
|
} else {
|
|
464
|
+
if (position !== null) {
|
|
465
|
+
this.accordionC.closeAll()
|
|
466
|
+
this.accordionC.open(position)
|
|
467
|
+
}
|
|
388
468
|
this.#unmountForm();
|
|
389
469
|
}
|
|
390
470
|
this.radioChecked = radio.id;
|