@finos_sdk/sdk-ekyc 1.5.0 → 1.5.2

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,4 +1,3 @@
1
- import React from 'react';
2
1
  import { SDK_VERSION, SDK_NAME } from '../../EKYCModule';
3
2
  import { NfcConfig } from '../types/ekycNFCType';
4
3
  import { SDKEkycResultWithEvent, SDKEkycResultStringWithEvent, EKYCError, AppIDType } from '../types/ekycType';
@@ -9,6 +8,7 @@ import { FaceServiceConfig, FaceCompareSuccessEvent } from '../types/ekycFaceTyp
9
8
  import { SmsOtpConfig, SmsOtpResult } from '../types/ekycSmsOtpType';
10
9
  import { ESignInitResult, ESignOpenSessionResult, ESignCertificate, ESignSignRequest, ESignPdfResult, ESignApiResponse } from '../types/ekycESignType';
11
10
  import { SDKFlowType } from '../types/ekycFlowType';
11
+ import { ExitConfirmConfig } from '../types/ekycExitConfirmType';
12
12
  /**
13
13
  * Finos eKYC SDK Module
14
14
  *
@@ -77,8 +77,9 @@ export declare class FinosEKYCModule {
77
77
  * @param config.customActions - SDKFaceDetectStatus[] enum (LEFT, RIGHT, SMILE, BLINK, ...). Bên sử dụng truyền enum thay vì string
78
78
  * @param config.activeActionCount - Number of random actions (1-10), only used when customActions is null (default: 2)
79
79
  * @param config.switchFrontCamera - Use front camera (default: false)
80
+ * @param exitConfirmConfig - Optional config tuỳ chỉnh bottom sheet xác nhận thoát. null = mặc định SDK.
80
81
  */
81
- startLiveness(config: LivenessConfig): Promise<LivenessSuccessEvent>;
82
+ startLiveness(config: LivenessConfig, exitConfirmConfig?: ExitConfirmConfig): Promise<LivenessSuccessEvent>;
82
83
  /**
83
84
  * Start face comparison (Face Service)
84
85
  * @param config Face service configuration
@@ -101,51 +102,6 @@ export declare class FinosEKYCModule {
101
102
  * Handle new intent (Android)
102
103
  */
103
104
  handleNewIntent(): void;
104
- /**
105
- * Register a custom exit confirmation handler to show UI in React Native instead of using native bottom sheet.
106
- */
107
- registerExitHandler(): Promise<boolean>;
108
- /**
109
- * Resolve the custom exit confirmation.
110
- * @param action 'CONFIRM' (exit SDK), 'CANCEL' or 'CLOSE' (stay in SDK)
111
- */
112
- resolveExit(action: 'CONFIRM' | 'CANCEL' | 'CLOSE'): Promise<boolean>;
113
- /**
114
- * Set custom component to render inside the exit bottom sheet.
115
- * Thay thế ExitConfirmSheet mặc định bằng component tùy chỉnh.
116
- * Không cần AppRegistry — SDK tự lo phần registration.
117
- *
118
- * @param component React component để hiển thị, hoặc null để về default
119
- *
120
- * @example
121
- * FinosEKYC.setExitSheetComponent(WarningBottomSheet);
122
- */
123
- setExitSheetComponent(component: React.ComponentType<any> | null): void;
124
- /**
125
- * Show the exit bottom sheet on top of the current SDK screen.
126
- * Mặc định dùng 'SDKExitSheetWrapper' (đã register sẵn trong SDK).
127
- *
128
- * @param props Props truyền vào component (optional)
129
- *
130
- * @example
131
- * // Dùng default ExitConfirmSheet
132
- * FinosEKYC.showRNExitSheet();
133
- *
134
- * // Dùng custom component (set trước bằng setExitSheetComponent)
135
- * FinosEKYC.setExitSheetComponent(WarningBottomSheet);
136
- * FinosEKYC.showRNExitSheet();
137
- */
138
- showRNExitSheet(props?: any): Promise<boolean>;
139
- /**
140
- * Show a native alert dialog on top of the current activity (useful for SDK screens)
141
- * @param config Dialog configuration { title, message, confirmText, cancelText }
142
- */
143
- showNativeExitDialog(config: {
144
- title?: string;
145
- message?: string;
146
- confirmText?: string;
147
- cancelText?: string;
148
- }): Promise<'CONFIRM' | 'CANCEL'>;
149
105
  /**
150
106
  * Listen for NFC scan start events
151
107
  */
