diff --git a/README.md b/README.md index d1b6db3..1cf8816 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,7 @@ The iOS podspec URL is derived from the native SDK version this package pins (`d [ "@didit-protocol/sdk-react-native", { - "iosPodspecUrl": "https://raw.githubusercontent.com/didit-protocol/sdk-ios/4.8.0/DiditSDK.podspec" + "iosPodspecUrl": "https://raw.githubusercontent.com/didit-protocol/sdk-ios/4.9.0/DiditSDK.podspec" } ] ``` @@ -200,7 +200,7 @@ didit_sdk_subspec = case $DiditSdkIosVariant else raise "Invalid $DiditSdkIosVariant '#{$DiditSdkIosVariant}'. Supported values: all, core, autodetection, nfc." end -pod didit_sdk_subspec, :podspec => 'https://raw.githubusercontent.com/didit-protocol/sdk-ios/4.8.0/DiditSDK.podspec' +pod didit_sdk_subspec, :podspec => 'https://raw.githubusercontent.com/didit-protocol/sdk-ios/4.9.0/DiditSDK.podspec' ``` ##### Swift Package Manager (optional) @@ -322,6 +322,7 @@ import { startVerification } from '@didit-protocol/sdk-react-native'; // With startVerification — config is the second argument const result = await startVerification('your-session-token', { languageCode: 'es', + showLanguageSelector: true, fontFamily: 'Avenir', loggingEnabled: true, showCloseButton: true, @@ -334,6 +335,7 @@ const result = await startVerificationWithWorkflow('your-workflow-id', { vendorData: 'user-123', config: { languageCode: 'es', + showLanguageSelector: true, loggingEnabled: true, showCloseButton: true, showExitConfirmation: true, @@ -346,6 +348,7 @@ const result = await startVerificationWithWorkflow('your-workflow-id', { | Option | Type | Default | Description | |--------|------|---------|-------------| | `languageCode` | `string` | Device locale | ISO 639-1 language code (e.g. `"en"`, `"fr"`, `"ar"`) | +| `showLanguageSelector` | `boolean` | `false` | Show the web-style language selector on the welcome screen | | `fontFamily` | `string` | System font | Custom font family name | | `loggingEnabled` | `boolean` | `false` | Enable SDK debug logging | | `showCloseButton` | `boolean` | `true` | Show close (X) button on verification step screens | @@ -370,6 +373,14 @@ await startVerification(token, { languageCode: 'fr' }); await startVerification(token); ``` +### `showLanguageSelector` + +Set this to `true` to let users change the verification language from the welcome screen. The selector is hidden by default. + +```tsx +await startVerification(token, { showLanguageSelector: true }); +``` + ### `fontFamily` Overrides the font used throughout the SDK UI. The font must be registered in your app's native configuration: diff --git a/android/build.gradle b/android/build.gradle index 6e5001b..50bb958 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -132,7 +132,7 @@ dependencies { implementation "com.facebook.react:react-android" // Didit native Android SDK - implementation "me.didit:$diditSdkAndroidArtifact:4.8.0" + implementation "me.didit:$diditSdkAndroidArtifact:4.9.0" // Coroutines (required for state flow observation) implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3" diff --git a/android/src/main/java/com/sdkreactnative/SdkReactNativeModule.kt b/android/src/main/java/com/sdkreactnative/SdkReactNativeModule.kt index a02b03b..cad8498 100644 --- a/android/src/main/java/com/sdkreactnative/SdkReactNativeModule.kt +++ b/android/src/main/java/com/sdkreactnative/SdkReactNativeModule.kt @@ -179,6 +179,7 @@ class SdkReactNativeModule(reactContext: ReactApplicationContext) : return Configuration( languageLocale = language, + showLanguageSelector = if (map.hasKey("showLanguageSelector")) map.getBoolean("showLanguageSelector") else false, fontFamily = if (map.hasKey("fontFamily")) map.getString("fontFamily") else null, loggingEnabled = if (map.hasKey("loggingEnabled")) map.getBoolean("loggingEnabled") else false, showCloseButton = if (map.hasKey("showCloseButton")) map.getBoolean("showCloseButton") else true, diff --git a/example-expo/ios/Podfile b/example-expo/ios/Podfile index 12af00a..caf9c29 100644 --- a/example-expo/ios/Podfile +++ b/example-expo/ios/Podfile @@ -30,7 +30,7 @@ target 'DiditExpoExample' do else raise "Invalid $DiditSdkIosVariant '#{$DiditSdkIosVariant}'. Supported values: all, core, autodetection, nfc." end - pod didit_sdk_subspec, :podspec => 'https://raw.githubusercontent.com/didit-protocol/sdk-ios/4.8.0/DiditSDK.podspec' + pod didit_sdk_subspec, :podspec => 'https://raw.githubusercontent.com/didit-protocol/sdk-ios/4.9.0/DiditSDK.podspec' use_expo_modules! diff --git a/ios/DiditSdkBridge.swift b/ios/DiditSdkBridge.swift index f66fb00..8a09dac 100644 --- a/ios/DiditSdkBridge.swift +++ b/ios/DiditSdkBridge.swift @@ -189,6 +189,7 @@ public class DiditSdkBridge: NSObject, @unchecked Sendable { /// Sendable value type that captures config primitives before crossing concurrency boundaries. private struct ParsedConfig: Sendable { let languageCode: String? + let showLanguageSelector: Bool let fontFamily: String? let loggingEnabled: Bool let showCloseButton: Bool @@ -203,6 +204,7 @@ public class DiditSdkBridge: NSObject, @unchecked Sendable { init(_ dict: NSDictionary?) { guard let dict = dict, dict.count > 0 else { self.languageCode = nil + self.showLanguageSelector = false self.fontFamily = nil self.loggingEnabled = false self.showCloseButton = true @@ -216,6 +218,7 @@ public class DiditSdkBridge: NSObject, @unchecked Sendable { return } self.languageCode = dict["languageCode"] as? String + self.showLanguageSelector = dict["showLanguageSelector"] as? Bool ?? false self.fontFamily = dict["fontFamily"] as? String self.loggingEnabled = dict["loggingEnabled"] as? Bool ?? false self.showCloseButton = dict["showCloseButton"] as? Bool ?? true @@ -244,7 +247,8 @@ public class DiditSdkBridge: NSObject, @unchecked Sendable { defaultDocumentCamera: Self.parseCameraLens(defaultDocumentCamera) ?? .back, defaultLivenessCamera: Self.parseCameraLens(defaultLivenessCamera) ?? .front, showDocumentCameraSwitchButton: showDocumentCameraSwitchButton, - showLivenessCameraSwitchButton: showLivenessCameraSwitchButton + showLivenessCameraSwitchButton: showLivenessCameraSwitchButton, + showLanguageSelector: showLanguageSelector ) } diff --git a/package.json b/package.json index 2a24933..e4141c3 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "@didit-protocol/sdk-react-native", - "version": "4.8.0", + "version": "4.9.0", "diditNativeSdkVersions": { - "ios": "4.8.0", - "android": "4.8.0" + "ios": "4.9.0", + "android": "4.9.0" }, "description": "React Native wrapper for Didit Identity Verification SDK", "main": "./lib/commonjs/index.js", diff --git a/release-notes/4.9.0.md b/release-notes/4.9.0.md new file mode 100644 index 0000000..dfed802 --- /dev/null +++ b/release-notes/4.9.0.md @@ -0,0 +1,6 @@ +Adds the opt-in `showLanguageSelector` configuration option. + +When enabled, users can change the verification language from the welcome screen using the same compact, searchable selector as the web verification flow. +The selector remains hidden by default. + +Pins the iOS and Android native SDKs exactly to 4.9.0. diff --git a/src/NativeSdkReactNative.ts b/src/NativeSdkReactNative.ts index e44d0e5..9568b4c 100644 --- a/src/NativeSdkReactNative.ts +++ b/src/NativeSdkReactNative.ts @@ -13,6 +13,8 @@ type EventEmitter = CodegenTypes.EventEmitter; export type VerificationConfig = { /** ISO 639-1 language code (e.g. "en", "fr", "ar"). Maps to SupportedLanguage on native. */ languageCode?: string; + /** Show the language selector on the welcome screen. Default: false. */ + showLanguageSelector?: boolean; /** Custom font family name. Must be registered by the host app. */ fontFamily?: string; /** Enable SDK logging for debugging. Default: false. */ diff --git a/src/__tests__/index.test.tsx b/src/__tests__/index.test.tsx index c86e1cc..6bdf882 100644 --- a/src/__tests__/index.test.tsx +++ b/src/__tests__/index.test.tsx @@ -3,6 +3,7 @@ import type { DiditTransactionResult } from '../types'; jest.mock('../NativeSdkReactNative', () => ({ __esModule: true, default: { + startVerification: jest.fn(), submitTransaction: jest.fn(), getTransaction: jest.fn(), onTransactionUpdated: jest.fn(() => ({ remove: jest.fn() })), @@ -10,8 +11,10 @@ jest.mock('../NativeSdkReactNative', () => ({ })); import NativeSdkReactNative from '../NativeSdkReactNative'; -import { submitTransaction, getTransaction } from '../index'; +import { startVerification, submitTransaction, getTransaction } from '../index'; +const mockStartVerification = + NativeSdkReactNative.startVerification as jest.Mock; const mockSubmit = NativeSdkReactNative.submitTransaction as jest.Mock; const mockGet = NativeSdkReactNative.getTransaction as jest.Mock; const mockOnUpdated = NativeSdkReactNative.onTransactionUpdated as jest.Mock; @@ -50,6 +53,35 @@ function pendingResult( }; } +describe('verification configuration marshalling', () => { + beforeEach(() => { + mockStartVerification.mockReset(); + mockStartVerification.mockResolvedValue({ + type: 'completed', + sessionId: 'test-session', + status: 'Approved', + }); + }); + + it('forwards an enabled language selector to native', async () => { + await startVerification('test-token', { showLanguageSelector: true }); + + expect(mockStartVerification).toHaveBeenCalledWith( + 'test-token', + expect.objectContaining({ showLanguageSelector: true }) + ); + }); + + it('leaves the selector disabled when the option is omitted', async () => { + await startVerification('test-token', {}); + + expect(mockStartVerification).toHaveBeenCalledWith( + 'test-token', + expect.objectContaining({ showLanguageSelector: undefined }) + ); + }); +}); + describe('transaction result marshalling', () => { beforeEach(() => { mockSubmit.mockReset(); diff --git a/src/index.tsx b/src/index.tsx index 4f1e688..a566819 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -148,6 +148,7 @@ export async function startVerification( const nativeConfig = config ? { languageCode: config.languageCode, + showLanguageSelector: config.showLanguageSelector, fontFamily: config.fontFamily, loggingEnabled: config.loggingEnabled, showCloseButton: config.showCloseButton, @@ -192,6 +193,7 @@ export async function startVerificationWithWorkflow( const nativeConfig = options?.config ? { languageCode: options.config.languageCode, + showLanguageSelector: options.config.showLanguageSelector, fontFamily: options.config.fontFamily, loggingEnabled: options.config.loggingEnabled, showCloseButton: options.config.showCloseButton, diff --git a/src/types.ts b/src/types.ts index 1e0a3fb..22edbe9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -120,6 +120,12 @@ export interface DiditConfig { */ languageCode?: string; + /** + * Show the language selector on the verification welcome screen. + * Default: `false`. + */ + showLanguageSelector?: boolean; + /** * Custom font family name to use throughout the SDK UI. * The font must be registered in your app's native configuration.