tonder-web-sdk 1.16.1 → 1.16.6-beta.DEV-1433.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 +134 -40
- package/package.json +29 -6
- package/types/card.d.ts +17 -17
- package/types/checkout.d.ts +85 -87
- package/types/common.d.ts +8 -2
- package/types/customer.d.ts +10 -10
- package/types/index.d.ts +9 -11
- package/types/inlineCheckout.d.ts +81 -61
- package/types/liteInlineCheckout.d.ts +78 -83
- package/types/paymentMethod.d.ts +17 -17
- package/types/transaction.d.ts +94 -94
- package/v1/bundle.min.js +1 -18
- package/.env-example +0 -1
- package/cypress/e2e/1-getting-started/todo.cy.js +0 -143
- package/cypress/e2e/2-advanced-examples/actions.cy.js +0 -299
- package/cypress/e2e/2-advanced-examples/aliasing.cy.js +0 -39
- package/cypress/e2e/2-advanced-examples/assertions.cy.js +0 -176
- package/cypress/e2e/2-advanced-examples/connectors.cy.js +0 -98
- package/cypress/e2e/2-advanced-examples/cookies.cy.js +0 -118
- package/cypress/e2e/2-advanced-examples/cypress_api.cy.js +0 -185
- package/cypress/e2e/2-advanced-examples/files.cy.js +0 -85
- package/cypress/e2e/2-advanced-examples/location.cy.js +0 -32
- package/cypress/e2e/2-advanced-examples/misc.cy.js +0 -104
- package/cypress/e2e/2-advanced-examples/navigation.cy.js +0 -56
- package/cypress/e2e/2-advanced-examples/network_requests.cy.js +0 -163
- package/cypress/e2e/2-advanced-examples/querying.cy.js +0 -114
- package/cypress/e2e/2-advanced-examples/spies_stubs_clocks.cy.js +0 -201
- package/cypress/e2e/2-advanced-examples/storage.cy.js +0 -110
- package/cypress/e2e/2-advanced-examples/traversal.cy.js +0 -121
- package/cypress/e2e/2-advanced-examples/utilities.cy.js +0 -108
- package/cypress/e2e/2-advanced-examples/viewport.cy.js +0 -58
- package/cypress/e2e/2-advanced-examples/waiting.cy.js +0 -30
- package/cypress/e2e/2-advanced-examples/window.cy.js +0 -22
- package/cypress/fixtures/example.json +0 -5
- package/cypress/support/commands.js +0 -25
- package/cypress/support/e2e.js +0 -20
- package/cypress.config.js +0 -9
- package/index.js.example +0 -50
- package/samples/react/README.md +0 -70
- package/samples/react/build/asset-manifest.json +0 -16
- package/samples/react/build/favicon.ico +0 -0
- package/samples/react/build/index.html +0 -1
- package/samples/react/build/logo192.png +0 -0
- package/samples/react/build/logo512.png +0 -0
- package/samples/react/build/manifest.json +0 -25
- package/samples/react/build/robots.txt +0 -3
- package/samples/react/build/static/css/main.073c9b0a.css +0 -2
- package/samples/react/build/static/css/main.073c9b0a.css.map +0 -1
- package/samples/react/build/static/js/787.b83ed06f.chunk.js +0 -2
- package/samples/react/build/static/js/787.b83ed06f.chunk.js.map +0 -1
- package/samples/react/build/static/js/main.0a848807.js +0 -3
- package/samples/react/build/static/js/main.0a848807.js.LICENSE.txt +0 -39
- package/samples/react/build/static/js/main.0a848807.js.map +0 -1
- package/samples/react/build/static/media/sdk-icons.b491623214b2af4cccdb.png +0 -0
- package/samples/react/package-lock.json +0 -28973
- package/samples/react/package.json +0 -44
- package/samples/react/public/favicon.ico +0 -0
- package/samples/react/public/index.html +0 -43
- package/samples/react/public/logo192.png +0 -0
- package/samples/react/public/logo512.png +0 -0
- package/samples/react/public/manifest.json +0 -25
- package/samples/react/public/robots.txt +0 -3
- package/samples/react/src/App.css +0 -38
- package/samples/react/src/App.js +0 -22
- package/samples/react/src/App.test.js +0 -8
- package/samples/react/src/assets/img/sdk-icons.png +0 -0
- package/samples/react/src/components/Cart.js +0 -29
- package/samples/react/src/components/ProductCard.js +0 -27
- package/samples/react/src/context/CartContext.js +0 -116
- package/samples/react/src/index.css +0 -13
- package/samples/react/src/index.js +0 -17
- package/samples/react/src/logo.svg +0 -1
- package/samples/react/src/reportWebVitals.js +0 -13
- package/samples/react/src/screens/Checkout.js +0 -82
- package/samples/react/src/screens/Store.js +0 -21
- package/samples/react/src/setupTests.js +0 -5
- package/samples/react/src/storeProducts.js +0 -30
- package/src/classes/3dsHandler.js +0 -203
- package/src/classes/BaseInlineCheckout.js +0 -324
- package/src/classes/LiteInlineCheckout.js +0 -220
- package/src/classes/checkout.js +0 -125
- package/src/classes/globalLoader.js +0 -29
- package/src/classes/inlineCheckout.js +0 -515
- package/src/data/apmApi.js +0 -44
- package/src/data/businessApi.js +0 -19
- package/src/data/cardApi.js +0 -143
- package/src/data/checkoutApi.js +0 -92
- package/src/data/customerApi.js +0 -37
- package/src/data/index.js +0 -17
- package/src/data/openPayApi.js +0 -16
- package/src/data/skyflowApi.js +0 -18
- package/src/helpers/skyflow.js +0 -361
- package/src/helpers/styles.js +0 -61
- package/src/helpers/template-skeleton.js +0 -59
- package/src/helpers/template.js +0 -743
- package/src/helpers/utils.js +0 -163
- package/src/helpers/validations.js +0 -54
- package/src/index-dev.js +0 -307
- package/src/index.html +0 -172
- package/src/index.js +0 -15
- package/src/shared/catalog/paymentMethodsCatalog.js +0 -247
- package/src/shared/constants/messages.js +0 -10
- package/src/shared/constants/paymentMethodAPM.js +0 -63
- package/src/shared/constants/tonderUrl.js +0 -8
- package/webpack.config.js +0 -77
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
import { BaseInlineCheckout } from "./BaseInlineCheckout";
|
|
2
|
-
import {
|
|
3
|
-
fetchCustomerAPMs,
|
|
4
|
-
fetchCustomerCards,
|
|
5
|
-
saveCustomerCard,
|
|
6
|
-
removeCustomerCard,
|
|
7
|
-
registerOrFetchCustomer,
|
|
8
|
-
} from "../data";
|
|
9
|
-
import { getSkyflowTokens } from "../helpers/skyflow";
|
|
10
|
-
import { getPaymentMethodDetails } from "../shared/catalog/paymentMethodsCatalog";
|
|
11
|
-
import { formatPublicErrorResponse, getCardType } from "../helpers/utils";
|
|
12
|
-
import { MESSAGES } from "../shared/constants/messages";
|
|
13
|
-
|
|
14
|
-
export class LiteInlineCheckout extends BaseInlineCheckout {
|
|
15
|
-
#customerData;
|
|
16
|
-
constructor({ mode = "stage", apiKey, returnUrl, callBack = () => {} }) {
|
|
17
|
-
super({ mode, apiKey, returnUrl, callBack });
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Initializes and prepares the checkout for use.
|
|
22
|
-
* This method set up the initial environment.
|
|
23
|
-
* @returns {Promise<void>} A promise that resolves when the checkout has been initialized.
|
|
24
|
-
* @throws {Error} If there's any problem during the checkout initialization.
|
|
25
|
-
* @public
|
|
26
|
-
*/
|
|
27
|
-
async injectCheckout() {
|
|
28
|
-
await this._initializeCheckout();
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Retrieves the list of cards associated with a customer.
|
|
33
|
-
* @returns {Promise<import("../../types").ICustomerCardsResponse>} A promise that resolves with the customer's card data.
|
|
34
|
-
*
|
|
35
|
-
* @throws {import("../../types").IPublicError} Throws an error object if the operation fails.
|
|
36
|
-
*
|
|
37
|
-
* @public
|
|
38
|
-
*/
|
|
39
|
-
async getCustomerCards() {
|
|
40
|
-
try {
|
|
41
|
-
const { auth_token } = await this.#getCustomer();
|
|
42
|
-
const response = await fetchCustomerCards(
|
|
43
|
-
this.baseUrl,
|
|
44
|
-
auth_token,
|
|
45
|
-
this.secureToken,
|
|
46
|
-
this.merchantData.business.pk,
|
|
47
|
-
);
|
|
48
|
-
return {
|
|
49
|
-
...response,
|
|
50
|
-
cards: response.cards.map((ic) => ({
|
|
51
|
-
...ic,
|
|
52
|
-
icon: getCardType(ic.fields.card_scheme),
|
|
53
|
-
})),
|
|
54
|
-
};
|
|
55
|
-
} catch (error) {
|
|
56
|
-
throw formatPublicErrorResponse(
|
|
57
|
-
{
|
|
58
|
-
message: MESSAGES.getCardsError,
|
|
59
|
-
},
|
|
60
|
-
error,
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Saves a card to a customer's account. This method can be used to add a new card
|
|
67
|
-
* or update an existing one.
|
|
68
|
-
* @param {import("../../types").ISaveCardRequest} card - The card information to be saved.
|
|
69
|
-
* @returns {Promise<import("../../types").ISaveCardResponse>} A promise that resolves with the saved card data.
|
|
70
|
-
*
|
|
71
|
-
* @throws {import("../../types").IPublicError} Throws an error object if the operation fails.
|
|
72
|
-
*
|
|
73
|
-
* @public
|
|
74
|
-
*/
|
|
75
|
-
async saveCustomerCard(card) {
|
|
76
|
-
try {
|
|
77
|
-
const { auth_token } = await this.#getCustomer();
|
|
78
|
-
const { vault_id, vault_url, business } = this.merchantData;
|
|
79
|
-
|
|
80
|
-
const skyflowTokens = await getSkyflowTokens({
|
|
81
|
-
vault_id: vault_id,
|
|
82
|
-
vault_url: vault_url,
|
|
83
|
-
data: card,
|
|
84
|
-
baseUrl: this.baseUrl,
|
|
85
|
-
apiKey: this.apiKeyTonder,
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
return await saveCustomerCard(
|
|
89
|
-
this.baseUrl,
|
|
90
|
-
auth_token,
|
|
91
|
-
this.secureToken,
|
|
92
|
-
business?.pk,
|
|
93
|
-
skyflowTokens,
|
|
94
|
-
);
|
|
95
|
-
} catch (error) {
|
|
96
|
-
throw formatPublicErrorResponse(
|
|
97
|
-
{
|
|
98
|
-
message: MESSAGES.saveCardError,
|
|
99
|
-
},
|
|
100
|
-
error,
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Removes a card from a customer's account.
|
|
107
|
-
* @param {string} skyflowId - The unique identifier of the card to be deleted.
|
|
108
|
-
* @returns {Promise<string>} A promise that resolves when the card is successfully deleted.
|
|
109
|
-
*
|
|
110
|
-
* @throws {import("../../types").IPublicError} Throws an error object if the operation fails.
|
|
111
|
-
*
|
|
112
|
-
* @public
|
|
113
|
-
*/
|
|
114
|
-
async removeCustomerCard(skyflowId) {
|
|
115
|
-
try {
|
|
116
|
-
const { auth_token } = await this.#getCustomer();
|
|
117
|
-
const { business } = this.merchantData;
|
|
118
|
-
|
|
119
|
-
return await removeCustomerCard(
|
|
120
|
-
this.baseUrl,
|
|
121
|
-
auth_token,
|
|
122
|
-
this.secureToken,
|
|
123
|
-
skyflowId,
|
|
124
|
-
business?.pk,
|
|
125
|
-
);
|
|
126
|
-
} catch (error) {
|
|
127
|
-
throw formatPublicErrorResponse(
|
|
128
|
-
{
|
|
129
|
-
message: MESSAGES.removeCardError,
|
|
130
|
-
},
|
|
131
|
-
error,
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Retrieves the list of available Alternative Payment Methods (APMs).
|
|
138
|
-
* @returns {Promise<import("../../types").IPaymentMethod[]>} A promise that resolves with the list of APMs.
|
|
139
|
-
*
|
|
140
|
-
* @throws {import("../../types").IPublicError} Throws an error object if the operation fails.
|
|
141
|
-
*
|
|
142
|
-
* @public
|
|
143
|
-
*/
|
|
144
|
-
async getCustomerPaymentMethods() {
|
|
145
|
-
try {
|
|
146
|
-
const response = await fetchCustomerAPMs(this.baseUrl, this.apiKeyTonder);
|
|
147
|
-
|
|
148
|
-
const apms_results =
|
|
149
|
-
response && "results" in response && response["results"].length > 0
|
|
150
|
-
? response["results"]
|
|
151
|
-
: [];
|
|
152
|
-
|
|
153
|
-
return apms_results
|
|
154
|
-
.filter((apmItem) => apmItem.category.toLowerCase() !== "cards")
|
|
155
|
-
.map((apmItem) => {
|
|
156
|
-
const apm = {
|
|
157
|
-
id: apmItem.pk,
|
|
158
|
-
payment_method: apmItem.payment_method,
|
|
159
|
-
priority: apmItem.priority,
|
|
160
|
-
category: apmItem.category,
|
|
161
|
-
...getPaymentMethodDetails(apmItem.payment_method),
|
|
162
|
-
};
|
|
163
|
-
return apm;
|
|
164
|
-
})
|
|
165
|
-
.sort((a, b) => a.priority - b.priority);
|
|
166
|
-
} catch (error) {
|
|
167
|
-
throw formatPublicErrorResponse(
|
|
168
|
-
{
|
|
169
|
-
message: MESSAGES.getPaymentMethodsError,
|
|
170
|
-
},
|
|
171
|
-
error,
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
_setCartTotal(total) {
|
|
177
|
-
this.cartTotal = total;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
async _checkout({ card, payment_method }) {
|
|
181
|
-
const customer = await this._getCustomer(
|
|
182
|
-
this.customer,
|
|
183
|
-
this.abortController.signal,
|
|
184
|
-
);
|
|
185
|
-
const { vault_id, vault_url } = this.merchantData;
|
|
186
|
-
let skyflowTokens;
|
|
187
|
-
if (!payment_method || payment_method !== "" || payment_method === null) {
|
|
188
|
-
if (typeof card === "string") {
|
|
189
|
-
skyflowTokens = {
|
|
190
|
-
skyflow_id: card,
|
|
191
|
-
};
|
|
192
|
-
} else {
|
|
193
|
-
skyflowTokens = await getSkyflowTokens({
|
|
194
|
-
vault_id: vault_id,
|
|
195
|
-
vault_url: vault_url,
|
|
196
|
-
data: {...card, card_number: card.card_number.replace(/\s+/g, '')},
|
|
197
|
-
baseUrl: this.baseUrl,
|
|
198
|
-
apiKey: this.apiKeyTonder,
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
return await this._handleCheckout({
|
|
204
|
-
card: skyflowTokens,
|
|
205
|
-
payment_method,
|
|
206
|
-
customer,
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
async #getCustomer() {
|
|
211
|
-
if (!!this.#customerData) return this.#customerData;
|
|
212
|
-
|
|
213
|
-
this.#customerData = await registerOrFetchCustomer(
|
|
214
|
-
this.baseUrl,
|
|
215
|
-
this.apiKeyTonder,
|
|
216
|
-
this.customer,
|
|
217
|
-
);
|
|
218
|
-
return this.#customerData;
|
|
219
|
-
}
|
|
220
|
-
}
|
package/src/classes/checkout.js
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import { AES } from "crypto-js";
|
|
2
|
-
|
|
3
|
-
export class Checkout {
|
|
4
|
-
constructor({
|
|
5
|
-
apiKey,
|
|
6
|
-
type = "payment",
|
|
7
|
-
backgroundColor="#141414",
|
|
8
|
-
color="#EBEBEB",
|
|
9
|
-
cb=()=>{},
|
|
10
|
-
url="http://checkout.tonder.io/#/"
|
|
11
|
-
}) {
|
|
12
|
-
this.url = url
|
|
13
|
-
this.apiKey = apiKey
|
|
14
|
-
this.type = type
|
|
15
|
-
this.backgroundColor = backgroundColor
|
|
16
|
-
this.color = color
|
|
17
|
-
this.params = ""
|
|
18
|
-
this.order = {}
|
|
19
|
-
this.buttonText = "Proceder al pago"
|
|
20
|
-
this.cb = cb
|
|
21
|
-
|
|
22
|
-
window.addEventListener("message", this.receiveMessage.bind(this), false);
|
|
23
|
-
}
|
|
24
|
-
generateButton = (buttonText) => {
|
|
25
|
-
this.buttonText = buttonText ? buttonText : this.buttonText
|
|
26
|
-
this.tonderButton = document.createElement('button');
|
|
27
|
-
this.tonderButton.innerHTML = this.buttonText;
|
|
28
|
-
this.stylishButton(this.tonderButton)
|
|
29
|
-
this.tonderButton.onclick = this.openCheckout
|
|
30
|
-
}
|
|
31
|
-
getButton = ({buttonText}) => {
|
|
32
|
-
this.generateButton(buttonText)
|
|
33
|
-
return this.tonderButton
|
|
34
|
-
}
|
|
35
|
-
mountButton = ({buttonText}) => {
|
|
36
|
-
this.generateButton(buttonText)
|
|
37
|
-
const entryPoint = document.getElementById("tonder-checkout")
|
|
38
|
-
try {
|
|
39
|
-
entryPoint.innerHTML = ""
|
|
40
|
-
entryPoint.append(this.tonderButton)
|
|
41
|
-
} catch(error) {
|
|
42
|
-
console.error(error)
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
stylishButton = (element) => {
|
|
46
|
-
element.style.backgroundColor = this.backgroundColor
|
|
47
|
-
element.style.color = this.color
|
|
48
|
-
element.style.display = 'flex'
|
|
49
|
-
element.style.justifyContent = 'center'
|
|
50
|
-
element.style.border = 'none'
|
|
51
|
-
element.style.padding = '1rem'
|
|
52
|
-
element.style.borderRadius = '10px'
|
|
53
|
-
element.style.fontSize = '1rem'
|
|
54
|
-
element.style.width = '100%'
|
|
55
|
-
element.style.boxShadow = '0 3px 6px 0 rgba(0,0,0,0.16)'
|
|
56
|
-
}
|
|
57
|
-
setOrder = ({products, email, shippingCost }) => {
|
|
58
|
-
let _order = {}
|
|
59
|
-
if (products) _order.products = products
|
|
60
|
-
if (email) _order.email = email
|
|
61
|
-
if (shippingCost) _order.shippingCost = shippingCost
|
|
62
|
-
this.order = {...this.order, ..._order}
|
|
63
|
-
return this.order
|
|
64
|
-
}
|
|
65
|
-
openTabListener = (tab, button) => {
|
|
66
|
-
const tabInterval = setInterval(() => {
|
|
67
|
-
if (tab.closed) {
|
|
68
|
-
clearInterval(tabInterval);
|
|
69
|
-
button.disabled = false
|
|
70
|
-
button.innerHTML = this.buttonText
|
|
71
|
-
}
|
|
72
|
-
}, 500)
|
|
73
|
-
}
|
|
74
|
-
openCheckout = () => {
|
|
75
|
-
const queryString = this.getUrlParams()
|
|
76
|
-
const encrypted = AES.encrypt(queryString, 'url-params-encrypt').toString()
|
|
77
|
-
const encodedURL = encodeURIComponent(encrypted);
|
|
78
|
-
this.params = "?" + encodedURL;
|
|
79
|
-
const newWindow = window.open(this.url + this.params, '_blank', `width=1200,height=$800,left=0,top=0`);
|
|
80
|
-
this.tonderButton.disabled = true
|
|
81
|
-
this.tonderButton.innerHTML = `
|
|
82
|
-
<div class="loader"></div>
|
|
83
|
-
<style>
|
|
84
|
-
.loader {
|
|
85
|
-
border: 4px solid ${this.color};
|
|
86
|
-
border-radius: 50%;
|
|
87
|
-
border-top: 4px solid ${this.backgroundColor};
|
|
88
|
-
width: 0.625rem;
|
|
89
|
-
height: 0.625rem;
|
|
90
|
-
-webkit-animation: spin 2s linear infinite; /* Safari */
|
|
91
|
-
animation: spin 2s linear infinite;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/* Safari */
|
|
95
|
-
@-webkit-keyframes spin {
|
|
96
|
-
0% { -webkit-transform: rotate(0deg); }
|
|
97
|
-
100% { -webkit-transform: rotate(360deg); }
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
@keyframes spin {
|
|
101
|
-
0% { transform: rotate(0deg); }
|
|
102
|
-
100% { transform: rotate(360deg); }
|
|
103
|
-
}
|
|
104
|
-
</style>
|
|
105
|
-
`
|
|
106
|
-
this.openTabListener(newWindow, this.tonderButton)
|
|
107
|
-
}
|
|
108
|
-
getUrlParams = () => {
|
|
109
|
-
const params = { apiKey: this.apiKey, ...this.order, type: this.type}
|
|
110
|
-
if (params.products) {
|
|
111
|
-
params.products = JSON.stringify(params.products)
|
|
112
|
-
}
|
|
113
|
-
const queryString = new URLSearchParams(params).toString();
|
|
114
|
-
return queryString
|
|
115
|
-
}
|
|
116
|
-
receiveMessage(event) {
|
|
117
|
-
// Parse data if it is possible, in case of error it will return the raw data.
|
|
118
|
-
try {
|
|
119
|
-
const data = JSON.parse(event.data)
|
|
120
|
-
this.cb(data)
|
|
121
|
-
} catch(error) {
|
|
122
|
-
this.cb(event.data)
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { cardTemplateSkeleton } from '../helpers/template-skeleton.js'
|
|
2
|
-
|
|
3
|
-
class GlobalLoader {
|
|
4
|
-
constructor() {
|
|
5
|
-
this.requestCount = 0;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
show() {
|
|
9
|
-
this.requestCount++;
|
|
10
|
-
const checkoutContainer = document.querySelector("#global-loader");
|
|
11
|
-
if (checkoutContainer) {
|
|
12
|
-
checkoutContainer.innerHTML = cardTemplateSkeleton;
|
|
13
|
-
checkoutContainer.style.display = 'block';
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
remove() {
|
|
18
|
-
this.requestCount--;
|
|
19
|
-
if (this.requestCount <= 0) {
|
|
20
|
-
this.requestCount = 0;
|
|
21
|
-
const loader = document.querySelector('#global-loader');
|
|
22
|
-
if (loader) {
|
|
23
|
-
loader.style.display = 'none';
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export const globalLoader = new GlobalLoader();
|