@tonder.io/ionic-full-sdk 0.0.34-beta → 0.0.36-beta

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.
@@ -39,3 +39,17 @@ export type PaymentData = {
39
39
  items: OrderItem[];
40
40
  };
41
41
  };
42
+ export type TonderAPM = {
43
+ pk: string;
44
+ payment_method: string;
45
+ priority: number;
46
+ category: string;
47
+ unavailable_countries: string[];
48
+ status: string;
49
+ };
50
+ export type APM = {
51
+ id: string;
52
+ payment_method: string;
53
+ priority: number;
54
+ category: string;
55
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tonder.io/ionic-full-sdk",
3
- "version": "0.0.34-beta",
3
+ "version": "0.0.36-beta",
4
4
  "description": "Tonder ionic full SDK",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.js",
@@ -10,7 +10,7 @@
10
10
  "author": "",
11
11
  "license": "ISC",
12
12
  "dependencies": {
13
- "@tonder.io/ionic-lite-sdk": "^0.0.33-beta",
13
+ "@tonder.io/ionic-lite-sdk": "^0.0.34-beta",
14
14
  "crypto-js": "^4.1.1",
15
15
  "skyflow-js": "^1.34.1"
16
16
  },
@@ -65,19 +65,6 @@ export class ThreeDSHandler {
65
65
  }
66
66
  }
67
67
 