@@ -200,11 +156,6 @@ export declare class FinosEKYCModule {
200
156
  * Listen for eKYC UI error events
201
157
  */
202
158
  onEkycUIError(callback: (error: any) => void): import("react-native").EmitterSubscription | null;
203
- /**
204
- * Listen for exit confirm events triggered by the SDK.
205
- * Call resolveExit('CONFIRM' | 'CANCEL' | 'CLOSE') after user chooses an action.
206
- */
207
- onShowExitConfirm(callback: () => void): import("react-native").EmitterSubscription | null;
208
159
  /**
209
160
  * Remove all event listeners
210
161
  */
@@ -347,6 +298,8 @@ export declare class FinosEKYCModule {
347
298
  * @param appKeyConfig Optional app key configuration
348
299
  * @param optionConfig Optional configuration settings (includes switchFrontCamera for camera control)
349
300
  * @param styleConfig Optional style configuration
301
+ * @param exitConfirmConfig Optional config tuỳ chỉnh bottom sheet xác nhận thoát (icon, title, content, buttons).
302
+ * null = giữ default SDK. Xem EXIT_CONFIRM_CONFIG.md.
350
303
  */
351
304
  startEkycUI(appKey: string, flowSDK: SDKFlowType[], language: string, transactionId: string, appKeyConfig: {
352
305
  appKey: string;
@@ -409,7 +362,7 @@ export declare class FinosEKYCModule {
409
362
  };
410
363
  captureButtonColor?: number;
411
364
  captureButtonDisabledColor?: number;
412
- }): Promise<any>;
365
+ }, exitConfirmConfig?: ExitConfirmConfig): Promise<any>;
413
366
  private validateSDKReady;
414
367
  private validatePlatform;
415
368
  }
@@ -38,7 +38,6 @@ const react_native_1 = require("react-native");
38
38
  const EKYCModule_1 = __importStar(require("../../EKYCModule"));
39
39
  Object.defineProperty(exports, "SDK_VERSION", { enumerable: true, get: function () { return EKYCModule_1.SDK_VERSION; } });
40
40
  Object.defineProperty(exports, "SDK_NAME", { enumerable: true, get: function () { return EKYCModule_1.SDK_NAME; } });
41
- const ExitSheetWrapper_1 = require("../components/ExitSheetWrapper");
42
41
  const ekycFlowType_1 = require("../types/ekycFlowType");
43
42
  /**
44
43
  * Finos eKYC SDK Module
@@ -199,8 +198,9 @@ class FinosEKYCModule {
199
198
  * @param config.customActions - SDKFaceDetectStatus[] enum (LEFT, RIGHT, SMILE, BLINK, ...). Bên sử dụng truyền enum thay vì string
200
199
  * @param config.activeActionCount - Number of random actions (1-10), only used when customActions is null (default: 2)
201
200
  * @param config.switchFrontCamera - Use front camera (default: false)
201
+ * @param exitConfirmConfig - Optional config tuỳ chỉnh bottom sheet xác nhận thoát. null = mặc định SDK.
202
202
  */
