tonder-web-sdk 1.12.0-beta.9 → 1.14.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 +664 -106
- package/package.json +2 -1
- package/src/classes/3dsHandler.js +20 -9
- package/src/classes/BaseInlineCheckout.js +17 -23
- package/src/classes/LiteInlineCheckout.js +46 -41
- package/src/classes/inlineCheckout.js +86 -75
- package/src/data/cardApi.js +21 -4
- package/src/helpers/template.js +9 -1
- package/src/helpers/utils.js +4 -4
- package/src/helpers/validations.js +54 -0
- package/src/index-dev.js +160 -78
- package/src/index.html +4 -1
- package/src/index.js +7 -1
- package/types/{card.ts → card.d.ts} +1 -0
- package/types/{checkout.ts → checkout.d.ts} +1 -1
- package/types/{common.ts → common.d.ts} +1 -0
- package/types/{customer.ts → customer.d.ts} +1 -0
- package/types/index.d.ts +1 -1
- package/types/inlineCheckout.d.ts +53 -1
- package/types/liteInlineCheckout.d.ts +65 -8
- package/types/validations.d.ts +11 -0
- package/v1/bundle.min.js +3 -3
- package/webpack.config.js +12 -1
- package/.idea/aws.xml +0 -17
- package/.idea/inspectionProfiles/profiles_settings.xml +0 -6
- package/.idea/misc.xml +0 -4
- package/.idea/prettier.xml +0 -6
- package/.idea/vcs.xml +0 -6
- package/.idea/workspace.xml +0 -153
- /package/types/{paymentMethod.ts → paymentMethod.d.ts} +0 -0
- /package/types/{transaction.ts → transaction.d.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tonder-web-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.0",
|
|
4
4
|
"description": "tonder sdk for integrations",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"@babel/core": "^7.20.12",
|
|
19
19
|
"@babel/preset-env": "^7.20.2",
|
|
20
|
+
"@maskito/core": "^3.0.1",
|
|
20
21
|
"babel-loader": "^9.1.2",
|
|
21
22
|
"css-loader": "^6.7.3",
|
|
22
23
|
"cypress": "^13.6.2",
|
|
@@ -6,7 +6,8 @@ export class ThreeDSHandler {
|
|
|
6
6
|
}) {
|
|
7
7
|
this.baseUrl = baseUrl,
|
|
8
8
|
this.apiKey = apiKey,
|
|
9
|
-
this.payload = payload
|
|
9
|
+
this.payload = payload,
|
|
10
|
+
this.isTransactionPending = false
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
saveVerifyTransactionUrl() {
|
|
@@ -127,8 +128,6 @@ export class ThreeDSHandler {
|
|
|
127
128
|
return response;
|
|
128
129
|
}
|
|
129
130
|
|
|
130
|
-
// TODO: the method below needs to be tested with a real 3DS challenge
|
|
131
|
-
// since we couldn't get a test card that works with this feature
|
|
132
131
|
async handle3dsChallenge(response_json) {
|
|
133
132
|
// Create the form element:
|
|
134
133
|
const form = document.createElement('form');
|
|
@@ -139,15 +138,17 @@ export class ThreeDSHandler {
|
|
|
139
138
|
// Add hidden fields:
|
|
140
139
|
const creqInput = document.createElement('input');
|
|
141
140
|
creqInput.type = 'hidden';
|
|
142
|
-
creqInput.name =
|
|
141
|
+
creqInput.name = 'creq';
|
|
143
142
|
creqInput.value = response_json.creq;
|
|
144
143
|
form.appendChild(creqInput);
|
|
145
144
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
145
|
+
if (response_json.term_url) {
|
|
146
|
+
const termUrlInput = document.createElement('input');
|
|
147
|
+
termUrlInput.type = 'hidden';
|
|
148
|
+
termUrlInput.name = 'TermUrl';
|
|
149
|
+
termUrlInput.value = response_json.term_url;
|
|
150
|
+
form.appendChild(termUrlInput);
|
|
151
|
+
}
|
|
151
152
|
|
|
152
153
|
// Append the form to the body:
|
|
153
154
|
document.body.appendChild(form);
|
|
@@ -172,6 +173,14 @@ export class ThreeDSHandler {
|
|
|
172
173
|
}
|
|
173
174
|
|
|
174
175
|
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
|
|
175
184
|
const verifyUrl = this.getUrlWithExpiration();
|
|
176
185
|
|
|
177
186
|
if (verifyUrl) {
|
|
@@ -199,6 +208,8 @@ export class ThreeDSHandler {
|
|
|
199
208
|
} else {
|
|
200
209
|
console.log('No verify_transaction_status_url found');
|
|
201
210
|
}
|
|
211
|
+
|
|
212
|
+
this.isTransactionPending = false
|
|
202
213
|
}
|
|
203
214
|
|
|
204
215
|
setPayload = (payload) => {
|
|
@@ -13,12 +13,7 @@ import { getBrowserInfo, injectMercadoPagoSecurity } from "../helpers/utils";
|
|
|
13
13
|
export class BaseInlineCheckout {
|
|
14
14
|
baseUrl = "";
|
|
15
15
|
cartTotal = "0";
|
|
16
|
-
constructor({
|
|
17
|
-
mode = "stage",
|
|
18
|
-
apiKey,
|
|
19
|
-
returnUrl,
|
|
20
|
-
callBack = () => {},
|
|
21
|
-
}) {
|
|
16
|
+
constructor({ mode = "stage", apiKey, returnUrl, callBack = () => {} }) {
|
|
22
17
|
this.apiKeyTonder = apiKey;
|
|
23
18
|
this.returnUrl = returnUrl;
|
|
24
19
|
this.callBack = callBack;
|
|
@@ -34,11 +29,12 @@ export class BaseInlineCheckout {
|
|
|
34
29
|
/**
|
|
35
30
|
* The configureCheckout function allows you to set initial information, such as the customer's email, which is used to retrieve a list of saved cards.
|
|
36
31
|
* @param {import("../../types").IConfigureCheckout} data - Configuration data including customer information and potentially other settings.
|
|
37
|
-
* @returns {
|
|
32
|
+
* @returns {void}.
|
|
38
33
|
* @public
|
|
39
34
|
*/
|
|
40
35
|
configureCheckout(data) {
|
|
41
36
|
if ("customer" in data) this.#handleCustomer(data["customer"]);
|
|
37
|
+
if ("secureToken" in data) this.#handleSecureToken(data["secureToken"]);
|
|
42
38
|
}
|
|
43
39
|
|
|
44
40
|
/**
|
|
@@ -75,7 +71,6 @@ export class BaseInlineCheckout {
|
|
|
75
71
|
this.#handleMetadata(data);
|
|
76
72
|
this.#handleCurrency(data);
|
|
77
73
|
this.#handleCard(data);
|
|
78
|
-
console.log("data", data)
|
|
79
74
|
const response = await this._checkout(data);
|
|
80
75
|
this.process3ds.setPayload(response);
|
|
81
76
|
this.callBack(response);
|
|
@@ -121,7 +116,6 @@ export class BaseInlineCheckout {
|
|
|
121
116
|
async _handleCheckout({ card, payment_method, customer }) {
|
|
122
117
|
const { openpay_keys, reference, business } = this.merchantData;
|
|
123
118
|
const total = Number(this.cartTotal);
|
|
124
|
-
|
|
125
119
|
try {
|
|
126
120
|
let deviceSessionIdTonder;
|
|
127
121
|
if (
|
|
@@ -272,6 +266,10 @@ export class BaseInlineCheckout {
|
|
|
272
266
|
this.customer = customer;
|
|
273
267
|
}
|
|
274
268
|
|
|
269
|
+
#handleSecureToken(secureToken) {
|
|
270
|
+
this.secureToken = secureToken;
|
|
271
|
+
}
|
|
272
|
+
|
|
275
273
|
#handleMetadata(data) {
|
|
276
274
|
this.metadata = data?.metadata;
|
|
277
275
|
}
|
|
@@ -289,23 +287,19 @@ export class BaseInlineCheckout {
|
|
|
289
287
|
}
|
|
290
288
|
|
|
291
289
|
async #handle3dsRedirect(response) {
|
|
290
|
+
console.log('Handling 3DS redirect...');
|
|
292
291
|
const iframe = response?.next_action?.iframe_resources?.iframe;
|
|
292
|
+
const threeDsChallenge = response?.next_action?.three_ds_challenge;
|
|
293
293
|
|
|
294
294
|
if (iframe) {
|
|
295
|
-
|
|
296
|
-
.loadIframe()
|
|
297
|
-
.
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
// }, 10000);
|
|
304
|
-
this.process3ds.verifyTransactionStatus();
|
|
305
|
-
})
|
|
306
|
-
.catch((error) => {
|
|
307
|
-
console.log("Error loading iframe:", error);
|
|
308
|
-
});
|
|
295
|
+
try {
|
|
296
|
+
await this.process3ds.loadIframe();
|
|
297
|
+
await this.process3ds.verifyTransactionStatus();
|
|
298
|
+
} catch (error) {
|
|
299
|
+
console.log("Error loading iframe:", error);
|
|
300
|
+
}
|
|
301
|
+
} else if (threeDsChallenge) {
|
|
302
|
+
await this.process3ds.handle3dsChallenge(threeDsChallenge);
|
|
309
303
|
} else {
|
|
310
304
|
const redirectUrl = this.process3ds.getRedirectUrl();
|
|
311
305
|
if (redirectUrl) {
|
|
@@ -8,13 +8,12 @@ import {
|
|
|
8
8
|
} from "../data";
|
|
9
9
|
import { getSkyflowTokens } from "../helpers/skyflow";
|
|
10
10
|
import { getPaymentMethodDetails } from "../shared/catalog/paymentMethodsCatalog";
|
|
11
|
-
import { formatPublicErrorResponse } from "../helpers/utils";
|
|
11
|
+
import { formatPublicErrorResponse, getCardType } from "../helpers/utils";
|
|
12
12
|
import { MESSAGES } from "../shared/constants/messages";
|
|
13
13
|
|
|
14
14
|
export class LiteInlineCheckout extends BaseInlineCheckout {
|
|
15
15
|
#customerData;
|
|
16
16
|
constructor({ mode = "stage", apiKey, returnUrl, callBack = () => {} }) {
|
|
17
|
-
|
|
18
17
|
super({ mode, apiKey, returnUrl, callBack });
|
|
19
18
|
}
|
|
20
19
|
|
|
@@ -40,11 +39,18 @@ export class LiteInlineCheckout extends BaseInlineCheckout {
|
|
|
40
39
|
async getCustomerCards() {
|
|
41
40
|
try {
|
|
42
41
|
const { auth_token } = await this.#getCustomer();
|
|
43
|
-
|
|
42
|
+
const response = await fetchCustomerCards(
|
|
44
43
|
this.baseUrl,
|
|
45
44
|
auth_token,
|
|
46
45
|
this.merchantData.business.pk,
|
|
47
46
|
);
|
|
47
|
+
return {
|
|
48
|
+
...response,
|
|
49
|
+
cards: response.cards.map((ic) => ({
|
|
50
|
+
...ic,
|
|
51
|
+
icon: getCardType(ic.fields.card_scheme),
|
|
52
|
+
})),
|
|
53
|
+
};
|
|
48
54
|
} catch (error) {
|
|
49
55
|
throw formatPublicErrorResponse(
|
|
50
56
|
{
|
|
@@ -104,22 +110,22 @@ export class LiteInlineCheckout extends BaseInlineCheckout {
|
|
|
104
110
|
* @public
|
|
105
111
|
*/
|
|
106
112
|
async removeCustomerCard(skyflowId) {
|
|
107
|
-
try{
|
|
113
|
+
try {
|
|
108
114
|
const { auth_token } = await this.#getCustomer();
|
|
109
115
|
const { business } = this.merchantData;
|
|
110
116
|
|
|
111
117
|
return await removeCustomerCard(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
118
|
+
this.baseUrl,
|
|
119
|
+
auth_token,
|
|
120
|
+
skyflowId,
|
|
121
|
+
business?.pk,
|
|
116
122
|
);
|
|
117
|
-
}catch (error){
|
|
123
|
+
} catch (error) {
|
|
118
124
|
throw formatPublicErrorResponse(
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
125
|
+
{
|
|
126
|
+
message: MESSAGES.removeCardError,
|
|
127
|
+
},
|
|
128
|
+
error,
|
|
123
129
|
);
|
|
124
130
|
}
|
|
125
131
|
}
|
|
@@ -137,29 +143,29 @@ export class LiteInlineCheckout extends BaseInlineCheckout {
|
|
|
137
143
|
const response = await fetchCustomerAPMs(this.baseUrl, this.apiKeyTonder);
|
|
138
144
|
|
|
139
145
|
const apms_results =
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
146
|
+
response && "results" in response && response["results"].length > 0
|
|
147
|
+
? response["results"]
|
|
148
|
+
: [];
|
|
143
149
|
|
|
144
150
|
return apms_results
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}catch (error){
|
|
151
|
+
.filter((apmItem) => apmItem.category.toLowerCase() !== "cards")
|
|
152
|
+
.map((apmItem) => {
|
|
153
|
+
const apm = {
|
|
154
|
+
id: apmItem.pk,
|
|
155
|
+
payment_method: apmItem.payment_method,
|
|
156
|
+
priority: apmItem.priority,
|
|
157
|
+
category: apmItem.category,
|
|
158
|
+
...getPaymentMethodDetails(apmItem.payment_method),
|
|
159
|
+
};
|
|
160
|
+
return apm;
|
|
161
|
+
})
|
|
162
|
+
.sort((a, b) => a.priority - b.priority);
|
|
163
|
+
} catch (error) {
|
|
158
164
|
throw formatPublicErrorResponse(
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
165
|
+
{
|
|
166
|
+
message: MESSAGES.getPaymentMethodsError,
|
|
167
|
+
},
|
|
168
|
+
error,
|
|
163
169
|
);
|
|
164
170
|
}
|
|
165
171
|
}
|
|
@@ -169,7 +175,6 @@ export class LiteInlineCheckout extends BaseInlineCheckout {
|
|
|
169
175
|
}
|
|
170
176
|
|
|
171
177
|
async _checkout({ card, payment_method }) {
|
|
172
|
-
console.log("_checkout", card, payment_method)
|
|
173
178
|
const customer = await this._getCustomer(
|
|
174
179
|
this.customer,
|
|
175
180
|
this.abortController.signal,
|
|
@@ -177,7 +182,7 @@ export class LiteInlineCheckout extends BaseInlineCheckout {
|
|
|
177
182
|
const { vault_id, vault_url } = this.merchantData;
|
|
178
183
|
let skyflowTokens;
|
|
179
184
|
if (!payment_method || payment_method !== "" || payment_method === null) {
|
|
180
|
-
if (typeof
|
|
185
|
+
if (typeof card === "string") {
|
|
181
186
|
skyflowTokens = {
|
|
182
187
|
skyflow_id: card,
|
|
183
188
|
};
|
|
@@ -185,7 +190,7 @@ export class LiteInlineCheckout extends BaseInlineCheckout {
|
|
|
185
190
|
skyflowTokens = await getSkyflowTokens({
|
|
186
191
|
vault_id: vault_id,
|
|
187
192
|
vault_url: vault_url,
|
|
188
|
-
data: card,
|
|
193
|
+
data: {...card, card_number: card.card_number.replace(/\s+/g, '')},
|
|
189
194
|
baseUrl: this.baseUrl,
|
|
190
195
|
apiKey: this.apiKeyTonder,
|
|
191
196
|
});
|
|
@@ -200,13 +205,13 @@ export class LiteInlineCheckout extends BaseInlineCheckout {
|
|
|
200
205
|
}
|
|
201
206
|
|
|
202
207
|
async #getCustomer() {
|
|
203
|
-
if(!!this.#customerData) return this.#customerData;
|
|
208
|
+
if (!!this.#customerData) return this.#customerData;
|
|
204
209
|
|
|
205
210
|
this.#customerData = await registerOrFetchCustomer(
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
211
|
+
this.baseUrl,
|
|
212
|
+
this.apiKeyTonder,
|
|
213
|
+
this.customer,
|
|
209
214
|
);
|
|
210
|
-
return this.#customerData
|
|
215
|
+
return this.#customerData;
|
|
211
216
|
}
|
|
212
217
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {apmItemsTemplate, cardItemsTemplate, cardTemplate} from '../helpers/template.js'
|
|
1
|
+
import { apmItemsTemplate, cardItemsTemplate, cardTemplate } from '../helpers/template.js'
|
|
2
2
|
import {
|
|
3
3
|
clearSpace,
|
|
4
4
|
injectMercadoPagoSecurity,
|
|
@@ -6,18 +6,18 @@ import {
|
|
|
6
6
|
showError,
|
|
7
7
|
showMessage
|
|
8
8
|
} from '../helpers/utils';
|
|
9
|
-
import {initSkyflow} from '../helpers/skyflow'
|
|
10
|
-
import {globalLoader} from './globalLoader.js';
|
|
11
|
-
import {BaseInlineCheckout} from "./BaseInlineCheckout";
|
|
9
|
+
import { initSkyflow } from '../helpers/skyflow'
|
|
10
|
+
import { globalLoader } from './globalLoader.js';
|
|
11
|
+
import { BaseInlineCheckout } from "./BaseInlineCheckout";
|
|
12
12
|
import {
|
|
13
13
|
fetchCustomerCards,
|
|
14
14
|
removeCustomerCard,
|
|
15
15
|
saveCustomerCard,
|
|
16
16
|
fetchCustomerAPMs
|
|
17
17
|
} from "../data";
|
|
18
|
-
import {MESSAGES} from "../shared/constants/messages";
|
|
18
|
+
import { MESSAGES } from "../shared/constants/messages";
|
|
19
19
|
|
|
20
|
-
export class InlineCheckout extends BaseInlineCheckout{
|
|
20
|
+
export class InlineCheckout extends BaseInlineCheckout {
|
|
21
21
|
static injected = false;
|
|
22
22
|
static cardsInjected = false
|
|
23
23
|
static apmsInjected = false
|
|
@@ -42,19 +42,35 @@ export class InlineCheckout extends BaseInlineCheckout{
|
|
|
42
42
|
msgNotification: "msgNotification",
|
|
43
43
|
apmsListContainer: "apmsListContainer"
|
|
44
44
|
}
|
|
45
|
-
|
|
45
|
+
customization = {
|
|
46
|
+
saveCards: {
|
|
47
|
+
showSaveCardOption: false,
|
|
48
|
+
showSaved: false,
|
|
49
|
+
autoSave: false
|
|
50
|
+
}
|
|
51
|
+
}
|
|
46
52
|
constructor({
|
|
47
53
|
mode = "stage",
|
|
48
54
|
apiKey,
|
|
49
55
|
returnUrl,
|
|
50
56
|
renderPaymentButton = false,
|
|
51
57
|
callBack = () => { },
|
|
52
|
-
styles
|
|
58
|
+
styles,
|
|
59
|
+
customization,
|
|
53
60
|
}) {
|
|
54
61
|
super({ mode, apiKey, returnUrl, callBack });
|
|
55
62
|
this.renderPaymentButton = renderPaymentButton;
|
|
56
63
|
this.customStyles = styles
|
|
57
|
-
this.abortRefreshCardsController = new AbortController()
|
|
64
|
+
this.abortRefreshCardsController = new AbortController();
|
|
65
|
+
// TODO: Wait until SaveCards is ready (server token).
|
|
66
|
+
this.customization = {
|
|
67
|
+
...this.customization,
|
|
68
|
+
...(customization || {}),
|
|
69
|
+
saveCards: {
|
|
70
|
+
...this.customization.saveCards,
|
|
71
|
+
...(customization?.saveCards || {}),
|
|
72
|
+
},
|
|
73
|
+
}
|
|
58
74
|
}
|
|
59
75
|
|
|
60
76
|
#mountPayButton() {
|
|
@@ -130,20 +146,20 @@ export class InlineCheckout extends BaseInlineCheckout{
|
|
|
130
146
|
}
|
|
131
147
|
|
|
132
148
|
async #mount(containerTonderCheckout) {
|
|
133
|
-
containerTonderCheckout.innerHTML = cardTemplate({renderPaymentButton: this.renderPaymentButton, customStyles: this.customStyles});
|
|
149
|
+
containerTonderCheckout.innerHTML = cardTemplate({ renderPaymentButton: this.renderPaymentButton, customStyles: this.customStyles, customization: this.customization });
|
|
134
150
|
globalLoader.show()
|
|
135
151
|
await this.#mountTonder();
|
|
136
152
|
InlineCheckout.injected = true;
|
|
137
153
|
}
|
|
138
154
|
|
|
139
155
|
async #mountAPMs() {
|
|
140
|
-
try{
|
|
156
|
+
try {
|
|
141
157
|
const apms = await fetchCustomerAPMs(this.baseUrl, this.apiKeyTonder);
|
|
142
|
-
if(apms && apms['results'] && apms['results'].length > 0){
|
|
158
|
+
if (apms && apms['results'] && apms['results'].length > 0) {
|
|
143
159
|
this.apmsData = apms['results']
|
|
144
160
|
this.#loadAPMList(apms['results'])
|
|
145
161
|
}
|
|
146
|
-
}catch(e){
|
|
162
|
+
} catch (e) {
|
|
147
163
|
console.warn("Error getting APMS")
|
|
148
164
|
}
|
|
149
165
|
}
|
|
@@ -160,16 +176,7 @@ export class InlineCheckout extends BaseInlineCheckout{
|
|
|
160
176
|
const customerResponse = await this._getCustomer({ email: this.email });
|
|
161
177
|
if ("auth_token" in customerResponse) {
|
|
162
178
|
const { auth_token } = customerResponse
|
|
163
|
-
|
|
164
|
-
this.baseUrl,
|
|
165
|
-
auth_token,
|
|
166
|
-
this.merchantData.business.pk
|
|
167
|
-
);
|
|
168
|
-
|
|
169
|
-
if ("cards" in cards) {
|
|
170
|
-
const cardsMapped = cards.cards.map(mapCards)
|
|
171
|
-
this.#loadCardsList(cardsMapped, auth_token)
|
|
172
|
-
}
|
|
179
|
+
await this.#loadCardsList(auth_token)
|
|
173
180
|
}
|
|
174
181
|
}
|
|
175
182
|
|
|
@@ -256,39 +263,15 @@ export class InlineCheckout extends BaseInlineCheckout{
|
|
|
256
263
|
)
|
|
257
264
|
const { auth_token } = customerData;
|
|
258
265
|
if (auth_token && this.email) {
|
|
259
|
-
|
|
260
|
-
if (saveCard && "checked" in saveCard && saveCard.checked) {
|
|
261
|
-
try {
|
|
262
|
-
await saveCustomerCard(this.baseUrl, auth_token, business.pk, {
|
|
263
|
-
skyflow_id: cardTokens.skyflow_id,
|
|
264
|
-
});
|
|
265
|
-
showMessage(MESSAGES.cardSaved, this.collectorIds.msgNotification);
|
|
266
|
-
} catch (error) {
|
|
267
|
-
if (error?.message) {
|
|
268
|
-
showError(error.message)
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
this.cardsInjected = false;
|
|
273
|
-
|
|
274
|
-
const cards = await fetchCustomerCards(
|
|
275
|
-
this.baseUrl,
|
|
276
|
-
auth_token,
|
|
277
|
-
this.merchantData.business.pk,
|
|
278
|
-
);
|
|
279
|
-
if ("cards" in cards) {
|
|
280
|
-
const cardsMapped = cards.cards.map((card) => mapCards(card))
|
|
281
|
-
this.#loadCardsList(cardsMapped, auth_token)
|
|
282
|
-
}
|
|
283
|
-
}
|
|
266
|
+
await this.#handleSaveCard(auth_token, business.pk, cardTokens)
|
|
284
267
|
}
|
|
285
268
|
|
|
286
|
-
const selected_apm = this.apmsData ? this.apmsData.find((iapm) => iapm.pk ===
|
|
269
|
+
const selected_apm = this.apmsData ? this.apmsData.find((iapm) => iapm.pk === this.radioChecked) : {};
|
|
287
270
|
|
|
288
271
|
const jsonResponseRouter = await this._handleCheckout({
|
|
289
|
-
...(
|
|
290
|
-
|
|
291
|
-
|
|
272
|
+
...(selected_apm && Object.keys(selected_apm).length > 0
|
|
273
|
+
? { payment_method: selected_apm.payment_method }
|
|
274
|
+
: { card: cardTokens }),
|
|
292
275
|
customer: customerData
|
|
293
276
|
});
|
|
294
277
|
|
|
@@ -308,17 +291,49 @@ export class InlineCheckout extends BaseInlineCheckout{
|
|
|
308
291
|
}
|
|
309
292
|
};
|
|
310
293
|
|
|
311
|
-
#
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
294
|
+
async #handleSaveCard(auth_token, businessId, cardTokens) {
|
|
295
|
+
const saveCard = document.getElementById("save-checkout-card");
|
|
296
|
+
if ((saveCard && "checked" in saveCard && saveCard.checked) || !!this.customization.saveCards?.autoSave) {
|
|
297
|
+
try {
|
|
298
|
+
await saveCustomerCard(
|
|
299
|
+
this.baseUrl,
|
|
300
|
+
auth_token,
|
|
301
|
+
this.secureToken,
|
|
302
|
+
businessId,
|
|
303
|
+
{ skyflow_id: cardTokens.skyflow_id, }
|
|
304
|
+
);
|
|
305
|
+
showMessage(MESSAGES.cardSaved, this.collectorIds.msgNotification);
|
|
306
|
+
} catch (error) {
|
|
307
|
+
if (error?.message) {
|
|
308
|
+
showError(error.message)
|
|
309
|
+
}
|
|
320
310
|
}
|
|
321
|
-
|
|
311
|
+
|
|
312
|
+
await this.#loadCardsList(auth_token)
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
async #loadCardsList(token) {
|
|
316
|
+
if(this.cardsInjected || !this.customization.saveCards?.showSaved) return;
|
|
317
|
+
this.cardsInjected = false
|
|
318
|
+
const cardsResponse = await fetchCustomerCards(
|
|
319
|
+
this.baseUrl,
|
|
320
|
+
token,
|
|
321
|
+
this.secureToken,
|
|
322
|
+
this.merchantData.business.pk,
|
|
323
|
+
);
|
|
324
|
+
let cards = []
|
|
325
|
+
if("cards" in cardsResponse) {
|
|
326
|
+
cards = cardsResponse.cards.map(mapCards)
|
|
327
|
+
const injectInterval = setInterval(() => {
|
|
328
|
+
const queryElement = document.querySelector(`#${this.collectorIds.cardsListContainer}`);
|
|
329
|
+
if (queryElement && InlineCheckout.injected) {
|
|
330
|
+
queryElement.innerHTML = cardItemsTemplate(cards)
|
|
331
|
+
clearInterval(injectInterval)
|
|
332
|
+
this.#mountRadioButtons(token)
|
|
333
|
+
this.cardsInjected = true
|
|
334
|
+
}
|
|
335
|
+
}, 500);
|
|
336
|
+
}
|
|
322
337
|
}
|
|
323
338
|
|
|
324
339
|
#loadAPMList(apms) {
|
|
@@ -390,8 +405,14 @@ export class InlineCheckout extends BaseInlineCheckout{
|
|
|
390
405
|
this.abortRefreshCardsController = new AbortController();
|
|
391
406
|
}
|
|
392
407
|
const businessId = this.merchantData.business.pk
|
|
393
|
-
await removeCustomerCard(
|
|
394
|
-
|
|
408
|
+
await removeCustomerCard(
|
|
409
|
+
this.baseUrl,
|
|
410
|
+
customerToken,
|
|
411
|
+
this.secureToken,
|
|
412
|
+
skyflow_id,
|
|
413
|
+
businessId
|
|
414
|
+
)
|
|
415
|
+
} catch (error) { } finally {
|
|
395
416
|
this.deletingCards = this.deletingCards.filter(id => id !== skyflow_id);
|
|
396
417
|
this.#refreshCardOnDelete(customerToken)
|
|
397
418
|
}
|
|
@@ -399,17 +420,7 @@ export class InlineCheckout extends BaseInlineCheckout{
|
|
|
399
420
|
}
|
|
400
421
|
async #refreshCardOnDelete(customerToken) {
|
|
401
422
|
if (this.deletingCards.length > 0) return;
|
|
402
|
-
this
|
|
403
|
-
const cards = await fetchCustomerCards(
|
|
404
|
-
this.baseUrl,
|
|
405
|
-
customerToken,
|
|
406
|
-
this.merchantData.business.pk,
|
|
407
|
-
this.abortRefreshCardsController.signal
|
|
408
|
-
)
|
|
409
|
-
if ("cards" in cards) {
|
|
410
|
-
const cardsMapped = cards.cards.map(mapCards)
|
|
411
|
-
this.#loadCardsList(cardsMapped, customerToken)
|
|
412
|
-
}
|
|
423
|
+
await this.#loadCardsList(customerToken)
|
|
413
424
|
}
|
|
414
425
|
#unmountForm() {
|
|
415
426
|
InlineCheckout.injected = false
|
package/src/data/cardApi.js
CHANGED
|
@@ -11,6 +11,7 @@ import {MESSAGES} from "../shared/constants/messages";
|
|
|
11
11
|
*
|
|
12
12
|
* @param {string} baseUrl - The base URL of the API.
|
|
13
13
|
* @param {string} customerToken - The customer's authentication token.
|
|
14
|
+
* @param {string} secureToken - Token generated by secure-token endpoint.
|
|
14
15
|
* @param {string | number} businessId - The business ID.
|
|
15
16
|
* @param {import("../../types").ISaveCardSkyflowRequest} data - The card information to be saved.
|
|
16
17
|
* @returns {Promise<import("../../types").ISaveCardResponse>} The saved card data.
|
|
@@ -20,6 +21,7 @@ import {MESSAGES} from "../shared/constants/messages";
|
|
|
20
21
|
export async function saveCustomerCard(
|
|
21
22
|
baseUrl,
|
|
22
23
|
customerToken,
|
|
24
|
+
secureToken,
|
|
23
25
|
businessId,
|
|
24
26
|
data,
|
|
25
27
|
) {
|
|
@@ -28,7 +30,8 @@ export async function saveCustomerCard(
|
|
|
28
30
|
const response = await fetch(url, {
|
|
29
31
|
method: "POST",
|
|
30
32
|
headers: {
|
|
31
|
-
Authorization: `
|
|
33
|
+
Authorization: `Bearer ${secureToken}`,
|
|
34
|
+
"User-Token": customerToken,
|
|
32
35
|
"Content-Type": "application/json",
|
|
33
36
|
},
|
|
34
37
|
body: JSON.stringify(data),
|
|
@@ -57,6 +60,7 @@ export async function saveCustomerCard(
|
|
|
57
60
|
* Removes a customer's card.
|
|
58
61
|
* @param {string} baseUrl - The base URL of the API.
|
|
59
62
|
* @param {string} customerToken - The customer's authentication token.
|
|
63
|
+
* @param {string} secureToken - Token generated by secure-token endpoint.
|
|
60
64
|
* @param {string} skyflowId - The Skyflow ID of the card to be removed.
|
|
61
65
|
* @param {string} businessId - The business ID.
|
|
62
66
|
* @returns {Promise<string>} The result of the card removal operation.
|
|
@@ -66,6 +70,7 @@ export async function saveCustomerCard(
|
|
|
66
70
|
export async function removeCustomerCard(
|
|
67
71
|
baseUrl,
|
|
68
72
|
customerToken,
|
|
73
|
+
secureToken,
|
|
69
74
|
skyflowId = "",
|
|
70
75
|
businessId,
|
|
71
76
|
) {
|
|
@@ -75,8 +80,9 @@ export async function removeCustomerCard(
|
|
|
75
80
|
const response = await fetch(url, {
|
|
76
81
|
method: "DELETE",
|
|
77
82
|
headers: {
|
|
78
|
-
Authorization: `
|
|
83
|
+
Authorization: `Bearer ${secureToken}`,
|
|
79
84
|
"Content-Type": "application/json",
|
|
85
|
+
"User-Token": customerToken,
|
|
80
86
|
},
|
|
81
87
|
});
|
|
82
88
|
|
|
@@ -94,6 +100,7 @@ export async function removeCustomerCard(
|
|
|
94
100
|
* Fetches a customer's saved cards.
|
|
95
101
|
* @param {string} baseUrl - The base URL of the API.
|
|
96
102
|
* @param {string} customerToken - The customer's authentication token.
|
|
103
|
+
* @param {string} secureToken - Token generated by secure-token endpoint.
|
|
97
104
|
* @param {string} businessId - The business ID.
|
|
98
105
|
* @param {AbortSignal} signal - The abort signal to cancel the request.
|
|
99
106
|
* @returns {Promise<import("../../types").ICustomerCardsResponse>} The customer's saved cards.
|
|
@@ -103,6 +110,7 @@ export async function removeCustomerCard(
|
|
|
103
110
|
export async function fetchCustomerCards(
|
|
104
111
|
baseUrl,
|
|
105
112
|
customerToken,
|
|
113
|
+
secureToken,
|
|
106
114
|
businessId,
|
|
107
115
|
signal= null,
|
|
108
116
|
) {
|
|
@@ -111,12 +119,21 @@ export async function fetchCustomerCards(
|
|
|
111
119
|
const response = await fetch(url, {
|
|
112
120
|
method: "GET",
|
|
113
121
|
headers: {
|
|
114
|
-
Authorization: `
|
|
115
|
-
"
|
|
122
|
+
Authorization: `Bearer ${secureToken}`,
|
|
123
|
+
"User-Token": customerToken,
|
|
116
124
|
},
|
|
117
125
|
signal,
|
|
118
126
|
});
|
|
119
127
|
if (response.ok) return await response.json();
|
|
128
|
+
if (response.status === 401) {
|
|
129
|
+
return {
|
|
130
|
+
code: 401,
|
|
131
|
+
body: {},
|
|
132
|
+
name: "",
|
|
133
|
+
message: "Unauthorized",
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
120
137
|
const res_json = await response.json();
|
|
121
138
|
|
|
122
139
|
throw await buildErrorResponse(response, res_json, MESSAGES.getCardsError);
|