Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions packages/mobile-sdk-alpha/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,12 @@
"react-native": "./dist/animations/loading/*.json",
"import": "./dist/animations/loading/*.json",
"require": "./dist/animations/loading/*.json"
},
"./navigators/onboarding/native-stack": {
"types": "./dist/esm/navigators/onboarding/native-stack.d.ts",
"react-native": "./dist/esm/navigators/onboarding/native-stack.js",
"import": "./dist/esm/navigators/onboarding/native-stack.js",
"require": "./dist/cjs/navigators/onboarding/native-stack.cjs"
}
},
"main": "./dist/cjs/index.cjs",
Expand Down Expand Up @@ -162,6 +168,8 @@
"zustand": "^4.5.2"
},
"devDependencies": {
"@react-navigation/native": "^7.0.14",
"@react-navigation/native-stack": "^7.2.0",
"@testing-library/react": "^14.1.2",
"@types/react": "^18.3.4",
"@types/react-dom": "^18.3.0",
Expand All @@ -181,23 +189,47 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-native": "0.76.9",
"react-native-gesture-handler": "2.19.0",
"react-native-haptic-feedback": "^2.3.3",
"react-native-localize": "^3.5.2",
"react-native-screens": "4.15.3",
"react-native-web": "^0.21.1",
"tsup": "^8.0.1",
"typescript": "^5.9.2",
"vitest": "^2.1.8"
},
"peerDependencies": {
"@react-navigation/native": ">=7.0.0",
"@react-navigation/native-stack": ">=7.0.0",
"lottie-react-native": "7.2.2",
"react": "^18.3.1",
"react-native": "0.76.9",
"react-native-blur-effect": "^1.1.3",
"react-native-gesture-handler": "*",
"react-native-haptic-feedback": "*",
"react-native-localize": "*",
"react-native-safe-area-context": "*",
"react-native-screens": "*",
"react-native-svg": "*",
"react-native-webview": "^13.16.0"
},
"peerDependenciesMeta": {
"@react-navigation/native": {
"optional": true
},
"@react-navigation/native-stack": {
"optional": true
},
"react-native-gesture-handler": {
"optional": true
},
"react-native-safe-area-context": {
"optional": true
},
"react-native-screens": {
"optional": true
}
},
"packageManager": "yarn@4.6.0",
"publishConfig": {
"access": "restricted"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.

import { useCallback, useRef } from 'react';

Check failure on line 5 in packages/mobile-sdk-alpha/src/flows/onboarding/document-camera-screen.tsx

View workflow job for this annotation

GitHub Actions / workspace-lint

Run autofix to sort these imports!

Check failure on line 5 in packages/mobile-sdk-alpha/src/flows/onboarding/document-camera-screen.tsx

View workflow job for this annotation

GitHub Actions / lint

Run autofix to sort these imports!
import { StyleSheet } from 'react-native';
import type { MRZInfo } from 'src/types/public';

import Scan from '../../../svgs/icons/passport_camera_scan.svg';
import Scan from '@selfxyz/mobile-sdk-alpha/svgs/icons/passport_camera_scan.svg';
import passportScanAnimation from '../../animations/passport_scan.json';
import { Additional, Description, SecondaryButton, Title, View, XStack, YStack } from '../../components';
import { DelayedLottieView } from '../../components/DelayedLottieView';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
import type React from 'react';
import { StyleSheet } from 'react-native';

import AadhaarLogo from '../../../svgs/icons/aadhaar.svg';
import EPassportLogoRounded from '../../../svgs/icons/epassport_rounded.svg';
import PlusIcon from '../../../svgs/icons/plus.svg';
import SelfLogo from '../../../svgs/logo.svg';
import AadhaarLogo from '@selfxyz/mobile-sdk-alpha/svgs/icons/aadhaar.svg';
import EPassportLogoRounded from '@selfxyz/mobile-sdk-alpha/svgs/icons/epassport_rounded.svg';
import PlusIcon from '@selfxyz/mobile-sdk-alpha/svgs/icons/plus.svg';
import SelfLogo from '@selfxyz/mobile-sdk-alpha/svgs/logo.svg';

import { BodyText, RoundFlag, View, XStack, YStack } from '../../components';
import { black, slate100, slate300, slate400, white } from '../../constants/colors';
import { advercase, dinot } from '../../constants/fonts';
Expand Down
137 changes: 137 additions & 0 deletions packages/mobile-sdk-alpha/src/navigators/onboarding/native-stack.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc.
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.

import React, { useEffect } from 'react';

Check failure on line 5 in packages/mobile-sdk-alpha/src/navigators/onboarding/native-stack.tsx

View workflow job for this annotation

GitHub Actions / workspace-lint

Imports "React" are only used as type

Check failure on line 5 in packages/mobile-sdk-alpha/src/navigators/onboarding/native-stack.tsx

View workflow job for this annotation

GitHub Actions / lint

Imports "React" are only used as type

import { useSelfClient } from '../../context';
import CountryPickerScreen from '../../flows/onboarding/country-picker-screen';
import { DocumentCameraScreen } from '../../flows/onboarding/document-camera-screen';
import { DocumentNFCScreen } from '../../flows/onboarding/document-nfc-screen';
import IDSelectionScreen from '../../flows/onboarding/id-selection-screen';
import { SdkEvents } from '../../types/events';

import { useNavigation } from '@react-navigation/native';
import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

export type OnboardingNavigationProp = NativeStackNavigationProp<OnboardingStackParamList>;

export type OnboardingStackParamList = {
CountryPicker: undefined;
IDSelection: {
countryCode: string;
countryName: string;
documentTypes: string[];
};
DocumentCamera: {
documentType?: string;
};
DocumentNFC: undefined;
};

const Stack = createNativeStackNavigator<OnboardingStackParamList>();

/**
* Event listener component that bridges SDK events to react-navigation
* Must be rendered inside a screen to access navigation context
*/
function OnboardingNavigationHandler({ children }: { children: React.ReactNode }) {
const navigation = useNavigation<OnboardingNavigationProp>();
const selfClient = useSelfClient();

useEffect(() => {
const unsubscribers = [
// When country is selected, navigate to ID selection or camera
selfClient.on(SdkEvents.DOCUMENT_COUNTRY_SELECTED, payload => {
if (!payload) return;
const { countryCode, countryName, documentTypes } = payload;
if (documentTypes.length === 1) {
// Skip ID selection if only one document type available
navigation.navigate('DocumentCamera', { documentType: documentTypes[0] });
} else {
navigation.navigate('IDSelection', { countryCode, countryName, documentTypes });
}
}),

// When document type is selected, navigate to camera
selfClient.on(SdkEvents.DOCUMENT_TYPE_SELECTED, payload => {
if (!payload) return;
const { documentType } = payload;
navigation.navigate('DocumentCamera', { documentType });
}),

// Add handlers for other navigation events as needed
];

return () => {
unsubscribers.forEach(unsub => unsub());
};
}, [navigation, selfClient]);

return <>{children}</>;
}

/**
* Onboarding flow navigator using React Navigation native stack
*
* This navigator handles the document verification onboarding flow:
* 1. Country selection
* 2. ID type selection (if multiple types available)
* 3. Document camera scan (MRZ)
* 4. NFC scan (optional)
*
* @example
* ```tsx
* import { OnboardingNavigator } from '@selfxyz/mobile-sdk-alpha/navigators/onboarding/native-stack';
*
* <Stack.Navigator>
* <Stack.Screen name="Onboarding" component={OnboardingNavigator} />
* </Stack.Navigator>
* ```
*/
export function OnboardingNavigator() {
return (
<Stack.Navigator
screenOptions={{
headerShown: false,
animation: 'slide_from_right',
gestureEnabled: true,
}}
>
<Stack.Screen name="CountryPicker">
{() => (
<OnboardingNavigationHandler>
<CountryPickerScreen insets={{ top: 0, bottom: 0 }} />
</OnboardingNavigationHandler>
)}
</Stack.Screen>

<Stack.Screen name="IDSelection">
{({ route }) => (
<OnboardingNavigationHandler>
<IDSelectionScreen countryCode={route.params.countryCode} documentTypes={route.params.documentTypes} />
</OnboardingNavigationHandler>
)}
</Stack.Screen>

<Stack.Screen name="DocumentCamera">
{() => (
<OnboardingNavigationHandler>
<DocumentCameraScreen safeAreaInsets={{ top: 0, bottom: 0 }} />
</OnboardingNavigationHandler>
)}
</Stack.Screen>

<Stack.Screen name="DocumentNFC">
{() => (
<OnboardingNavigationHandler>
<DocumentNFCScreen safeAreaInsets={{ top: 0, bottom: 0 }} />
</OnboardingNavigationHandler>
)}
</Stack.Screen>
</Stack.Navigator>
);
}

OnboardingNavigator.displayName = 'OnboardingNavigator';
5 changes: 4 additions & 1 deletion packages/mobile-sdk-alpha/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"resolveJsonModule": true,
"verbatimModuleSyntax": false,
"types": ["vitest/globals", "react"],
"rootDir": ".",
"baseUrl": ".",
"paths": {
"@selfxyz/common": ["../../common/dist/esm/index"],
Expand All @@ -26,7 +27,9 @@
"@selfxyz/common/utils/hash/sha": ["../../common/dist/esm/src/utils/hash/sha"],
"@selfxyz/common/utils/passportFormat": ["../../common/dist/esm/src/utils/passports/format"],
"@selfxyz/common/utils/csca": ["../../common/dist/esm/src/utils/csca"],
"@selfxyz/common/utils/passports": ["../../common/dist/esm/src/utils/passports/index"]
"@selfxyz/common/utils/passports": ["../../common/dist/esm/src/utils/passports/index"],
"@selfxyz/mobile-sdk-alpha/svgs/*": ["./dist/svgs/*"],
"@selfxyz/mobile-sdk-alpha/svgs/icons/*": ["./dist/svgs/icons/*"]
}
},
"include": ["src", "tests"]
Expand Down
13 changes: 13 additions & 0 deletions packages/mobile-sdk-alpha/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const entry = {
'hooks/useSafeBottomPadding': 'src/hooks/useSafeBottomPadding.ts',
stores: 'src/stores/index.ts',
'utils/utils': 'src/utils/utils.ts',
'navigators/onboarding/native-stack': 'src/navigators/onboarding/native-stack.tsx',
...flowEntries,
};

Expand Down Expand Up @@ -78,6 +79,12 @@ export default defineConfig([
'lottie-react-native',
'react-native-haptic-feedback',
'react-native-localize',
'react-native-safe-area-context',
'react-native-screens',
'react-native-gesture-handler',
// React Navigation
'@react-navigation/native',
'@react-navigation/native-stack',
// SVG files should be handled by React Native's SVG transformer
/\.svg$/,
],
Expand Down Expand Up @@ -129,6 +136,12 @@ export default defineConfig([
'lottie-react-native',
'react-native-haptic-feedback',
'react-native-localize',
'react-native-safe-area-context',
'react-native-screens',
'react-native-gesture-handler',
// React Navigation
'@react-navigation/native',
'@react-navigation/native-stack',
// SVG files should be handled by React Native's SVG transformer
/\.svg$/,
],
Expand Down
Loading
Loading