@tonder.io/ionic-lite-sdk 0.0.57 → 0.0.58

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.
@@ -1,5 +1,12 @@
1
1
  import { ICustomer } from "./customer";
2
2
  import { IProcessPaymentRequest, IStartCheckoutResponse } from "./checkout";
3
+ import CollectorContainer from "skyflow-js/types/core/external/collect/collect-container";
4
+ import ComposableContainer from "skyflow-js/types/core/external/collect/compose-collect-container";
5
+ import RevealContainer from "skyflow-js/types/core/external/reveal/reveal-container";
6
+ import CollectElement from "skyflow-js/types/core/external/collect/collect-element";
7
+ import ComposableElement from "skyflow-js/types/core/external/collect/compose-collect-element";
8
+ import RevealElement from "skyflow-js/types/core/external/reveal/reveal-element";
9
+ import { LabelStyles } from "skyflow-js/types/utils/common";
3
10
  export type Business = {
4
11
  business: {
5
12
  pk: number;
@@ -112,6 +119,28 @@ export interface IInlineLiteCheckoutOptions extends IInlineCheckoutBaseOptions {
112
119
  collectorIds?: {
113
120
  tdsIframe?: string;
114
121
  };
122
+ customization?: ILiteCustomizationOptions;
123
+ events?: IEvents;
124
+ }
125
+ export interface ICardFormEvents {
126
+ cardHolderEvents?: IInputEvents;
127
+ cardNumberEvents?: IInputEvents;
128
+ cvvEvents?: IInputEvents;
129
+ monthEvents?: IInputEvents;
130
+ yearEvents?: IInputEvents;
131
+ }
132
+ export interface IInputEvents {
133
+ onChange?: (event: IEventSecureInput) => void;
134
+ onFocus?: (event: IEventSecureInput) => void;
135
+ onBlur?: (event: IEventSecureInput) => void;
136
+ }
137
+ export interface IEventSecureInput {
138
+ elementType: string;
139
+ isEmpty: boolean;
140
+ isFocused: boolean;
141
+ isValid: boolean;
142
+ }
143
+ export interface IEvents extends ICardFormEvents {
115
144
  }
116
145
  export interface IApiError {
117
146
  code: string;
@@ -128,3 +157,56 @@ export interface IPublicError {
128
157
  export type CustomizationOptions = {
129
158
  redirectOnComplete?: boolean;
130
159
  };
160
+ export interface InCollectorContainer {
161
+ container: CollectorContainer | ComposableContainer | RevealContainer;
162
+ elements: (CollectElement | ComposableElement | RevealElement)[];
163
+ }
164
+ export interface ILiteCustomizationOptions extends CustomizationOptions {
165
+ styles?: IStyles;
166
+ labels?: IFormLabels;
167
+ placeholders?: IFormPlaceholder;
168
+ }
169
+ export interface IFormLabels {
170
+ name?: string;
171
+ card_number?: string;
172
+ cvv?: string;
173
+ expiry_date?: string;
174
+ expiration_year?: string;
175
+ expiration_month?: string;
176
+ }
177
+ export interface IFormPlaceholder {
178
+ name?: string;
179
+ card_number?: string;
180
+ cvv?: string;
181
+ expiration_month?: string;
182
+ expiration_year?: string;
183
+ }
184
+ export interface IStyles {
185
+ cardForm?: ILiteCardFormStyles;
186
+ }
187
+ export interface ILiteCardFormStyles extends StylesBaseVariant, IElementStyle {
188
+ }
189
+ export interface StylesBaseVariant {
190
+ base?: Record<string, any>;
191
+ }
192
+ export interface IElementStyle {
193
+ inputStyles?: CollectInputStylesVariant;
194
+ labelStyles?: LabelStyles;
195
+ errorStyles?: StylesBaseVariant;
196
+ }
197
+ export interface StylesFocusVariant {
198
+ focus?: Record<string, any>;
199
+ }
200
+ export interface CollectInputStylesVariant extends StylesBaseVariant, StylesFocusVariant {
201
+ complete?: Record<string, any>;
202
+ invalid?: Record<string, any>;
203
+ empty?: Record<string, any>;
204
+ cardIcon?: Record<string, any>;
205
+ dropdownIcon?: Record<string, any>;
206
+ dropdown?: Record<string, any>;
207
+ dropdownListItem?: Record<string, any>;
208
+ global: Record<string, any>;
209
+ }
210
+ export interface CollectLabelStylesVariant extends StylesBaseVariant, StylesFocusVariant {
211
+ requiredAsterisk?: Record<string, any>;
212
+ }
@@ -158,4 +158,12 @@ export interface ILiteCheckout {
158
158
  * during the payment process.
159
159
  */
160
160
  getOpenpayDeviceSessionID(merchant_id: string, public_key: string, is_sandbox: boolean): Promise<string | ErrorResponse>;
161
+ /**
162
+ * Displays and renders card input fields in the checkout.
163
+ * Uses the provided configuration to show the required fields in the payment form.
164
+ * @param {import("./card").IMountCardFieldsRequest} event - Configuration for the card fields to render.
165
+ * @returns {Promise<void>} Resolves when the fields have been successfully rendered.
166
+ * @public
167
+ */
168
+ mountCardFields(event: import("./card").IMountCardFieldsRequest): Promise<void>;
161
169
  }
@@ -66,7 +66,7 @@ export type TokensSkyflowRequest = {
66
66
  apiKey: string;
67
67
  vault_id: string;
68
68
  vault_url: string;
69
- data: {
69
+ data?: {
70
70
  [key: string]: any;
71
71
  };
72
72
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tonder.io/ionic-lite-sdk",
3
- "version": "0.0.57",
3
+ "version": "0.0.58",
4
4
  "description": "Tonder ionic lite SDK",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -13,7 +13,7 @@
13
13
  "license": "ISC",
14
14
  "dependencies": {
15
15
  "lodash.get": "^4.4.2",
16
- "skyflow-js": "^1.34.1",
16
+ "skyflow-js": "2.4.4",
17
17
  "ts-node": "^10.9.2"
18
18
  },
19
19
  "publishConfig": {
@@ -239,7 +239,6 @@ export class ThreeDSHandler {
239
239
 
240
240
  handleSuccessTransaction(response: any) {
241
241
  this.removeVerifyTransactionUrl();
242
- console.log('Transacción autorizada.');
243
242
  return response;
244
243
  }
245
244
 
@@ -1,40 +1,59 @@
1
- import { fetchBusiness } from "../data/businessApi";
2
-
3
- declare const MP_DEVICE_SESSION_ID: string | undefined;
4
- import { ErrorResponse } from "./errorResponse";
1
+ import {fetchBusiness} from "../data/businessApi";
2
+ import {ErrorResponse} from "./errorResponse";
5
3
  import {
6
4
  buildErrorResponse,
7
5
  buildErrorResponseFromCatch,
6
+ formatPublicErrorResponse,
8
7
  getBrowserInfo,
9
8
  getBusinessId,
10
- formatPublicErrorResponse,
11
9
  getCardType,
12
10
  } from "../helpers/utils";
13
- import { getCustomerAPMs } from "../data/api";
14
- import { BaseInlineCheckout } from "./BaseInlineCheckout";
15
- import { MESSAGES } from "../shared/constants/messages";
16
- import { getSkyflowTokens } from "../helpers/skyflow";
17
- import { startCheckoutRouter } from "../data/checkoutApi";
18
- import { getOpenpayDeviceSessionID } from "../data/openPayApi";
19
- import { getPaymentMethodDetails } from "../shared/catalog/paymentMethodsCatalog";
20
- import {APM, IInlineLiteCheckoutOptions, TonderAPM} from "../types/commons";
21
- import {ICustomerCardsResponse, ISaveCardRequest, ISaveCardResponse, ISaveCardSkyflowRequest} from "../types/card";
11
+ import {getCustomerAPMs} from "../data/api";
12
+ import {BaseInlineCheckout} from "./BaseInlineCheckout";
13
+ import {MESSAGES} from "../shared/constants/messages";
14
+ import {getSkyflowTokens, initSkyflowInstance, mountSkyflowFields} from "../helpers/skyflow";
15
+ import {startCheckoutRouter} from "../data/checkoutApi";
16
+ import {getOpenpayDeviceSessionID} from "../data/openPayApi";
17
+ import {getPaymentMethodDetails} from "../shared/catalog/paymentMethodsCatalog";
18
+ import {
19
+ APM, IEvents,
20
+ IInlineLiteCheckoutOptions,
21
+ ILiteCustomizationOptions,
22
+ InCollectorContainer,
23
+ TonderAPM
24
+ } from "../types/commons";
25
+ import {
26
+ ICustomerCardsResponse,
27
+ IMountCardFieldsRequest,
28
+ ISaveCardRequest,
29
+ ISaveCardResponse,
30
+ ISaveCardSkyflowRequest
31
+ } from "../types/card";
22
32
  import {IPaymentMethod} from "../types/paymentMethod";
23
33
  import {
24
34
  CreateOrderResponse,
25
35
  CreatePaymentResponse,
26
36
  CustomerRegisterResponse,
27
- GetBusinessResponse, IErrorResponse, RegisterCustomerCardResponse, StartCheckoutResponse
37
+ GetBusinessResponse,
38
+ IErrorResponse,
39
+ RegisterCustomerCardResponse,
40
+ StartCheckoutResponse
28
41
  } from "../types/responses";
29
42
  import {
30
43
  CreateOrderRequest,
31
- CreatePaymentRequest, RegisterCustomerCardRequest, StartCheckoutFullRequest,
44
+ CreatePaymentRequest,
45
+ RegisterCustomerCardRequest,
46
+ StartCheckoutFullRequest,
32
47
  StartCheckoutIdRequest,
33
48
  StartCheckoutRequest,
34
49
  TokensRequest
35
50
  } from "../types/requests";
36
51
  import {ICardFields, IStartCheckoutResponse} from "../types/checkout";
37
52
  import {ILiteCheckout} from "../types/liteInlineCheckout";
53
+ import CollectorContainer from "skyflow-js/types/core/external/collect/collect-container";
54
+ import Skyflow from "skyflow-js";
55
+
56
+ declare const MP_DEVICE_SESSION_ID: string | undefined;
38
57
 
39
58
  declare global {
40
59
  interface Window {
@@ -44,9 +63,15 @@ declare global {
44
63
 
45
64
  export class LiteCheckout extends BaseInlineCheckout implements ILiteCheckout{
46
65
  activeAPMs: APM[] = [];
66
+ private collectContainer: InCollectorContainer | null;
67
+ private skyflowInstance: Skyflow | null;
68
+ private readonly events: IEvents
47
69
 
48
- constructor({ apiKey, mode, returnUrl, callBack, apiKeyTonder, baseUrlTonder, customization, collectorIds }: IInlineLiteCheckoutOptions) {
70
+ constructor({ apiKey, mode, returnUrl, callBack, apiKeyTonder, baseUrlTonder, customization, collectorIds, events }: IInlineLiteCheckoutOptions) {
49
71
  super({ mode, apiKey, returnUrl, callBack, apiKeyTonder, baseUrlTonder, customization, tdsIframeId: collectorIds && 'tdsIframe' in collectorIds ? collectorIds?.tdsIframe : "tdsIframe"});
72
+ this.collectContainer = null;
73
+ this.skyflowInstance = null;
74
+ this.events = events || {}
50
75
  }
51
76
 
52
77
  public async injectCheckout() {
@@ -169,6 +194,16 @@ export class LiteCheckout extends BaseInlineCheckout implements ILiteCheckout{
169
194
  }
170
195
  }
171
196
 
197
+ public async mountCardFields(event: IMountCardFieldsRequest): Promise<void> {
198
+ await this.createSkyflowInstance();
199
+ this.collectContainer = await mountSkyflowFields({
200
+ skyflowInstance: this.skyflowInstance!,
201
+ data: event,
202
+ customization: this.customization,
203
+ events: this.events,
204
+ });
205
+ }
206
+
172
207
  public async getBusiness(): Promise<GetBusinessResponse> {
173
208
  try {
174
209
  return await fetchBusiness(
@@ -186,6 +221,19 @@ export class LiteCheckout extends BaseInlineCheckout implements ILiteCheckout{
186
221
  }
187
222
  }
188
223
 
224
+
225
+ private async createSkyflowInstance() {
226
+ if(this.skyflowInstance) return this.skyflowInstance
227
+ await this._fetchMerchantData();
228
+ const { vault_id, vault_url } = this.merchantData!;
229
+ this.skyflowInstance = await initSkyflowInstance({
230
+ vault_id: vault_id,
231
+ vault_url: vault_url,
232
+ baseUrl: this.baseUrl,
233
+ apiKey: this.apiKeyTonder,
234
+ })
235
+ }
236
+
189
237
  // TODO: DEPRECATED
190
238
  async getOpenpayDeviceSessionID(
191
239
  merchant_id: string,
@@ -240,6 +288,8 @@ export class LiteCheckout extends BaseInlineCheckout implements ILiteCheckout{
240
288
  let skyflowTokens;
241
289
  if (!payment_method || payment_method === "" || payment_method === null) {
242
290
  if (typeof card === "string") {
291
+ const container = this.collectContainer?.container as CollectorContainer;
292
+ await container.collect()
243
293
  skyflowTokens = {
244
294
  skyflow_id: card,
245
295
  };
@@ -3,9 +3,7 @@ export function injectMercadoPagoSecurity() {
3
3
  const script = document.createElement("script");
4
4
  script.src = "https://www.mercadopago.com/v2/security.js";
5
5
  script.setAttribute("view", "");
6
- script.onload = () => {
7
- console.log("Mercado Pago script loaded successfully.");
8
- };
6
+ script.onload = () => {};
9
7
  script.onerror = (error) => {
10
8
  console.error("Error loading Mercado Pago script:", error);
11
9
  };
@@ -1,11 +1,35 @@
1
- import {ErrorResponse} from "../classes/errorResponse";
1
+ import { ErrorResponse } from "../classes/errorResponse";
2
2
  import Skyflow from "skyflow-js";
3
3
  import CollectContainer from "skyflow-js/types/core/external/collect/collect-container";
4
- import {buildErrorResponseFromCatch} from "./utils";
4
+ import { buildErrorResponseFromCatch } from "./utils";
5
5
  import CollectElement from "skyflow-js/types/core/external/collect/collect-element";
6
- import {getVaultToken} from "../data/skyflowApi";
7
- import {TokensSkyflowRequest} from "../types/requests";
6
+ import { getVaultToken } from "../data/skyflowApi";
7
+ import { TokensSkyflowRequest } from "../types/requests";
8
+ import { CardFieldEnum, IMountCardFieldsRequest } from "../types/card";
9
+ import {
10
+ IEvents,
11
+ IInputEvents,
12
+ ILiteCustomizationOptions,
13
+ StylesBaseVariant,
14
+ } from "../types/commons";
15
+ import {
16
+ DEFAULT_SKYFLOW_lABELS,
17
+ DEFAULT_SKYFLOW_PLACEHOLDERS,
18
+ lengthMatchRule,
19
+ regexMatchRule,
20
+ } from "../shared/constants/skyflow.contants";
21
+ import {
22
+ DEFAULT_SKYFLOW_ERROR_TEXT_STYLES,
23
+ DEFAULT_SKYFLOW_INPUT_STYLES,
24
+ DEFAULT_SKYFLOW_lABEL_STYLES,
25
+ } from "../shared/styles/skyflow.styles";
26
+ import { get } from "lodash";
8
27
 
28
+ /**
29
+ * [DEPRECATION WARNING]
30
+ * This function should be deprecated in favor of using mountSkyflowFields for security,
31
+ * to prevent users from creating their own inputs.
32
+ */
9
33
  export async function getSkyflowTokens({
10
34
  baseUrl,
11
35
  apiKey,
@@ -19,7 +43,7 @@ export async function getSkyflowTokens({
19
43
  getBearerToken: async () => await getVaultToken(baseUrl, apiKey),
20
44
  options: {
21
45
  logLevel: Skyflow.LogLevel.ERROR,
22
- env: Skyflow.Env.DEV,
46
+ env: Skyflow.Env.DEV, // ⚠️ This should be Env.PROD, but currently it cannot be changed because getSkyflowTokens must be deprecated first, since .setValue does not work in PROD.
23
47
  },
24
48
  });
25
49
 
@@ -52,40 +76,288 @@ export async function getSkyflowTokens({
52
76
  }
53
77
  }
54
78
 
55
- async function getFieldsPromise(data: any, collectContainer: CollectContainer): Promise<Promise<boolean>[]> {
56
- const fields = await getFields(data, collectContainer);
57
- if (!fields) return [];
79
+ async function getFieldsPromise(
80
+ data: any,
81
+ collectContainer: CollectContainer,
82
+ ): Promise<Promise<boolean>[]> {
83
+ const fields = await getFields(data, collectContainer);
84
+ if (!fields) return [];
58
85
 
59
- return fields.map((field: { element: CollectElement, key: string }) => {
86
+ return fields.map((field: { element: CollectElement; key: string }) => {
60
87
  return new Promise((resolve) => {
61
- const div = document.createElement("div");
62
- div.hidden = true;
63
- div.id = `id-${field.key}`;
64
- document.querySelector(`body`)?.appendChild(div);
65
- setTimeout(() => {
66
- field.element.mount(`#id-${field.key}`);
67
- setInterval(() => {
68
- if (field.element.isMounted()) {
69
- const value = data[field.key];
70
- field.element.update({ value: value });
71
- return resolve(field.element.isMounted());
72
- }
73
- }, 120);
88
+ const div = document.createElement("div");
89
+ div.hidden = true;
90
+ div.id = `id-${field.key}`;
91
+ document.querySelector(`body`)?.appendChild(div);
92
+ setTimeout(() => {
93
+ field.element.mount(`#id-${field.key}`);
94
+ setInterval(() => {
95
+ if (field.element.isMounted()) {
96
+ const value = data[field.key];
97
+ field.element.setValue(value);
98
+ return resolve(field.element.isMounted());
99
+ }
74
100
  }, 120);
101
+ }, 120);
102
+ });
103
+ });
104
+ }
105
+
106
+ async function getFields(
107
+ data: any,
108
+ collectContainer: CollectContainer,
109
+ ): Promise<{ element: CollectElement; key: string }[]> {
110
+ return await Promise.all(
111
+ Object.keys(data).map(async (key) => {
112
+ const cardHolderNameElement = await collectContainer.create({
113
+ table: "cards",
114
+ column: key,
115
+ type: Skyflow.ElementType.INPUT_FIELD,
116
+ });
117
+ return { element: cardHolderNameElement, key: key };
118
+ }),
119
+ );
120
+ }
121
+
122
+ export async function initSkyflowInstance({
123
+ baseUrl,
124
+ apiKey,
125
+ vault_id,
126
+ vault_url,
127
+ }: TokensSkyflowRequest): Promise<Skyflow> {
128
+ return Skyflow.init({
129
+ vaultID: vault_id,
130
+ vaultURL: vault_url,
131
+ getBearerToken: async () => await getVaultToken(baseUrl, apiKey),
132
+ options: {
133
+ logLevel: Skyflow.LogLevel.ERROR,
134
+ env: Skyflow.Env.DEV,
135
+ },
136
+ });
137
+ }
138
+
139
+ export async function mountSkyflowFields(event: {
140
+ skyflowInstance: Skyflow;
141
+ data: IMountCardFieldsRequest;
142
+ customization?: ILiteCustomizationOptions;
143
+ events?: IEvents;
144
+ }): Promise<{ elements: CollectElement[]; container: CollectContainer }> {
145
+ const { skyflowInstance, data, customization, events } = event;
146
+ const collectContainer: CollectContainer = skyflowInstance.container(
147
+ Skyflow.ContainerType.COLLECT,
148
+ ) as CollectContainer;
149
+ const elements: { element: CollectElement; containerId: string }[] = [];
150
+ const typeByField: Record<
151
+ CardFieldEnum,
152
+ (typeof Skyflow.ElementType)[keyof typeof Skyflow.ElementType]
153
+ > = {
154
+ [CardFieldEnum.CVV]: Skyflow.ElementType.CVV,
155
+ [CardFieldEnum.CARD_NUMBER]: Skyflow.ElementType.CARD_NUMBER,
156
+ [CardFieldEnum.EXPIRATION_MONTH]: Skyflow.ElementType.EXPIRATION_MONTH,
157
+ [CardFieldEnum.EXPIRATION_YEAR]: Skyflow.ElementType.EXPIRATION_YEAR,
158
+ [CardFieldEnum.CARDHOLDER_NAME]: Skyflow.ElementType.CARDHOLDER_NAME,
159
+ };
160
+
161
+ const validationsByField = {
162
+ [CardFieldEnum.CVV]: [regexMatchRule],
163
+ [CardFieldEnum.CARD_NUMBER]: [regexMatchRule],
164
+ [CardFieldEnum.EXPIRATION_MONTH]: [regexMatchRule],
165
+ [CardFieldEnum.EXPIRATION_YEAR]: [regexMatchRule],
166
+ [CardFieldEnum.CARDHOLDER_NAME]: [lengthMatchRule, regexMatchRule],
167
+ };
168
+ const customStyles = {
169
+ errorStyles:
170
+ customization?.styles?.cardForm?.errorStyles ||
171
+ DEFAULT_SKYFLOW_ERROR_TEXT_STYLES,
172
+ inputStyles:
173
+ customization?.styles?.cardForm?.inputStyles ||
174
+ DEFAULT_SKYFLOW_INPUT_STYLES,
175
+ labelStyles:
176
+ customization?.styles?.cardForm?.labelStyles ||
177
+ DEFAULT_SKYFLOW_lABEL_STYLES,
178
+ };
179
+ const labels: Record<string, string> = {
180
+ name: customization?.labels?.name || DEFAULT_SKYFLOW_lABELS.name,
181
+ card_number:
182
+ customization?.labels?.card_number || DEFAULT_SKYFLOW_lABELS.card_number,
183
+ cvv: customization?.labels?.cvv || DEFAULT_SKYFLOW_lABELS.cvv,
184
+ expiration_date:
185
+ customization?.labels?.expiry_date ||
186
+ DEFAULT_SKYFLOW_lABELS.expiration_date,
187
+ expiration_month:
188
+ customization?.labels?.expiration_month ||
189
+ DEFAULT_SKYFLOW_lABELS.expiration_month,
190
+ expiration_year:
191
+ customization?.labels?.expiration_year ||
192
+ DEFAULT_SKYFLOW_lABELS.expiration_year,
193
+ };
194
+ const placeholders: Record<string, string> = {
195
+ name:
196
+ customization?.placeholders?.name || DEFAULT_SKYFLOW_PLACEHOLDERS.name,
197
+ card_number:
198
+ customization?.placeholders?.card_number ||
199
+ DEFAULT_SKYFLOW_PLACEHOLDERS.card_number,
200
+ cvv: customization?.placeholders?.cvv || DEFAULT_SKYFLOW_PLACEHOLDERS.cvv,
201
+ expiration_month:
202
+ customization?.placeholders?.expiration_month ||
203
+ DEFAULT_SKYFLOW_PLACEHOLDERS.expiration_month,
204
+ expiration_year:
205
+ customization?.placeholders?.expiration_year ||
206
+ DEFAULT_SKYFLOW_PLACEHOLDERS.expiration_year,
207
+ };
208
+ const eventsByField: Record<CardFieldEnum, IInputEvents | undefined> = {
209
+ [CardFieldEnum.CVV]: events?.cvvEvents,
210
+ [CardFieldEnum.CARD_NUMBER]: events?.cardNumberEvents,
211
+ [CardFieldEnum.EXPIRATION_MONTH]: events?.monthEvents,
212
+ [CardFieldEnum.EXPIRATION_YEAR]: events?.yearEvents,
213
+ [CardFieldEnum.CARDHOLDER_NAME]: events?.cardHolderEvents,
214
+ }
215
+
216
+ if ("fields" in data && Array.isArray(data.fields)) {
217
+ if (data.fields.length > 0 && typeof data.fields[0] === "string") {
218
+ for (const field of data.fields as CardFieldEnum[]) {
219
+ const element = collectContainer.create({
220
+ table: "cards",
221
+ column: field,
222
+ type: typeByField[field],
223
+ validations: validationsByField[field],
224
+ ...customStyles,
225
+ label: labels[field],
226
+ placeholder: placeholders[field],
227
+ ...(data.card_id ? { skyflowID: data.card_id } : {}),
228
+ });
229
+ handleSkyflowElementEvents({
230
+ element,
231
+ errorStyles: customStyles.errorStyles,
232
+ fieldMessage: [CardFieldEnum.CVV, CardFieldEnum.EXPIRATION_MONTH, CardFieldEnum.EXPIRATION_YEAR].includes(field) ? "":labels[field],
233
+ events: eventsByField[field],
234
+ });
235
+ const containerId =
236
+ `#collect_${String(field)}` +
237
+ (data.card_id ? `_${data.card_id}` : "");
238
+ element.mount(containerId);
239
+ elements.push({ element, containerId });
240
+ }
241
+ } else {
242
+ for (const fieldObj of data.fields as {
243
+ container_id?: string;
244
+ field: CardFieldEnum;
245
+ }[]) {
246
+ const key = fieldObj.field;
247
+ const element = collectContainer.create({
248
+ table: "cards",
249
+ column: key,
250
+ type: typeByField[key],
251
+ validations: validationsByField[key],
252
+ ...customStyles,
253
+ label: labels[key],
254
+ placeholder: placeholders[key],
255
+ ...(data.card_id ? { skyflowID: data.card_id } : {}),
256
+ });
257
+ const containerId =
258
+ fieldObj.container_id ||
259
+ `#collect_${String(key)}` + (data.card_id ? `_${data.card_id}` : "");
260
+ element.mount(containerId);
261
+ elements.push({ element, containerId });
262
+ }
263
+ }
264
+ }
265
+
266
+ return {
267
+ elements: elements.map((e) => e.element),
268
+ container: collectContainer,
269
+ };
270
+ }
271
+
272
+ function handleSkyflowElementEvents(event: {
273
+ element: CollectElement;
274
+ fieldMessage?: string;
275
+ errorStyles?: StylesBaseVariant;
276
+ requiredMessage?: string;
277
+ invalidMessage?: string;
278
+ events?: IInputEvents;
279
+ }) {
280
+ const {
281
+ element,
282
+ fieldMessage = "",
283
+ errorStyles = {},
284
+ requiredMessage = "Campo requerido",
285
+ invalidMessage = "Campo no válido",
286
+ events
287
+ } = event;
288
+ if ("on" in element) {
289
+ element.on(Skyflow.EventName.CHANGE, (state: any) => {
290
+ executeEvent({eventName: "onChange", data: state, events});
291
+ updateErrorLabel({
292
+ element,
293
+ errorStyles,
294
+ color: "transparent",
295
+ });
296
+ });
297
+
298
+ element.on(Skyflow.EventName.BLUR, (state: any) => {
299
+ executeEvent({eventName: "onBlur", data: state, events});
300
+ if (!state.isValid) {
301
+ const msj_error = state.isEmpty
302
+ ? requiredMessage
303
+ : fieldMessage != ""
304
+ ? `El campo ${fieldMessage} no es válido`
305
+ : invalidMessage;
306
+ element.setError(msj_error);
307
+ }
308
+ updateErrorLabel({
309
+ element,
310
+ errorStyles,
311
+ });
312
+ });
313
+
314
+ element.on(Skyflow.EventName.FOCUS, (state: any) => {
315
+ executeEvent({eventName: "onFocus", data: state, events});
316
+ updateErrorLabel({
317
+ element,
318
+ errorStyles,
319
+ color: "transparent",
320
+ });
321
+ element.resetError();
75
322
  });
76
- })
323
+ }
77
324
  }
78
325
 
79
- async function getFields(data: any, collectContainer: CollectContainer): Promise<{ element: CollectElement, key: string }[]> {
80
- return await Promise.all(
81
- Object.keys(data).map(async (key) => {
82
- const cardHolderNameElement = await collectContainer.create({
83
- table: "cards",
84
- column: key,
85
- type: Skyflow.ElementType.INPUT_FIELD,
86
- });
87
- return { element: cardHolderNameElement, key: key };
88
- })
89
- )
326
+ function updateErrorLabel(event: {
327
+ element: CollectElement;
328
+ errorStyles?: StylesBaseVariant;
329
+ color?: string;
330
+ }) {
331
+ const { element, errorStyles = {}, color = "" } = event;
332
+ if (Object.keys(errorStyles).length > 0) {
333
+ element.update({
334
+ errorTextStyles: {
335
+ ...errorStyles,
336
+ base: {
337
+ // @ts-ignore
338
+ ...(errorStyles.base && { ...errorStyles.base }),
339
+ ...(color != "" && { color }),
340
+ },
341
+ },
342
+ });
343
+ }
90
344
  }
91
345
 
346
+ const executeEvent = (event: {
347
+ eventName: "onChange" | "onBlur" | "onFocus";
348
+ data: any;
349
+ events?: IInputEvents;
350
+ }) => {
351
+ const { eventName, data, events } = event;
352
+ if (events && eventName in events) {
353
+ const eventHandler = events[eventName];
354
+ if (typeof eventHandler === "function") {
355
+ eventHandler({
356
+ elementType: get(data, "elementType", ""),
357
+ isEmpty: get(data, "isEmpty", ""),
358
+ isFocused: get(data, "isFocused", ""),
359
+ isValid: get(data, "isValid", ""),
360
+ });
361
+ }
362
+ }
363
+ };