tonder-web-sdk 1.7.0 → 1.8.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/package.json +1 -1
- package/src/classes/inlineCheckout.js +134 -6
- package/src/data/api.js +63 -0
- package/src/helpers/skyflow.js +12 -2
- package/src/helpers/template.js +328 -7
- package/src/helpers/utils.js +71 -0
- package/src/index-dev.js +1 -1
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cardTemplate } from '../helpers/template.js'
|
|
1
|
+
import { cardItemsTemplate, cardTemplate } from '../helpers/template.js'
|
|
2
2
|
import { cardTemplateSkeleton } from '../helpers/template-skeleton.js'
|
|
3
3
|
import {
|
|
4
4
|
getBusiness,
|
|
@@ -6,11 +6,16 @@ import {
|
|
|
6
6
|
createOrder,
|
|
7
7
|
createPayment,
|
|
8
8
|
startCheckoutRouter,
|
|
9
|
-
getOpenpayDeviceSessionID
|
|
9
|
+
getOpenpayDeviceSessionID,
|
|
10
|
+
getCustomerCards,
|
|
11
|
+
registerCard,
|
|
12
|
+
deleteCustomerCard
|
|
10
13
|
} from '../data/api';
|
|
11
14
|
import {
|
|
12
15
|
showError,
|
|
13
16
|
getBrowserInfo,
|
|
17
|
+
mapCards,
|
|
18
|
+
showMessage,
|
|
14
19
|
} from '../helpers/utils';
|
|
15
20
|
import { initSkyflow } from '../helpers/skyflow'
|
|
16
21
|
import { ThreeDSHandler } from './3dsHandler.js';
|
|
@@ -18,6 +23,7 @@ import { ThreeDSHandler } from './3dsHandler.js';
|
|
|
18
23
|
|
|
19
24
|
export class InlineCheckout {
|
|
20
25
|
static injected = false;
|
|
26
|
+
static cardsInjected = false
|
|
21
27
|
customer = {}
|
|
22
28
|
items = []
|
|
23
29
|
baseUrl = null
|
|
@@ -26,6 +32,18 @@ export class InlineCheckout {
|
|
|
26
32
|
cartTotal = null
|
|
27
33
|
metadata = {}
|
|
28
34
|
card = {}
|
|
35
|
+
collectorIds = {
|
|
36
|
+
cardsListContainer: "cardsListContainer",
|
|
37
|
+
holderName: "collectCardholderName",
|
|
38
|
+
cardNumber: "collectCardNumber",
|
|
39
|
+
expirationMonth: "collectExpirationMonth",
|
|
40
|
+
expirationYear: "collectExpirationYear",
|
|
41
|
+
cvv: "collectCvv",
|
|
42
|
+
tonderPayButton: "tonderPayButton",
|
|
43
|
+
msgError: "msgError",
|
|
44
|
+
msgNotification: "msgNotification"
|
|
45
|
+
|
|
46
|
+
}
|
|
29
47
|
|
|
30
48
|
constructor({
|
|
31
49
|
mode = "stage",
|
|
@@ -34,7 +52,7 @@ export class InlineCheckout {
|
|
|
34
52
|
successUrl,
|
|
35
53
|
renderPaymentButton = false,
|
|
36
54
|
callBack = () => { },
|
|
37
|
-
styles
|
|
55
|
+
styles
|
|
38
56
|
}) {
|
|
39
57
|
this.apiKeyTonder = apiKey;
|
|
40
58
|
this.returnUrl = returnUrl;
|
|
@@ -172,6 +190,9 @@ export class InlineCheckout {
|
|
|
172
190
|
this.cartItems = items
|
|
173
191
|
}
|
|
174
192
|
|
|
193
|
+
setCustomerEmail (email) {
|
|
194
|
+
this.email = email
|
|
195
|
+
}
|
|
175
196
|
setCartTotal(total) {
|
|
176
197
|
console.log('total: ', total)
|
|
177
198
|
this.cartTotal = total
|
|
@@ -215,13 +236,14 @@ export class InlineCheckout {
|
|
|
215
236
|
let checkoutContainer = document.querySelector("#global-loader");
|
|
216
237
|
if (checkoutContainer) {
|
|
217
238
|
checkoutContainer.innerHTML = cardTemplateSkeleton;
|
|
239
|
+
checkoutContainer.style.display = 'block';
|
|
218
240
|
}
|
|
219
241
|
}
|
|
220
242
|
|
|
221
243
|
#removeGlobalLoader() {
|
|
222
244
|
const loader = document.querySelector('#global-loader');
|
|
223
245
|
if (loader) {
|
|
224
|
-
loader.
|
|
246
|
+
loader.style.display = 'none';
|
|
225
247
|
}
|
|
226
248
|
}
|
|
227
249
|
|
|
@@ -245,13 +267,25 @@ export class InlineCheckout {
|
|
|
245
267
|
return await customerRegister(this.baseUrl, this.apiKeyTonder, customer, signal);
|
|
246
268
|
}
|
|
247
269
|
|
|
248
|
-
async #mountTonder() {
|
|
270
|
+
async #mountTonder(getCards = true) {
|
|
249
271
|
this.#mountPayButton()
|
|
250
272
|
try{
|
|
251
273
|
const {
|
|
252
274
|
vault_id,
|
|
253
275
|
vault_url,
|
|
254
276
|
} = await this.#fetchMerchantData();
|
|
277
|
+
if(this.email && getCards){
|
|
278
|
+
const customerResponse = await this.getCustomer({email: this.email});
|
|
279
|
+
if("auth_token" in customerResponse) {
|
|
280
|
+
const { auth_token } = customerResponse
|
|
281
|
+
const cards = await getCustomerCards(this.baseUrl, auth_token);
|
|
282
|
+
|
|
283
|
+
if("cards" in cards) {
|
|
284
|
+
const cardsMapped = cards.cards.map(mapCards)
|
|
285
|
+
this.#loadCardsList(cardsMapped, auth_token)
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
255
289
|
|
|
256
290
|
this.collectContainer = await initSkyflow(
|
|
257
291
|
vault_id,
|
|
@@ -274,6 +308,7 @@ export class InlineCheckout {
|
|
|
274
308
|
|
|
275
309
|
removeCheckout() {
|
|
276
310
|
InlineCheckout.injected = false
|
|
311
|
+
InlineCheckout.cardsInjected = false
|
|
277
312
|
// Cancel all requests
|
|
278
313
|
this.abortController.abort();
|
|
279
314
|
this.abortController = new AbortController();
|
|
@@ -285,7 +320,7 @@ export class InlineCheckout {
|
|
|
285
320
|
async #getCardTokens() {
|
|
286
321
|
if (this.card?.skyflow_id) return this.card
|
|
287
322
|
try {
|
|
288
|
-
const collectResponse = await this.collectContainer.collect();
|
|
323
|
+
const collectResponse = await this.collectContainer.container.collect();
|
|
289
324
|
const cardTokens = await collectResponse["records"][0]["fields"];
|
|
290
325
|
return cardTokens;
|
|
291
326
|
} catch (error) {
|
|
@@ -319,7 +354,23 @@ export class InlineCheckout {
|
|
|
319
354
|
this.customer,
|
|
320
355
|
this.abortController.signal
|
|
321
356
|
)
|
|
357
|
+
if(auth_token && this.email){
|
|
358
|
+
const saveCard = document.getElementById("save-checkout-card");
|
|
359
|
+
if(saveCard && "checked" in saveCard && saveCard.checked){
|
|
360
|
+
await registerCard(this.baseUrl, auth_token, { skyflow_id: cardTokens.skyflow_id });
|
|
361
|
+
|
|
362
|
+
this.cardsInjected = false;
|
|
363
|
+
|
|
364
|
+
const cards = await getCustomerCards(this.baseUrl, auth_token);
|
|
365
|
+
if("cards" in cards) {
|
|
366
|
+
const cardsMapped = cards.cards.map((card) => mapCards(card))
|
|
367
|
+
this.#loadCardsList(cardsMapped, auth_token)
|
|
368
|
+
}
|
|
322
369
|
|
|
370
|
+
showMessage("Tarjeta registrada con éxito", this.collectorIds.msgNotification);
|
|
371
|
+
|
|
372
|
+
}
|
|
373
|
+
}
|
|
323
374
|
var orderItems = {
|
|
324
375
|
business: this.apiKeyTonder,
|
|
325
376
|
client: auth_token,
|
|
@@ -401,4 +452,81 @@ export class InlineCheckout {
|
|
|
401
452
|
throw error;
|
|
402
453
|
}
|
|
403
454
|
};
|
|
455
|
+
|
|
456
|
+
#loadCardsList (cards, token) {
|
|
457
|
+
if(this.cardsInjected) return;
|
|
458
|
+
const injectInterval = setInterval(() => {
|
|
459
|
+
const queryElement = document.querySelector(`#${this.collectorIds.cardsListContainer}`);
|
|
460
|
+
if (queryElement && InlineCheckout.injected) {
|
|
461
|
+
queryElement.innerHTML = cardItemsTemplate(cards)
|
|
462
|
+
clearInterval(injectInterval)
|
|
463
|
+
this.#mountRadioButtons(token)
|
|
464
|
+
this.cardsInjected = true
|
|
465
|
+
}
|
|
466
|
+
}, 500);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
#mountRadioButtons (token) {
|
|
470
|
+
const radioButtons = document.getElementsByName(`card_selected`);
|
|
471
|
+
for (const radio of radioButtons) {
|
|
472
|
+
radio.style.display = "block";
|
|
473
|
+
radio.onclick = async (event) => {
|
|
474
|
+
await this.#handleRadioButtonClick(radio);
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
const cardsButtons = document.getElementsByClassName("card-delete-button");
|
|
478
|
+
for (const cardButton of cardsButtons) {
|
|
479
|
+
cardButton.addEventListener("click", (event) => {
|
|
480
|
+
event.preventDefault();
|
|
481
|
+
this.#handleDeleteCardButtonClick(token, cardButton)
|
|
482
|
+
}, false);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
async #handleRadioButtonClick (radio) {
|
|
487
|
+
if(radio.id === this.radioChecked || ( radio.id === "new" && this.radioChecked === undefined)) return;
|
|
488
|
+
const containerForm = document.querySelector(".container-form");
|
|
489
|
+
if(containerForm) {
|
|
490
|
+
containerForm.style.display = radio.id === "new" ? "block" : "none";
|
|
491
|
+
}
|
|
492
|
+
if(radio.id === "new") {
|
|
493
|
+
if(this.radioChecked !== radio.id) {
|
|
494
|
+
this.#addGlobalLoader()
|
|
495
|
+
this.#mountTonder(false);
|
|
496
|
+
InlineCheckout.injected = true;
|
|
497
|
+
}
|
|
498
|
+
} else {
|
|
499
|
+
this.#unmountForm();
|
|
500
|
+
}
|
|
501
|
+
this.radioChecked = radio.id;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
async #handleDeleteCardButtonClick (customerToken, button) {
|
|
505
|
+
const id = button.attributes.getNamedItem("id")
|
|
506
|
+
const skyflow_id = id?.value?.split("_")?.[2]
|
|
507
|
+
if(skyflow_id) {
|
|
508
|
+
const cardClicked = document.querySelector(`#card_container-${skyflow_id}`);
|
|
509
|
+
if(cardClicked) {
|
|
510
|
+
cardClicked.style.display = "none"
|
|
511
|
+
}
|
|
512
|
+
await deleteCustomerCard(this.baseUrl, customerToken, skyflow_id)
|
|
513
|
+
this.cardsInjected = false
|
|
514
|
+
const cards = await getCustomerCards(this.baseUrl, customerToken)
|
|
515
|
+
if("cards" in cards) {
|
|
516
|
+
const cardsMapped = cards.cards.map(mapCards)
|
|
517
|
+
this.#loadCardsList(cardsMapped, customerToken)
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
#unmountForm () {
|
|
523
|
+
InlineCheckout.injected = false
|
|
524
|
+
if(this.collectContainer) {
|
|
525
|
+
if("unmount" in this.collectContainer.elements.cardHolderNameElement) this.collectContainer.elements.cardHolderNameElement.unmount()
|
|
526
|
+
if("unmount" in this.collectContainer.elements.cardNumberElement) this.collectContainer.elements.cardNumberElement.unmount()
|
|
527
|
+
if("unmount" in this.collectContainer.elements.expiryYearElement) this.collectContainer.elements.expiryYearElement.unmount()
|
|
528
|
+
if("unmount" in this.collectContainer.elements.expiryMonthElement) this.collectContainer.elements.expiryMonthElement.unmount()
|
|
529
|
+
if("unmount" in this.collectContainer.elements.cvvElement) this.collectContainer.elements.cvvElement.unmount()
|
|
530
|
+
}
|
|
531
|
+
}
|
|
404
532
|
}
|
package/src/data/api.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { buildErrorResponse, buildErrorResponseFromCatch } from "../helpers/utils";
|
|
2
|
+
|
|
1
3
|
export async function getOpenpayDeviceSessionID(merchant_id, public_key, signal) {
|
|
2
4
|
let openpay = await window.OpenPay;
|
|
3
5
|
openpay.setId(merchant_id);
|
|
@@ -107,3 +109,64 @@ export async function startCheckoutRouter(baseUrlTonder, apiKeyTonder, routerIte
|
|
|
107
109
|
throw error
|
|
108
110
|
}
|
|
109
111
|
}
|
|
112
|
+
|
|
113
|
+
export async function registerCard(baseUrlTonder, customerToken, data) {
|
|
114
|
+
try {
|
|
115
|
+
const response = await fetch(`${baseUrlTonder}/api/v1/cards/`, {
|
|
116
|
+
method: 'POST',
|
|
117
|
+
headers: {
|
|
118
|
+
'Authorization': `Token ${customerToken}`,
|
|
119
|
+
'Content-Type': 'application/json'
|
|
120
|
+
},
|
|
121
|
+
body: JSON.stringify(data)
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
if (response.ok) return await response.json();
|
|
125
|
+
if (response.status === 409){
|
|
126
|
+
const res_json = await response.json()
|
|
127
|
+
if(res_json.error = 'Card number already exists.'){
|
|
128
|
+
return {
|
|
129
|
+
code: 200,
|
|
130
|
+
body: res_json,
|
|
131
|
+
name: '',
|
|
132
|
+
message: res_json.error,
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
throw await buildErrorResponse(response);
|
|
137
|
+
} catch (error) {
|
|
138
|
+
throw buildErrorResponseFromCatch(error);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
export async function deleteCustomerCard(baseUrlTonder, customerToken, skyflowId = "") {
|
|
142
|
+
try {
|
|
143
|
+
const response = await fetch(`${baseUrlTonder}/api/v1/cards/${skyflowId}`, {
|
|
144
|
+
method: 'DELETE',
|
|
145
|
+
headers: {
|
|
146
|
+
'Authorization': `Token ${customerToken}`,
|
|
147
|
+
'Content-Type': 'application/json'
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
if (response.ok) return true;
|
|
152
|
+
throw await buildErrorResponse(response);
|
|
153
|
+
} catch (error) {
|
|
154
|
+
throw buildErrorResponseFromCatch(error);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
export async function getCustomerCards(baseUrlTonder, customerToken, query = "") {
|
|
158
|
+
try {
|
|
159
|
+
const response = await fetch(`${baseUrlTonder}/api/v1/cards/${query}`, {
|
|
160
|
+
method: 'GET',
|
|
161
|
+
headers: {
|
|
162
|
+
'Authorization': `Token ${customerToken}`,
|
|
163
|
+
'Content-Type': 'application/json'
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
if (response.ok) return await response.json();
|
|
168
|
+
throw await buildErrorResponse(response);
|
|
169
|
+
} catch (error) {
|
|
170
|
+
throw buildErrorResponseFromCatch(error);
|
|
171
|
+
}
|
|
172
|
+
}
|
package/src/helpers/skyflow.js
CHANGED
|
@@ -6,7 +6,8 @@ export async function initSkyflow(
|
|
|
6
6
|
baseUrl,
|
|
7
7
|
apiKey,
|
|
8
8
|
signal,
|
|
9
|
-
customStyles = {}
|
|
9
|
+
customStyles = {},
|
|
10
|
+
collectorIds,
|
|
10
11
|
) {
|
|
11
12
|
const skyflow = await Skyflow.init({
|
|
12
13
|
vaultID: vaultId,
|
|
@@ -121,7 +122,16 @@ export async function initSkyflow(
|
|
|
121
122
|
cardHolderNameElement,
|
|
122
123
|
)
|
|
123
124
|
|
|
124
|
-
return
|
|
125
|
+
return {
|
|
126
|
+
container: collectContainer,
|
|
127
|
+
elements: {
|
|
128
|
+
cardHolderNameElement,
|
|
129
|
+
cardNumberElement,
|
|
130
|
+
cvvElement,
|
|
131
|
+
expiryMonthElement,
|
|
132
|
+
expiryYearElement
|
|
133
|
+
}
|
|
134
|
+
}
|
|
125
135
|
}
|
|
126
136
|
|
|
127
137
|
async function mountElements(
|
package/src/helpers/template.js
CHANGED
|
@@ -1,14 +1,33 @@
|
|
|
1
|
+
import { getCardType } from "./utils";
|
|
2
|
+
|
|
1
3
|
export const cardTemplate = `
|
|
2
4
|
<div class="container-tonder">
|
|
5
|
+
<div id="cardsListContainer" class="cards-list-container"></div>
|
|
6
|
+
<div class="pay-new-card">
|
|
7
|
+
<input checked id="new" class="card_selected" name="card_selected" type="radio"/>
|
|
8
|
+
<label class="card-item-label-new" for="new">
|
|
9
|
+
<img class="card-image" src="${getCardType("XXXX")}" />
|
|
10
|
+
<div class="card-number">Pagar con tarjeta</div>
|
|
11
|
+
</label>
|
|
12
|
+
</div>
|
|
3
13
|
<div id="global-loader" class="global-loader"></div>
|
|
4
|
-
<div
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
<div
|
|
8
|
-
|
|
9
|
-
|
|
14
|
+
<div class="container-form">
|
|
15
|
+
<div id="collectCardholderName" class="empty-div"></div>
|
|
16
|
+
<div id="collectCardNumber" class="empty-div"></div>
|
|
17
|
+
<div class="collect-row">
|
|
18
|
+
<div id="collectExpirationMonth" class="empty-div"></div>
|
|
19
|
+
<div id="collectExpirationYear" class="expiration-year"></div>
|
|
20
|
+
<div id="collectCvv" class="empty-div"></div>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="checkbox">
|
|
23
|
+
<input id="save-checkout-card" type="checkbox">
|
|
24
|
+
<label for="save-checkout-card">
|
|
25
|
+
Guardar tarjeta para futuros pagos
|
|
26
|
+
</label>
|
|
27
|
+
</div>
|
|
28
|
+
<div id="msgError"></div>
|
|
29
|
+
<div id="msgNotification"></div>
|
|
10
30
|
</div>
|
|
11
|
-
<div id="msgError"></div>
|
|
12
31
|
<button id="tonderPayButton" class="pay-button">Pagar</button>
|
|
13
32
|
</div>
|
|
14
33
|
|
|
@@ -57,6 +76,16 @@ export const cardTemplate = `
|
|
|
57
76
|
text-align: left !important;
|
|
58
77
|
}
|
|
59
78
|
|
|
79
|
+
.message-container{
|
|
80
|
+
color: #3bc635 !important;
|
|
81
|
+
background-color: #DAFCE4 !important;
|
|
82
|
+
margin-bottom: 13px !important;
|
|
83
|
+
font-size: 80% !important;
|
|
84
|
+
padding: 8px 10px !important;
|
|
85
|
+
border-radius: 10px !important;
|
|
86
|
+
text-align: left !important;
|
|
87
|
+
}
|
|
88
|
+
|
|
60
89
|
.pay-button {
|
|
61
90
|
font-size: 16px;
|
|
62
91
|
font-weight: bold;
|
|
@@ -117,5 +146,297 @@ export const cardTemplate = `
|
|
|
117
146
|
}
|
|
118
147
|
}
|
|
119
148
|
|
|
149
|
+
.checkbox label {
|
|
150
|
+
margin-left: 10px;
|
|
151
|
+
font-size: '12px';
|
|
152
|
+
font-weight: '500';
|
|
153
|
+
color: #1D1D1D;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.checkbox {
|
|
157
|
+
margin-top: 10px;
|
|
158
|
+
margin-bottom: 20px;
|
|
159
|
+
text-align: left;
|
|
160
|
+
padding: 0 10px;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.cards-list-container {
|
|
164
|
+
display: flex;
|
|
165
|
+
flex-direction: column;
|
|
166
|
+
padding: 0px 10px 0px 10px;
|
|
167
|
+
gap: 33% 20px;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.pay-new-card {
|
|
171
|
+
display: flex;
|
|
172
|
+
justify-content: start;
|
|
173
|
+
align-items: center;
|
|
174
|
+
color: #1D1D1D;
|
|
175
|
+
gap: 33% 20px;
|
|
176
|
+
margin-top: 10px;
|
|
177
|
+
margin-bottom: 10px;
|
|
178
|
+
padding-left: 10px;
|
|
179
|
+
padding-right: 10px;
|
|
180
|
+
width: 90%;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.pay-new-card .card-number {
|
|
184
|
+
font-size: 16px;
|
|
185
|
+
}
|
|
186
|
+
.card-image {
|
|
187
|
+
width: 39px;
|
|
188
|
+
height: 24px;
|
|
189
|
+
text-align: left;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.card-item-label-new {
|
|
193
|
+
display: flex;
|
|
194
|
+
justify-content: start;
|
|
195
|
+
align-items: center;
|
|
196
|
+
color: #1D1D1D;
|
|
197
|
+
gap: 33% 20px;
|
|
198
|
+
margin-top: 10px;
|
|
199
|
+
margin-bottom: 10px;
|
|
200
|
+
padding-left: 10px;
|
|
201
|
+
padding-right: 10px;
|
|
202
|
+
width: 90%;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.card_selected {
|
|
206
|
+
position: relative;
|
|
207
|
+
width: 16px;
|
|
208
|
+
height: 16px;
|
|
209
|
+
appearance: none;
|
|
210
|
+
cursor: pointer;
|
|
211
|
+
border-radius: 100%;
|
|
212
|
+
border: 1px #3bc635 solid;
|
|
213
|
+
color: #3bc635;
|
|
214
|
+
transition-property: all;
|
|
215
|
+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
216
|
+
transition-duration: 150ms;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.card_selected:before {
|
|
220
|
+
width: 8px;
|
|
221
|
+
height: 8px;
|
|
222
|
+
content: "";
|
|
223
|
+
position: absolute;
|
|
224
|
+
top: 50%;
|
|
225
|
+
left: 50%;
|
|
226
|
+
display: block;
|
|
227
|
+
transform: translate(-50%, -50%);
|
|
228
|
+
border-radius: 100%;
|
|
229
|
+
background-color: #3bc635;
|
|
230
|
+
opacity: 0;
|
|
231
|
+
transition-property: opacity;
|
|
232
|
+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
233
|
+
transition-duration: 150ms;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.card_selected:checked {
|
|
237
|
+
border: 1px #3bc635 solid;
|
|
238
|
+
position: relative;
|
|
239
|
+
width: 16px;
|
|
240
|
+
height: 16px;
|
|
241
|
+
appearance: none;
|
|
242
|
+
cursor: pointer;
|
|
243
|
+
border-radius: 100%;
|
|
244
|
+
color: #3bc635;
|
|
245
|
+
transition-property: all;
|
|
246
|
+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
247
|
+
transition-duration: 150ms;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.card_selected:checked:before {
|
|
251
|
+
content: "";
|
|
252
|
+
border: 1px #3bc635 solid;
|
|
253
|
+
width: 8px;
|
|
254
|
+
height: 8px;
|
|
255
|
+
position: absolute;
|
|
256
|
+
top: 50%;
|
|
257
|
+
left: 50%;
|
|
258
|
+
display: block;
|
|
259
|
+
transform: translate(-50%, -50%);
|
|
260
|
+
border-radius: 100%;
|
|
261
|
+
background-color: #3bc635;
|
|
262
|
+
opacity: 50;
|
|
263
|
+
transition-property: opacity;
|
|
264
|
+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
265
|
+
transition-duration: 150ms;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.card_selected:hover:before {
|
|
269
|
+
width: 8px;
|
|
270
|
+
height: 8px;
|
|
271
|
+
content: "";
|
|
272
|
+
position: absolute;
|
|
273
|
+
top: 50%;
|
|
274
|
+
left: 50%;
|
|
275
|
+
display: block;
|
|
276
|
+
transform: translate(-50%, -50%);
|
|
277
|
+
border-radius: 100%;
|
|
278
|
+
background-color: #3bc635;
|
|
279
|
+
transition-property: opacity;
|
|
280
|
+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
281
|
+
transition-duration: 150ms;
|
|
282
|
+
opacity: 10;
|
|
283
|
+
}
|
|
120
284
|
</style>
|
|
121
285
|
`
|
|
286
|
+
|
|
287
|
+
export const cardItemsTemplate = (cards) => {
|
|
288
|
+
|
|
289
|
+
const cardItemsHTML = cards.reduce((total, card) => {
|
|
290
|
+
return `${total}
|
|
291
|
+
<div class="card-item" id="card_container-${card.skyflow_id}">
|
|
292
|
+
<input id="${card.skyflow_id}" class="card_selected" name="card_selected" type="radio"/>
|
|
293
|
+
<label class="card-item-label" for="${card.skyflow_id}">
|
|
294
|
+
<img class="card-image" src="${getCardType(card.card_scheme)}" />
|
|
295
|
+
<div class="card-number">${card.card_number}</div>
|
|
296
|
+
<div class="card-expiration">Exp. ${card.expiration_month}/${card.expiration_year}</div>
|
|
297
|
+
<div class="card-delete-icon">
|
|
298
|
+
<button id="delete_button_${card.skyflow_id}" class="card-delete-button">
|
|
299
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px">
|
|
300
|
+
<path fill="currentColor" d="M292.309-140.001q-30.308 0-51.308-21t-21-51.308V-720h-40v-59.999H360v-35.384h240v35.384h179.999V-720h-40v507.691q0 30.308-21 51.308t-51.308 21H292.309ZM376.155-280h59.999v-360h-59.999v360Zm147.691 0h59.999v-360h-59.999v360Z"/>
|
|
301
|
+
</svg>
|
|
302
|
+
</button>
|
|
303
|
+
</div>
|
|
304
|
+
</label>
|
|
305
|
+
</div>`
|
|
306
|
+
}, ``);
|
|
307
|
+
|
|
308
|
+
const cardItemStyle = `
|
|
309
|
+
<style>
|
|
310
|
+
.card-item-label {
|
|
311
|
+
display: flex;
|
|
312
|
+
justify-content: space-between;
|
|
313
|
+
align-items: center;
|
|
314
|
+
color: #1D1D1D;
|
|
315
|
+
gap: 33% 20px;
|
|
316
|
+
margin-top: 10px;
|
|
317
|
+
margin-bottom: 10px;
|
|
318
|
+
padding-left: 10px;
|
|
319
|
+
padding-right: 10px;
|
|
320
|
+
width: 90%;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.card-item {
|
|
324
|
+
display: flex;
|
|
325
|
+
justify-content: start;
|
|
326
|
+
align-items: center;
|
|
327
|
+
gap: 33% 20px;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
.card-item .card-number {
|
|
331
|
+
font-size: 16px;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
.card-item .card-expiration {
|
|
335
|
+
font-size: 16px;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.card-image {
|
|
339
|
+
width: 39px;
|
|
340
|
+
height: 24px;
|
|
341
|
+
text-align: left;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
.card-delete-button {
|
|
345
|
+
background-color: transparent !important;
|
|
346
|
+
color: #000000 !important;
|
|
347
|
+
border: none;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.card-delete-button:hover {
|
|
351
|
+
background-color: transparent !important;
|
|
352
|
+
color: #D91C1C !important;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.card_selected {
|
|
356
|
+
position: relative;
|
|
357
|
+
width: 16px;
|
|
358
|
+
height: 16px;
|
|
359
|
+
appearance: none;
|
|
360
|
+
cursor: pointer;
|
|
361
|
+
border-radius: 100%;
|
|
362
|
+
border: 1px #3bc635 solid;
|
|
363
|
+
color: #3bc635;
|
|
364
|
+
transition-property: all;
|
|
365
|
+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
366
|
+
transition-duration: 150ms;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
.card_selected:before {
|
|
370
|
+
width: 8px;
|
|
371
|
+
height: 8px;
|
|
372
|
+
content: "";
|
|
373
|
+
position: absolute;
|
|
374
|
+
top: 50%;
|
|
375
|
+
left: 50%;
|
|
376
|
+
display: block;
|
|
377
|
+
transform: translate(-50%, -50%);
|
|
378
|
+
border-radius: 100%;
|
|
379
|
+
background-color: #3bc635;
|
|
380
|
+
opacity: 0;
|
|
381
|
+
transition-property: opacity;
|
|
382
|
+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
383
|
+
transition-duration: 150ms;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.card_selected:checked {
|
|
387
|
+
border: 1px #3bc635 solid;
|
|
388
|
+
position: relative;
|
|
389
|
+
width: 16px;
|
|
390
|
+
height: 16px;
|
|
391
|
+
appearance: none;
|
|
392
|
+
cursor: pointer;
|
|
393
|
+
border-radius: 100%;
|
|
394
|
+
color: #3bc635;
|
|
395
|
+
transition-property: all;
|
|
396
|
+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
397
|
+
transition-duration: 150ms;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
.card_selected:checked:before {
|
|
401
|
+
content: "";
|
|
402
|
+
border: 1px #3bc635 solid;
|
|
403
|
+
width: 8px;
|
|
404
|
+
height: 8px;
|
|
405
|
+
position: absolute;
|
|
406
|
+
top: 50%;
|
|
407
|
+
left: 50%;
|
|
408
|
+
display: block;
|
|
409
|
+
transform: translate(-50%, -50%);
|
|
410
|
+
border-radius: 100%;
|
|
411
|
+
background-color: #3bc635;
|
|
412
|
+
opacity: 50;
|
|
413
|
+
transition-property: opacity;
|
|
414
|
+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
415
|
+
transition-duration: 150ms;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.card_selected:hover:before {
|
|
419
|
+
width: 8px;
|
|
420
|
+
height: 8px;
|
|
421
|
+
content: "";
|
|
422
|
+
position: absolute;
|
|
423
|
+
top: 50%;
|
|
424
|
+
left: 50%;
|
|
425
|
+
display: block;
|
|
426
|
+
transform: translate(-50%, -50%);
|
|
427
|
+
border-radius: 100%;
|
|
428
|
+
background-color: #3bc635;
|
|
429
|
+
transition-property: opacity;
|
|
430
|
+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
431
|
+
transition-duration: 150ms;
|
|
432
|
+
opacity: 10;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
</style>
|
|
436
|
+
`
|
|
437
|
+
const cardItem = `
|
|
438
|
+
${cardItemsHTML}
|
|
439
|
+
${cardItemStyle}
|
|
440
|
+
`
|
|
441
|
+
return cardItem;
|
|
442
|
+
}
|