68
- saveCheckoutId(checkoutId: any) {
69
- localStorage.setItem('checkout_id', JSON.stringify(checkoutId))
70
- }
71
-
72
- removeCheckoutId() {
73
- localStorage.removeItem("checkout_id")
74
- }
75
-
76
- getCurrentCheckoutId() {
77
- const checkout_id = localStorage.getItem("checkout_id")
78
- return checkout_id ? JSON.parse(checkout_id):null; // TODO: JSON.parse de una string?
79
- }
80
-
81
68
  getUrlWithExpiration() {
82
69
  const status = this.getStorageItem();
83
70
  if(status) {
@@ -1,4 +1,4 @@
1
- import { Card, cardItemsTemplate, cardTemplate, CollectorIds } from '../helpers/template'
1
+ import { apmItemsTemplate, Card, cardItemsTemplate, cardTemplate, CollectorIds } from '../helpers/template'
2
2
  import { LiteCheckout } from '@tonder.io/ionic-lite-sdk';
3
3
  import {
4
4
  showError,
@@ -13,6 +13,7 @@ import { Business, Customer, PaymentData, OrderItem } from '@tonder.io/ionic-lit
13
13
  import { CustomerRegisterResponse, StartCheckoutResponse } from '@tonder.io/ionic-lite-sdk/dist/types/responses';
14
14
  import { StartCheckoutRequest, CreatePaymentRequest, CreateOrderRequest } from '@tonder.io/ionic-lite-sdk/dist/types/requests';
15
15
  import { InCollectorContainer } from '../helpers/skyflow';
16
+ import { APM } from '@tonder.io/ionic-lite-sdk/dist/types/commons';
16
17
 
17
18
  export type InlineCheckoutConstructor = {
18
19
  returnUrl: string,
@@ -25,7 +26,8 @@ export type InlineCheckoutConstructor = {
25
26
  containerId?: string,
26
27
  collectorIds?: CollectorIds,
27
28
  isOpenPaySandbox?: boolean,
28
- isEnrollmentCard?: boolean
29
+ isEnrollmentCard?: boolean,
30
+ mode?: 'production' | 'stage' | 'sandbox' | 'development',
29
31
  }
30
32
 
31
33
  export class InlineCheckout {
@@ -59,6 +61,8 @@ export class InlineCheckout {
59
61
  containerId: string
60
62
  injected: boolean
61
63
  cardsInjected: boolean
64
+ apmsInjected = false
65
+ apmsData: APM[] = []
62
66
  collectorIds: CollectorIds
63
67
  platforms?: string[]
64
68
  liteCheckout: LiteCheckout
@@ -70,6 +74,7 @@ export class InlineCheckout {
70
74
  card = {}
71
75
  currency: string = ""
72
76
  isEnrollmentCard: boolean = false
77
+ mode: 'production' | 'stage' | 'sandbox' | 'development' = "stage"
73
78
 
74
79
  constructor ({
75
80
  apiKey,
@@ -83,7 +88,9 @@ export class InlineCheckout {
83
88
  isOpenPaySandbox,
84
89
  isEnrollmentCard,
85
90
  renderSaveCardButton,
91
+ mode = 'stage',
86
92
  }: InlineCheckoutConstructor) {
93
+ this.mode = mode
87
94
  this.apiKeyTonder = apiKey;
88
95
  this.returnUrl = returnUrl;
89
96
  this.successUrl = successUrl;
@@ -91,7 +98,7 @@ export class InlineCheckout {
91
98
  this.renderSaveCardButton = renderSaveCardButton;
92
99
  this.callBack = callBack;
93
100
  this.customStyles = styles
94
-
101
+ this.baseUrl = this.#getBaseUrl()
95
102
  this.abortController = new AbortController()
96
103
 
97
104
  this.liteCheckout = new LiteCheckout({
@@ -118,7 +125,8 @@ export class InlineCheckout {
118
125
  tonderPayButton: "tonderPayButton",
119
126
  msgError: "msgError",
120
127
  msgNotification: "msgNotification",
121
- tonderSaveCardButton: "tonderSaveCardButton"
128
+ tonderSaveCardButton: "tonderSaveCardButton",
129
+ apmsListContainer: "apmsListContainer"
122
130
  }
123
131
  this.clientCards = []
124
132
  this.radioChecked = "new"
@@ -130,6 +138,17 @@ export class InlineCheckout {
130
138
  this.isEnrollmentCard = isEnrollmentCard === undefined ? false : isEnrollmentCard
131
139
  }
132
140
 
141
+ #getBaseUrl() {
142
+ const modeUrls = {
143
+ 'production': 'https://app.tonder.io',
144
+ 'sandbox': 'https://sandbox.tonder.io',
145
+ 'stage': 'https://stage.tonder.io',
146
+ 'development': 'http://localhost:8000',
147
+ };
148
+
149
+ return modeUrls[this.mode] || modeUrls['stage']
150
+ }
151
+
133
152
  #mountPayButton() {
134
153
  if (!this.renderPaymentButton) return;
135
154
 
@@ -251,7 +270,6 @@ export class InlineCheckout {
251
270
  this.#handleCard(data)
252
271
  const response: ErrorResponse | StartCheckoutResponse | false | undefined = await this.#checkout()
253
272
  this.process3ds.setPayload(response)
254
- this.process3ds.saveCheckoutId(response && 'checkout_id' in response ? response.checkout_id:"")
255
273
  this.callBack(response);
256
274
  const payload = await this.handle3dsRedirect(response)
257
275
  if (payload) {
@@ -263,7 +281,7 @@ export class InlineCheckout {
263
281
  });
264
282
  }
265
283
 
266
- #mountRadioButtons (token: string) {
284
+ #mountRadioButtons (token: string = "") {
267
285
  const radioButtons: NodeListOf<HTMLElement> = document.getElementsByName(`card_selected`);
268
286
  for (const radio of radioButtons) {
269
287
  radio.style.display = "block";
@@ -361,7 +379,7 @@ export class InlineCheckout {
361
379
  const injectInterval = setInterval(() => {
362
380
  const queryElement = document.querySelector(`#${this.containerId}`)
363
381
  if (queryElement) {
364
- queryElement.innerHTML = cardTemplate(this.customStyles ? true : false, this.collectorIds, this.isEnrollmentCard)
382
+ queryElement.innerHTML = cardTemplate(this.customStyles ? true : false, this.collectorIds, this.isEnrollmentCard, { renderPaymentButton: this.renderPaymentButton })
365
383
  this.#mountTonder();
366
384
  clearInterval(injectInterval);
367
385
  this.injected = true
@@ -382,8 +400,7 @@ export class InlineCheckout {
382
400
  async resumeCheckout(response: any) {
383
401
  if (["Failed", "Declined", "Cancelled"].includes(response?.status)) {
384
402
  const routerItems = {
385
- // TODO: Replace this with reponse.checkout_id
386
- checkout_id: this.process3ds.getCurrentCheckoutId(),
403
+ checkout_id: response.checkout?.id,
387
404
  };
388
405
  const routerResponse = await this.liteCheckout.handleCheckoutRouter(
389
406
  routerItems
@@ -415,6 +432,31 @@ export class InlineCheckout {
415
432
  return await this.liteCheckout.customerRegister(email);
416
433
  }
417
434
 
435
+ async #mountAPMs(){
436
+ try{
437
+ const apms: APM[] = await this.liteCheckout.getActiveAPMs();
438
+ if(apms.length > 0){
439
+ this.apmsData = apms;
440
+ this.#loadAPMList(apms)
441
+ }
442
+ }catch(e){
443
+ console.warn("Error getting APMS")
444
+ }
445
+ }
446
+
447
+ #loadAPMList(apms: APM[]) {
448
+ if (this.apmsInjected) return;
449
+ const injectInterval = setInterval(() => {
450
+ const queryElement = document.querySelector(`#${this.collectorIds.apmsListContainer}`);
451
+ if (queryElement && this.injected) {
452
+ queryElement.innerHTML = apmItemsTemplate(this.customStyles ? true : false, apms);
453
+ clearInterval(injectInterval);
454
+ this.#mountRadioButtons();
455
+ this.apmsInjected = true;
456
+ }
457
+ }, 500);
458
+ }
459
+
418
460
  async #mountTonder() {
419
461
  if(this.isEnrollmentCard){
420
462
  this.#mountSaveCardButton()
@@ -449,6 +491,7 @@ export class InlineCheckout {
449
491
  }
450
492
 
451
493
  }
494
+ await this.#mountAPMs();
452
495
 
453
496
  this.collectContainer = await initSkyflow(
454
497
  vault_id,
@@ -468,6 +511,7 @@ export class InlineCheckout {
468
511
 
469
512
  this.injected = false
470
513
  this.cardsInjected = false
514
+ this.apmsInjected = false
471
515
  // Cancel all requests
472
516
  this.abortController.abort();
473
517
  this.abortController = new AbortController();
@@ -548,7 +592,6 @@ export class InlineCheckout {
548
592
 
549
593
  if("auth_token" in customerResponse) {
550
594
  const { auth_token, id: cutomerId } = customerResponse;
551
- console.log("cardTokensSkyflowTonder: ", cardTokensSkyflowTonder)
552
595
  await this.liteCheckout.registerCustomerCard(auth_token, { skyflow_id: cardTokensSkyflowTonder.skyflow_id });
553
596
  showMessage("Tarjeta registrada con éxito", this.collectorIds.msgNotification);
554
597
  }
@@ -697,10 +740,11 @@ export class InlineCheckout {
697
740
  const jsonResponsePayment = await this.liteCheckout.createPayment(
698
741
  paymentItems
699
742
  );
700
-
743
+
744
+ const selected_apm: APM | undefined | null = this.apmsData ? this.apmsData.find((iapm) => iapm.id === this.radioChecked):null;
745
+
701
746
  // Checkout router
702
747
  const routerItems: StartCheckoutRequest = {
703
- card: cardTokensSkyflowTonder,
704
748
  name: this.firstName,
705
749
  last_name: this.lastName ?? "",
706
750
  email_client: this.email,
@@ -721,7 +765,11 @@ export class InlineCheckout {
721
765
  source: 'sdk',
722
766
  metadata: this.metadata,
723
767
  browser_info: getBrowserInfo(),
724
- currency: this.currency
768
+ currency: this.currency,
769
+ ...( !!selected_apm
770
+ ? {payment_method: selected_apm.payment_method}
771
+ : {card: cardTokensSkyflowTonder}
772
+ )
725
773
  };
726
774
 
727
775
  const jsonResponseRouter = await this.liteCheckout.handleCheckoutRouter(
@@ -0,0 +1,64 @@
1
+ enum PAYMENT_METHOD {
2
+ SORIANA = "SORIANA",
3
+ OXXO = "OXXO",
4
+ SPEI= "SPEI",
5
+ CODI= "CODI",
6
+ MERCADOPAGO= "MERCADOPAGO",
7
+ PAYPAL= "PAYPAL",
8
+ COMERCIALMEXICANA= "COMERCIALMEXICANA",
9
+ BANCOMER= "BANCOMER",
10
+ WALMART= "WALMART",
11
+ BODEGA= "BODEGA",
12
+ SAMSCLUB= "SAMSCLUB",
13
+ SUPERAMA= "SUPERAMA",
14
+ CALIMAX= "CALIMAX",
15
+ EXTRA= "EXTRA",
16
+ CIRCULOK= "CIRCULOK",
17
+ SEVEN11= "7ELEVEN",
18
+ TELECOMM= "TELECOMM",
19
+ BANORTE= "BANORTE",
20
+ BENAVIDES= "BENAVIDES",
21
+ DELAHORRO= "DELAHORRO",
22
+ ELASTURIANO= "ELASTURIANO",
23
+ WALDOS= "WALDOS",
24
+ ALSUPER= "ALSUPER",
25
+ KIOSKO= "KIOSKO",
26
+ STAMARIA= "STAMARIA",
27
+ LAMASBARATA= "LAMASBARATA",
28
+ FARMROMA= "FARMROMA",
29
+ FARMUNION= "FARMUNION",
30
+ FARMATODO= "FARMATODO",
31
+ SFDEASIS= "SFDEASIS",
32
+ FARM911= "FARM911",
33
+ FARMECONOMICAS= "FARMECONOMICAS",
34
+ FARMMEDICITY= "FARMMEDICITY",
35
+ RIANXEIRA= "RIANXEIRA",
36
+ WESTERNUNION= "WESTERNUNION",
37
+ ZONAPAGO= "ZONAPAGO",
38
+ CAJALOSANDES= "CAJALOSANDES",
39
+ CAJAPAITA= "CAJAPAITA",
40
+ CAJASANTA= "CAJASANTA",
41
+ CAJASULLANA= "CAJASULLANA",
42
+ CAJATRUJILLO= "CAJATRUJILLO",
43
+ EDPYME= "EDPYME",
44
+ KASNET= "KASNET",
45
+ NORANDINO= "NORANDINO",
46
+ QAPAQ= "QAPAQ",
47
+ RAIZ= "RAIZ",
48
+ PAYSER= "PAYSER",
49
+ WUNION= "WUNION",
50
+ BANCOCONTINENTAL= "BANCOCONTINENTAL",
51
+ GMONEY= "GMONEY",
52
+ GOPAY= "GOPAY",
53
+ WU= "WU",
54
+ PUNTOSHEY= "PUNTOSHEY",
55
+ AMPM= "AMPM",
56
+ JUMBOMARKET= "JUMBOMARKET",
57
+ SMELPUEBLO= "SMELPUEBLO",
58
+ BAM= "BAM",
59
+ REFACIL= "REFACIL",
60
+ ACYVALORES= "ACYVALORES"
61
+ }
62
+
63
+ export { PAYMENT_METHOD }
64
+
@@ -1,4 +1,5 @@
1
- import { getCardType } from './utils';
1
+ import { APM } from '@tonder.io/ionic-lite-sdk/dist/types/commons';
2
+ import { getCardType, getPaymentMethodDetails } from './utils';
2
3
 
3
4
  export type CollectorIds = {
4
5
  holderName: string,
@@ -10,7 +11,8 @@ export type CollectorIds = {
10
11
  tonderSaveCardButton?: string,
11
12
  msgError: string,
12
13
  msgNotification: string,
13
- cardsListContainer: string
14
+ cardsListContainer: string,
15
+ apmsListContainer?: string
14
16
  }
15
17
 
16
18
  export type Card = {
@@ -22,7 +24,7 @@ export type Card = {
22
24
  skyflow_id: string
23
25
  }
24
26
 
25
- export const cardTemplate = (external: boolean, collectorIds: CollectorIds, isEnrollmentCard: boolean = false) => `
27
+ export const cardTemplate = (external: boolean, collectorIds: CollectorIds, isEnrollmentCard: boolean = false, data: {renderPaymentButton?: boolean} = {}) => `
26
28
  <div class="container-tonder">
27
29
  <div id="${collectorIds.cardsListContainer}" class="cards-list-container"></div>
28
30
  ${!isEnrollmentCard ? `
@@ -53,8 +55,11 @@ export const cardTemplate = (external: boolean, collectorIds: CollectorIds, isEn
53
55
  <div id="${collectorIds.msgError}"></div>
54
56
  <div id="${collectorIds.msgNotification}"></div>
55
57
  </div>
56
- <button id="${collectorIds.tonderPayButton}" class="pay-button">Pagar</button>
57
- <button id="${collectorIds.tonderSaveCardButton ? collectorIds.tonderSaveCardButton:''}" class="save-card-button">Guardar</button>
58
+ <div id="apmsListContainer" class="apms-list-container"></div>
59
+ <div class="container-pay-button">
60
+ <button id="${collectorIds.tonderPayButton}" class="pay-button">Pagar</button>
61
+ <button id="${collectorIds.tonderSaveCardButton ? collectorIds.tonderSaveCardButton:''}" class="save-card-button">Guardar</button>
62
+ </div>
58
63
  </div>
59
64
 
60
65
  ${external ? `` : `<style>
@@ -72,6 +77,10 @@ ${external ? `` : `<style>
72
77
  font-family: "Inter", sans-serif !important;
73
78
  }
74
79
 
80
+ .container-form {
81
+ padding: 25px 21px 0px 21px;
82
+ }
83
+
75
84
  .expiration-year .error-custom-inputs-tonder {
76
85
  background-color: white;
77
86
  position: absolute;
@@ -86,13 +95,17 @@ ${external ? `` : `<style>
86
95
  .container-tonder {
87
96
  background-color: #F9F9F9;
88
97
  margin: 0 auto !important;
89
- padding: 30px 10px 30px 10px;
98
+ padding: 30px 0px 30px 0px;
90
99
  overflow: hidden;
91
100
  transition: max-height 0.5s ease-out;
92
101
  max-width: 600px;
93
102
  border: solid 1px #e3e3e3;
94
103
  }
95
104
 
105
+ .container-pay-button{
106
+ padding: ${!!data['renderPaymentButton'] ? '30px 30px':''};
107
+ }
108
+
96
109
  .collect-row {
97
110
  display: flex !important;
98
111
  justify-content: space-between !important;
@@ -220,10 +233,18 @@ ${external ? `` : `<style>
220
233
  .cards-list-container {
221
234
  display: flex;
222
235
  flex-direction: column;
223
- padding: 0px 10px 0px 10px;
236
+ padding: 0px;
224
237
  gap: 33% 20px;
225
238
  }
226
239
 
240
+ .apms-list-container {
241
+ display: flex;
242
+ flex-direction: column;
243
+ gap: 33% 20px;
244
+ max-height: 300px;
245
+ overflow-y: auto;
246
+ }
247
+
227
248
  .checkbox label {
228
249
  margin-left: 10px;
229
250
  font-size: '12px';
@@ -235,6 +256,8 @@ ${external ? `` : `<style>
235
256
  .checkbox {
236
257
  margin-top: 10px;
237
258
  margin-bottom: 20px;
259
+ margin-left: 10px !important;
260
+ margin-right: 10px !important;
238
261
  width: 100%;
239
262
  text-align: left;
240
263
  }
@@ -244,12 +267,12 @@ ${external ? `` : `<style>
244
267
  justify-content: start;
245
268
  align-items: center;
246
269
  color: #1D1D1D;
247
- gap: 33% 20px;
270
+ gap: 33% 15px;
248
271
  margin-top: 10px;
249
272
  margin-bottom: 10px;
250
- padding-left: 10px;
251
- padding-right: 10px;
252
- width: 90%;
273
+ padding: 0px 30px;
274
+ width: 100%;
275
+ position: relative;
253
276
  }
254
277
 
255
278
  .pay-new-card .card-number {
@@ -271,9 +294,7 @@ ${external ? `` : `<style>
271
294
  gap: 33% 20px;
272
295
  margin-top: 10px;
273
296
  margin-bottom: 10px;
274
- padding-left: 10px;
275
- padding-right: 10px;
276
- width: 90%;
297
+ width: 100%;
277
298
  }
278
299
 
279
300
  .card_selected {
@@ -391,18 +412,19 @@ export const cardItemsTemplate = (external: boolean, cards: Card[]) => {
391
412
  align-items: center;
392
413
  color: #1D1D1D;
393
414
  gap: 33% 20px;
394
- margin-top: 10px;
395
- margin-bottom: 10px;
396
- padding-left: 10px;
397
- padding-right: 10px;
398
- width: 90%;
415
+ margin-top: 15px;
416
+ margin-bottom: 15px;
417
+ width: 100%;
399
418
  }
400
419
 
401
420
  .card-item {
421
+ position: relative;
402
422
  display: flex;
403
423
  justify-content: start;
404
424
  align-items: center;
405
- gap: 33% 20px;
425
+ gap: 33% 15px;
426
+ border-bottom: 1px solid #e2e8f0;
427
+ padding: 0px 30px;
406
428
  }
407
429
 
408
430
  .card-item .card-number {
@@ -518,4 +540,165 @@ export const cardItemsTemplate = (external: boolean, cards: Card[]) => {
518
540
  ${cardItemStyle}
519
541
  `
520
542
  return cardItem;
543
+ }
544
+
545
+ export const apmItemsTemplate = (external: boolean, apms: APM[]) => {
546
+ console.log("apms here****: ", apms)
547
+ const apmItemsHTML = apms.reduce((total, apm) => {
548
+ const apm_data = getPaymentMethodDetails(apm.payment_method);
549
+ return `
550
+ ${total}
551
+ <div class="apm-item" id="card_container-${apm.id}">
552
+ <input id="${apm.id}" class="card_selected" name="card_selected" type="radio"/>
553
+ <label class="apm-item-label" for="${apm.id}">
554
+ <div class="apm-image">
555
+ <div class="apm-image-border"></div>
556
+ <img src="${apm_data.icon}" />
557
+ </div>
558
+ <div class="apm-name">${apm_data.label}</div>
559
+ </label>
560
+ </div>`
561
+ }, ``);
562
+
563
+ const apmItemStyle = external ? '' :`
564
+ <style>
565
+ .apm-item-label {
566
+ display: flex;
567
+ justify-content: flex-start;
568
+ align-items: center;
569
+ color: #1D1D1D;
570
+ gap: 33% 10px;
571
+ margin-top: 15px;
572
+ margin-bottom: 15px;
573
+ width: 100%;
574
+ }
575
+
576
+ .apm-item {
577
+ position: relative;
578
+ display: flex;
579
+ justify-content: start;
580
+ align-items: center;
581
+ gap: 33% 15px;
582
+ border-bottom: 1px solid #e2e8f0;
583
+ padding: 0px 30px;
584
+ }
585
+
586
+ .apm-item:first-child {
587
+ border-top: 1px solid #e2e8f0;
588
+ }
589
+
590
+ .apm-item .apm-name {
591
+ font-size: 16px;
592
+ }
593
+ .apm-image {
594
+ width: 30px;
595
+ height: 30px;
596
+ position: relative;
597
+ display: flex;
598
+ justify-content: center;
599
+ align-items: center;
600
+ }
601
+ .apm-image img {
602
+ width: auto;
603
+ height: 30px;
604
+ }
605
+ .apm-image-border{
606
+ position: absolute;
607
+ border: 1px solid #bababa36;
608
+ border-radius: 4px;
609
+ pointer-events: none;
610
+ box-sizing: border-box;
611
+ width: 100%;
612
+ height: 97%;
613
+ }
614
+
615
+ .card_selected {
616
+ position: relative;
617
+ width: 16px;
618
+ min-width: 16px;
619
+ height: 16px;
620
+ appearance: none;
621
+ cursor: pointer;
622
+ border-radius: 100%;
623
+ border: 1px #bababa solid;
624
+ color: #3bc635;
625
+ transition-property: all;
626
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
627
+ transition-duration: 150ms;
628
+ }
629
+
630
+ .card_selected:before {
631
+ width: 8px;
632
+ height: 8px;
633
+ content: "";
634
+ position: absolute;
635
+ top: 50%;
636
+ left: 50%;
637
+ display: block;
638
+ transform: translate(-50%, -50%);
639
+ border-radius: 100%;
640
+ background-color: #3bc635;
641
+ opacity: 0;
642
+ transition-property: opacity;
643
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
644
+ transition-duration: 150ms;
645
+ }
646
+
647
+ .card_selected:checked {
648
+ border: 1px #3bc635 solid;
649
+ position: relative;
650
+ width: 16px;
651
+ height: 16px;
652
+ min-width: 16px;
653
+ appearance: none;
654
+ cursor: pointer;
655
+ border-radius: 100%;
656
+ color: #3bc635;
657
+ transition-property: all;
658
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
659
+ transition-duration: 150ms;
660
+ }
661
+
662
+ .card_selected:checked:before {
663
+ content: "";
664
+ border: 1px #3bc635 solid;
665
+ width: 8px;
666
+ height: 8px;
667
+ position: absolute;
668
+ top: 50%;
669
+ left: 50%;
670
+ display: block;
671
+ transform: translate(-50%, -50%);
672
+ border-radius: 100%;
673
+ background-color: #3bc635;
674
+ opacity: 50;
675
+ transition-property: opacity;
676
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
677
+ transition-duration: 150ms;
678
+ }
679
+
680
+ .card_selected:hover:before {
681
+ width: 8px;
682
+ height: 8px;
683
+ content: "";
684
+ position: absolute;
685
+ top: 50%;
686
+ left: 50%;
687
+ display: block;
688
+ transform: translate(-50%, -50%);
689
+ border-radius: 100%;
690
+ background-color: #3bc635;
691
+ transition-property: opacity;
692
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
693
+ transition-duration: 150ms;
694
+ opacity: 10;
695
+ }
696
+
697
+ </style>
698
+ `
699
+ const apmItem = `
700
+ ${apmItemsHTML}
701
+ ${apmItemStyle}
702
+ `
703
+ return apmItem;
521
704
  }