203
- async startLiveness(config) {
203
+ async startLiveness(config, exitConfirmConfig) {
204
204
  this.validateSDKReady();
205
205
  try {
206
206
  console.log('👁️ Starting liveness detection...');
@@ -213,7 +213,10 @@ class FinosEKYCModule {
213
213
  else if (config.activeActionCount !== undefined) {
214
214
  console.log('🎲 Random actions count:', config.activeActionCount);
215
215
  }
216
- const result = await this.sdk.startLiveness(config);
216
+ if (exitConfirmConfig) {
217
+ console.log('🚪 ExitConfirmConfig:', exitConfirmConfig);
218
+ }
219
+ const result = await this.sdk.startLiveness(config, exitConfirmConfig);
217
220
  console.log('✅ Liveness detection completed:', result.event);
218
221
  react_native_1.DeviceEventEmitter.emit('onLivenessSuccess', {
219
222
  event: 'LIVENESS_SUCCESS',
@@ -283,87 +286,6 @@ class FinosEKYCModule {
283
286
  // Note: This method needs to be implemented in the native module
284
287
  console.log('📱 New intent handled');
285
288
  }
286
- // ==================== Exit Handler ====================
287
- /**
288
- * Register a custom exit confirmation handler to show UI in React Native instead of using native bottom sheet.
289
- */
290
- async registerExitHandler() {
291
- this.validateSDKReady();
292
- try {
293
- console.log('🔗 Registering custom exit handler...');
294
- return await this.sdk.registerExitHandler();
295
- }
296
- catch (error) {
297
- console.error('❌ Failed to register exit handler:', error);
298
- throw error;
299
- }
300
- }
301
- /**
302
- * Resolve the custom exit confirmation.
303
- * @param action 'CONFIRM' (exit SDK), 'CANCEL' or 'CLOSE' (stay in SDK)
304
- */
305
- async resolveExit(action) {
306
- this.validateSDKReady();
307
- try {
308
- console.log('🔙 Resolving exit action:', action);
309
- return await this.sdk.resolveExit(action);
310
- }
311
- catch (error) {
312
- console.error('❌ Failed to resolve exit:', error);
313
- throw error;
314
- }
315
- }
316
- /**
317
- * Set custom component to render inside the exit bottom sheet.
318
- * Thay thế ExitConfirmSheet mặc định bằng component tùy chỉnh.
319
- * Không cần AppRegistry — SDK tự lo phần registration.
320
- *
321
- * @param component React component để hiển thị, hoặc null để về default
322
- *
323
- * @example
324
- * FinosEKYC.setExitSheetComponent(WarningBottomSheet);
325
- */
326
- setExitSheetComponent(component) {
327
- (0, ExitSheetWrapper_1.setCustomExitComponent)(component);
328
- }
329
- /**
330
- * Show the exit bottom sheet on top of the current SDK screen.
331
- * Mặc định dùng 'SDKExitSheetWrapper' (đã register sẵn trong SDK).
332
- *
333
- * @param props Props truyền vào component (optional)
334
- *
335
- * @example
336
- * // Dùng default ExitConfirmSheet
337
- * FinosEKYC.showRNExitSheet();
338
- *
339
- * // Dùng custom component (set trước bằng setExitSheetComponent)
340
- * FinosEKYC.setExitSheetComponent(WarningBottomSheet);
341
- * FinosEKYC.showRNExitSheet();
342
- */
343
- async showRNExitSheet(props = {}) {
344
- this.validateSDKReady();
345
- try {
346
- return await this.sdk.showRNExitSheet('SDKExitSheetWrapper', props);
347
- }
348
- catch (error) {
349
- console.error('❌ Failed to show RN exit sheet:', error);
350
- throw error;
351
- }
352
- }
353
- /**
354
- * Show a native alert dialog on top of the current activity (useful for SDK screens)
355
- * @param config Dialog configuration { title, message, confirmText, cancelText }
356
- */
357
- async showNativeExitDialog(config) {
358
- this.validateSDKReady();
359
- try {
360
- return await this.sdk.showNativeExitDialog(config);
361
- }
362
- catch (error) {
363
- console.error('❌ Failed to show native exit dialog:', error);
364
- throw error;
365
- }
366
- }
367
289
  // ==================== Event Listeners ====================
368
290
  /**
369
291
  * Listen for NFC scan start events
@@ -445,13 +367,6 @@ class FinosEKYCModule {
445
367
  onEkycUIError(callback) {
446
368
  return this.sdk.onEkycUIError(callback);
447
369
  }
448
- /**
449
- * Listen for exit confirm events triggered by the SDK.
450
- * Call resolveExit('CONFIRM' | 'CANCEL' | 'CLOSE') after user chooses an action.
451
- */
452
- onShowExitConfirm(callback) {
453
- return this.sdk.onShowExitConfirm(callback);
454
- }
455
370
  /**
456
371
  * Remove all event listeners
457
372
  */
@@ -757,8 +672,10 @@ class FinosEKYCModule {
757
672
  * @param appKeyConfig Optional app key configuration
758
673
  * @param optionConfig Optional configuration settings (includes switchFrontCamera for camera control)
759
674
  * @param styleConfig Optional style configuration
675
+ * @param exitConfirmConfig Optional config tuỳ chỉnh bottom sheet xác nhận thoát (icon, title, content, buttons).
676
+ * null = giữ default SDK. Xem EXIT_CONFIRM_CONFIG.md.
760
677
  */
761
- async startEkycUI(appKey, flowSDK, language, transactionId, appKeyConfig, optionConfig, styleConfig) {
678
+ async startEkycUI(appKey, flowSDK, language, transactionId, appKeyConfig, optionConfig, styleConfig, exitConfirmConfig) {
762
679
  this.validateSDKReady();
763
680
  try {
764
681
  console.log('🚀 Starting eKYC UI with flow:', flowSDK);
@@ -768,7 +685,10 @@ class FinosEKYCModule {
768
685
  }
769
686
  console.log('🔑 AppKeyConfig:', appKeyConfig);
770
687
  console.log('🎨 StyleConfig:', styleConfig);
771
- const result = await this.sdk.startEkycUI(appKey, (0, ekycFlowType_1.flowToStrings)(flowSDK), language, transactionId, appKeyConfig, optionConfig, styleConfig);
688
+ if (exitConfirmConfig) {
689
+ console.log('🚪 ExitConfirmConfig:', exitConfirmConfig);
690
+ }
691
+ const result = await this.sdk.startEkycUI(appKey, (0, ekycFlowType_1.flowToStrings)(flowSDK), language, transactionId, appKeyConfig, optionConfig, styleConfig, exitConfirmConfig);
772
692
  console.log('✅ eKYC UI started successfully');
773
693
  return result;
774
694
  }
@@ -827,10 +747,7 @@ const isMethod = (prop) => {
827
747
  prop === 'startOcr' ||
828
748
  prop === 'startLiveness' ||
829
749
  prop === 'startFaceCompare' ||
830
- prop === 'registerExitHandler' ||
831
- prop === 'resolveExit' ||
832
- prop === 'showRNExitSheet' ||
833
- prop === 'setExitSheetComponent';
750
+ false;
834
751
  };
835
752
  // Create a comprehensive stub object with all methods to prevent undefined errors
836
753
  const createFinosEKYCStub = () => {
@@ -860,7 +777,6 @@ const createFinosEKYCStub = () => {
860
777
  'startEkycUI', 'sendOtp', 'verifyOtp', 'resendOtp', 'initializeESign', 'openSessionId',
861
778
  'registerDevice', 'listCerts', 'verifyCert', 'listSignRequest', 'confirmSign',
862
779
  'registerRemoteSigning', 'signPdf', 'sendConfirmationDocument',
863
- 'registerExitHandler', 'resolveExit', 'showRNExitSheet', 'setExitSheetComponent',
864
780
  'onResume', 'onPause', 'isSDKReady', 'getSDKInfo'
865
781
  ];
866
782
  otherMethods.forEach(method => {
@@ -0,0 +1,115 @@
1
+ /**
2
+ * ExitConfirmConfig — bottom sheet xác nhận thoát khi user nhấn back trong liveness.
3
+ * Map 1-1 với native ExitConfirmConfig (sdkcore 1.5.2+).
4
+ *
5
+ * Mọi field đều optional — null/undefined = giữ giá trị mặc định của SDK.
6
+ * Xem EXIT_CONFIRM_CONFIG.md để biết chi tiết và giá trị mặc định.
7
+ */
8
+ /** Hướng gradient cho ViewStyle.backgroundGradient*. Map android.graphics.drawable.GradientDrawable.Orientation. */
9
+ export declare enum ExitConfirmGradientOrientation {
10
+ LEFT_RIGHT = "LEFT_RIGHT",
11
+ RIGHT_LEFT = "RIGHT_LEFT",
12
+ TOP_BOTTOM = "TOP_BOTTOM",
13
+ BOTTOM_TOP = "BOTTOM_TOP",
14
+ TL_BR = "TL_BR",
15
+ TR_BL = "TR_BL",
16
+ BL_TR = "BL_TR",
17
+ BR_TL = "BR_TL"
18
+ }
19
+ /** Text style cho title/content/button label. */
20
+ export interface ExitConfirmTextStyles {
21
+ /** Hex màu chữ, vd "#1A1A1A" hoặc "#FF1A1A1A". */
22
+ textColor?: string;
23
+ /** Cỡ chữ đơn vị sp. */
24
+ textSize?: number;
25
+ /** Tên font resource trong res/font/, vd "inter_medium". */
26
+ textFont?: string;
27
+ /** 0 Normal · 1 Bold · 2 Italic · 3 Bold+Italic. */
28
+ textStyle?: number;
29
+ /** android.view.Gravity flag, vd Gravity.CENTER = 17. */
30
+ textAlign?: number;
31
+ }
32
+ /** View style cho background, kích thước, margin, padding, bo góc của container/button. */
33
+ export interface ExitConfirmViewStyle {
34
+ /** Hex màu nền. Bị bỏ qua nếu set gradient. */
35
+ backgroundColor?: string;
36
+ /** Tối thiểu 2 màu hex cho gradient. */
37
+ backgroundGradientColors?: string[];
38
+ /**
39
+ * Vị trí [0.0–1.0] tương ứng từng màu (Android 10+).
40
+ * null = phân bổ đều. Bắt buộc cùng size với backgroundGradientColors.
41
+ */
42
+ backgroundGradientPositions?: number[];
43
+ /** Hướng gradient. Mặc định LEFT_RIGHT. */
44
+ backgroundGradientOrientation?: ExitConfirmGradientOrientation;
45
+ /** dp — null = giữ constraint layout. */
46
+ width?: number;
47
+ /** dp. */
48
+ height?: number;
49
+ marginTop?: number;
50
+ marginBottom?: number;
51
+ marginStart?: number;
52
+ marginEnd?: number;
53
+ paddingTop?: number;
54
+ paddingBottom?: number;
55
+ paddingStart?: number;
56
+ paddingEnd?: number;
57
+ /** android.view.Gravity flag cho nội dung bên trong. */
58
+ gravity?: number;
59
+ /** Bo góc dp. 100f = pill shape. */
60
+ cornerRadius?: number;
61
+ }
62
+ /**
63
+ * Icon phía trên bottom sheet.
64
+ * Native field `icon: Int?` là R.drawable resource ID — RN không truy cập trực tiếp được.
65
+ * Truyền `iconResName` (vd "ic_warning") để native resolve qua getIdentifier().
66
+ * Bỏ qua / null = dùng icon mặc định SDK (ic_bell).
67
+ */
68
+ export interface ExitConfirmIconProps {
69
+ /** Tên drawable resource trong res/drawable/. null/omitted = icon mặc định SDK. */
70
+ iconResName?: string;
71
+ iconViewStyle?: ExitConfirmViewStyle;
72
+ }
73
+ export interface ExitConfirmTitleProps {
74
+ title?: string;
75
+ titleStyles?: ExitConfirmTextStyles;
76
+ }
77
+ export interface ExitConfirmContentProps {
78
+ content?: string;
79
+ contentStyles?: ExitConfirmTextStyles;
80
+ }
81
+ export interface ExitConfirmButtonProps {
82
+ buttonTitle?: string;
83
+ buttonTextStyles?: ExitConfirmTextStyles;
84
+ buttonStyles?: ExitConfirmViewStyle;
85
+ }
86
+ /**
87
+ * Config bottom sheet xác nhận thoát. Truyền vào FinosEKYC.startEkycUI / startLiveness.
88
+ * Mọi field optional — null = SDK default.
89
+ *
90
+ * @example
91
+ * exitConfirmConfig: {
92
+ * titleProps: { title: "Thông báo" },
93
+ * contentProps: { content: "Quý khách muốn thoát?" },
94
+ * confirmButtonProps: {
95
+ * buttonTitle: "Có",
96
+ * buttonStyles: {
97
+ * backgroundGradientColors: ["#DA2128", "#F9A61C", "#FFDD00"],
98
+ * cornerRadius: 100,
99
+ * },
100
+ * },
101
+ * cancelButtonProps: {
102
+ * buttonTitle: "Không",
103
+ * buttonStyles: { backgroundColor: "#F3F4F6", cornerRadius: 100 },
104
+ * },
105
+ * }
106
+ */
107
+ export interface ExitConfirmConfig {
108
+ iconProps?: ExitConfirmIconProps;
109
+ titleProps?: ExitConfirmTitleProps;
110
+ contentProps?: ExitConfirmContentProps;
111
+ /** Nút xác nhận thoát (vd "Có") — chỉ nút này mới trigger callback thoát SDK. */
112
+ confirmButtonProps?: ExitConfirmButtonProps;
113
+ /** Nút huỷ (vd "Không") — đóng sheet, ở lại SDK. */
114
+ cancelButtonProps?: ExitConfirmButtonProps;
115
+ }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ /**
3
+ * ExitConfirmConfig — bottom sheet xác nhận thoát khi user nhấn back trong liveness.
4
+ * Map 1-1 với native ExitConfirmConfig (sdkcore 1.5.2+).
5
+ *
6
+ * Mọi field đều optional — null/undefined = giữ giá trị mặc định của SDK.
7
+ * Xem EXIT_CONFIRM_CONFIG.md để biết chi tiết và giá trị mặc định.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.ExitConfirmGradientOrientation = void 0;
11
+ /** Hướng gradient cho ViewStyle.backgroundGradient*. Map android.graphics.drawable.GradientDrawable.Orientation. */
12
+ var ExitConfirmGradientOrientation;
13
+ (function (ExitConfirmGradientOrientation) {
14
+ ExitConfirmGradientOrientation["LEFT_RIGHT"] = "LEFT_RIGHT";
15
+ ExitConfirmGradientOrientation["RIGHT_LEFT"] = "RIGHT_LEFT";
16
+ ExitConfirmGradientOrientation["TOP_BOTTOM"] = "TOP_BOTTOM";
17
+ ExitConfirmGradientOrientation["BOTTOM_TOP"] = "BOTTOM_TOP";
18
+ ExitConfirmGradientOrientation["TL_BR"] = "TL_BR";
19
+ ExitConfirmGradientOrientation["TR_BL"] = "TR_BL";
20
+ ExitConfirmGradientOrientation["BL_TR"] = "BL_TR";
21
+ ExitConfirmGradientOrientation["BR_TL"] = "BR_TL";
22
+ })(ExitConfirmGradientOrientation || (exports.ExitConfirmGradientOrientation = ExitConfirmGradientOrientation = {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finos_sdk/sdk-ekyc",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
4
4
  "description": "React Native SDK for eKYC - Vietnamese CCCD NFC reading, OCR, Liveness detection, Face matching, and C06, eSign, SmsOTP residence verification",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,7 +1,6 @@
1
1
  import React from 'react';
2
2
  import { Platform, DeviceEventEmitter } from 'react-native';
3
3
  import sdkEKYC, { SDKeKYC, SDK_VERSION, SDK_NAME } from '../../EKYCModule';
4
- import { setCustomExitComponent } from '../components/ExitSheetWrapper';
5
4
  import { NfcConfig, NfcError } from '../types/ekycNFCType';
6
5
  import { SDKEkycResultWithEvent, SDKEkycResultStringWithEvent, EKYCError, getEkycError, AppIDType } from '../types/ekycType';
7
6
  import { C06Config } from '../types/ekycC06Type';
@@ -11,6 +10,7 @@ import { FaceServiceConfig, FaceCompareError, FaceCompareSuccessEvent } from '..
11
10
  import { SmsOtpConfig, SmsOtpResult, SmsOtpError } from '../types/ekycSmsOtpType';
12
11
  import { ESignInitResult, ESignOpenSessionResult, ESignCertificate, ESignSignRequest, ESignError, ESignAuthenticateResult, ESignPdfResult, ESignApiResponse } from '../types/ekycESignType';
13
12
  import { SDKFlowType, flowToStrings } from '../types/ekycFlowType';
13
+ import { ExitConfirmConfig } from '../types/ekycExitConfirmType';
14
14
 
15
15
  /**
16
16
  * Finos eKYC SDK Module
@@ -195,8 +195,12 @@ export class FinosEKYCModule {
195
195
  * @param config.customActions - SDKFaceDetectStatus[] enum (LEFT, RIGHT, SMILE, BLINK, ...). Bên sử dụng truyền enum thay vì string
196
196
  * @param config.activeActionCount - Number of random actions (1-10), only used when customActions is null (default: 2)
197
197
  * @param config.switchFrontCamera - Use front camera (default: false)
198
+ * @param exitConfirmConfig - Optional config tuỳ chỉnh bottom sheet xác nhận thoát. null = mặc định SDK.
198
199
  */
199
- public async startLiveness(config: LivenessConfig): Promise<LivenessSuccessEvent> {
200
+ public async startLiveness(
201
+ config: LivenessConfig,
202
+ exitConfirmConfig?: ExitConfirmConfig
203
+ ): Promise<LivenessSuccessEvent> {
200
204
  this.validateSDKReady();
201
205
 
202
206
  try {
@@ -209,8 +213,11 @@ export class FinosEKYCModule {
209
213
  } else if (config.activeActionCount !== undefined) {
210
214
  console.log('🎲 Random actions count:', config.activeActionCount);
211
215
  }
216
+ if (exitConfirmConfig) {
217
+ console.log('🚪 ExitConfirmConfig:', exitConfirmConfig);
218
+ }
212
219
 
213
- const result = await this.sdk.startLiveness(config);
220
+ const result = await this.sdk.startLiveness(config, exitConfirmConfig);
214
221
  console.log('✅ Liveness detection completed:', result.event);
215
222
  DeviceEventEmitter.emit('onLivenessSuccess', {
216
223
  event: 'LIVENESS_SUCCESS',
@@ -289,96 +296,6 @@ export class FinosEKYCModule {
289
296
  console.log('📱 New intent handled');
290
297
  }
291
298
 
292
- // ==================== Exit Handler ====================
293
-
294
- /**
295
- * Register a custom exit confirmation handler to show UI in React Native instead of using native bottom sheet.
296
- */
297
- public async registerExitHandler(): Promise<boolean> {
298
- this.validateSDKReady();
299
-
300
- try {
301
- console.log('🔗 Registering custom exit handler...');
302
- return await this.sdk.registerExitHandler();
303
- } catch (error) {
304
- console.error('❌ Failed to register exit handler:', error);
305
- throw error;
306
- }
307
- }
308
-
309
- /**
310
- * Resolve the custom exit confirmation.
311
- * @param action 'CONFIRM' (exit SDK), 'CANCEL' or 'CLOSE' (stay in SDK)
312
- */
313
- public async resolveExit(action: 'CONFIRM' | 'CANCEL' | 'CLOSE'): Promise<boolean> {
314
- this.validateSDKReady();
315
-
316
- try {
317
- console.log('🔙 Resolving exit action:', action);
318
- return await this.sdk.resolveExit(action);
319
- } catch (error) {
320
- console.error('❌ Failed to resolve exit:', error);
321
- throw error;
322
- }
323
- }
324
-
325
- /**
326
- * Set custom component to render inside the exit bottom sheet.
327
- * Thay thế ExitConfirmSheet mặc định bằng component tùy chỉnh.
328
- * Không cần AppRegistry — SDK tự lo phần registration.
329
- *
330
- * @param component React component để hiển thị, hoặc null để về default
331
- *
332
- * @example
333
- * FinosEKYC.setExitSheetComponent(WarningBottomSheet);
334
- */
335
- public setExitSheetComponent(component: React.ComponentType<any> | null): void {
336
- setCustomExitComponent(component);
337
- }
338
-
339
- /**
340
- * Show the exit bottom sheet on top of the current SDK screen.
341
- * Mặc định dùng 'SDKExitSheetWrapper' (đã register sẵn trong SDK).
342
- *
343
- * @param props Props truyền vào component (optional)
344
- *
345
- * @example
346
- * // Dùng default ExitConfirmSheet
347
- * FinosEKYC.showRNExitSheet();
348
- *
349
- * // Dùng custom component (set trước bằng setExitSheetComponent)
350
- * FinosEKYC.setExitSheetComponent(WarningBottomSheet);
351
- * FinosEKYC.showRNExitSheet();
352
- */
353
- public async showRNExitSheet(props: any = {}): Promise<boolean> {
354
- this.validateSDKReady();
355
- try {
356
- return await this.sdk.showRNExitSheet('SDKExitSheetWrapper', props);
357
- } catch (error) {
358
- console.error('❌ Failed to show RN exit sheet:', error);
359
- throw error;
360
- }
361
- }
362
-
363
- /**
364
- * Show a native alert dialog on top of the current activity (useful for SDK screens)
365
- * @param config Dialog configuration { title, message, confirmText, cancelText }
366
- */
367
- public async showNativeExitDialog(config: {
368
- title?: string;
369
- message?: string;
370
- confirmText?: string;
371
- cancelText?: string;
372
- }): Promise<'CONFIRM' | 'CANCEL'> {
373
- this.validateSDKReady();
374
- try {
375
- return await this.sdk.showNativeExitDialog(config);
376
- } catch (error) {
377
- console.error('❌ Failed to show native exit dialog:', error);
378
- throw error;
379
- }
380
- }
381
-
382
299
  // ==================== Event Listeners ====================
383
300
  /**
384
301
  * Listen for NFC scan start events
@@ -473,14 +390,6 @@ export class FinosEKYCModule {
473
390
  return this.sdk.onEkycUIError(callback);
474
391
  }
475
392
 
476
- /**
477
- * Listen for exit confirm events triggered by the SDK.
478
- * Call resolveExit('CONFIRM' | 'CANCEL' | 'CLOSE') after user chooses an action.
479
- */
480
- public onShowExitConfirm(callback: () => void) {
481
- return this.sdk.onShowExitConfirm(callback);
482
- }
483
-
484
393
  /**
485
394
  * Remove all event listeners
486
395
  */
@@ -852,6 +761,8 @@ export class FinosEKYCModule {
852
761
  * @param appKeyConfig Optional app key configuration
853
762
  * @param optionConfig Optional configuration settings (includes switchFrontCamera for camera control)
854
763
  * @param styleConfig Optional style configuration
764
+ * @param exitConfirmConfig Optional config tuỳ chỉnh bottom sheet xác nhận thoát (icon, title, content, buttons).
765
+ * null = giữ default SDK. Xem EXIT_CONFIRM_CONFIG.md.
855
766
  */
856
767
  public async startEkycUI(
857
768
  appKey: string,
@@ -921,7 +832,8 @@ export class FinosEKYCModule {
921
832
  };
922
833
  captureButtonColor?: number;
923
834
  captureButtonDisabledColor?: number;
924
- }
835
+ },
836
+ exitConfirmConfig?: ExitConfirmConfig
925
837
  ): Promise<any> {
926
838
  this.validateSDKReady();
927
839
 
@@ -933,6 +845,9 @@ export class FinosEKYCModule {
933
845
  }
934
846
  console.log('🔑 AppKeyConfig:', appKeyConfig);
935
847
  console.log('🎨 StyleConfig:', styleConfig);
848
+ if (exitConfirmConfig) {
849
+ console.log('🚪 ExitConfirmConfig:', exitConfirmConfig);
850
+ }
936
851
 
937
852
  const result = await this.sdk.startEkycUI(
938
853
  appKey,
@@ -941,7 +856,8 @@ export class FinosEKYCModule {
941
856
  transactionId,
942
857
  appKeyConfig,
943
858
  optionConfig,
944
- styleConfig
859
+ styleConfig,
860
+ exitConfirmConfig
945
861
  );
946
862
  console.log('✅ eKYC UI started successfully');
947
863
  return result;
@@ -1002,10 +918,7 @@ const isMethod = (prop: string | symbol): boolean => {
1002
918
  prop === 'startOcr' ||
1003
919
  prop === 'startLiveness' ||
1004
920
  prop === 'startFaceCompare' ||
1005
- prop === 'registerExitHandler' ||
1006
- prop === 'resolveExit' ||
1007
- prop === 'showRNExitSheet' ||
1008
- prop === 'setExitSheetComponent';
921
+ false;
1009
922
  };
1010
923
 
1011
924
  // Create a comprehensive stub object with all methods to prevent undefined errors
@@ -1039,7 +952,6 @@ const createFinosEKYCStub = (): FinosEKYCModule => {
1039
952
  'startEkycUI', 'sendOtp', 'verifyOtp', 'resendOtp', 'initializeESign', 'openSessionId',
1040
953
  'registerDevice', 'listCerts', 'verifyCert', 'listSignRequest', 'confirmSign',
1041
954
  'registerRemoteSigning', 'signPdf', 'sendConfirmationDocument',
1042
- 'registerExitHandler', 'resolveExit', 'showRNExitSheet', 'setExitSheetComponent',
1043
955
  'onResume', 'onPause', 'isSDKReady', 'getSDKInfo'
1044
956
  ];
1045
957