Merge pull request #1439 from selfxyz/release/staging-2025-11-20

Release to Staging - 2025-11-20
This commit is contained in:
Justin Hernandez
2025-11-20 20:28:22 -03:00
committed by GitHub
289 changed files with 4328 additions and 2730 deletions

View File

@@ -13,7 +13,7 @@ jobs:
- name: Install gitleaks
uses: gitleaks/gitleaks-action@v2.3.9
with:
config-path: .gitleaks.toml
config-path: gitleaks-override.toml
fail: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -150,9 +150,16 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
# Guard against auto-closed PRs (GitHub reports merged == false when a PR closes without merging)
if: |
(github.event_name != 'pull_request' || github.event.pull_request.merged == true) &&
!contains(github.event.pull_request.labels.*.name, 'deploy:skip')
(
github.event_name != 'pull_request' ||
(github.event.action == 'closed' && github.event.pull_request.merged == true)
) &&
(
github.event_name != 'pull_request' ||
!contains(github.event.pull_request.labels.*.name, 'deploy:skip')
)
outputs:
version: ${{ steps.bump.outputs.version }}
ios_build: ${{ steps.bump.outputs.ios_build }}
@@ -262,7 +269,8 @@ jobs:
contents: read
actions: write
if: |
(github.event_name != 'pull_request' || github.event.pull_request.merged == true) &&
(github.event_name != 'pull_request' ||
(github.event.action == 'closed' && github.event.pull_request.merged == true)) &&
(
(inputs.platform == 'ios' || inputs.platform == 'both') ||
(github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'deploy:android'))
@@ -829,7 +837,8 @@ jobs:
actions: write
id-token: write
if: |
(github.event_name != 'pull_request' || github.event.pull_request.merged == true) &&
(github.event_name != 'pull_request' ||
(github.event.action == 'closed' && github.event.pull_request.merged == true)) &&
(
(inputs.platform == 'android' || inputs.platform == 'both') ||
(github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'deploy:ios'))
@@ -1241,7 +1250,8 @@ jobs:
needs: [bump-version, build-ios, build-android]
if: |
always() &&
(github.event_name != 'pull_request' || github.event.pull_request.merged == true) &&
(github.event_name != 'pull_request' ||
(github.event.action == 'closed' && github.event.pull_request.merged == true)) &&
(needs.build-ios.result == 'success' || needs.build-android.result == 'success')
env:
APP_PATH: ${{ github.workspace }}/app

View File

@@ -6,7 +6,7 @@
f506113a22e5b147132834e4659f5af308448389:app/tests/utils/deeplinks.test.ts:generic-api-key:183
5a67b5cc50f291401d1da4e51706d0cfcf1c2316:app/tests/utils/deeplinks.test.ts:generic-api-key:182
0e4555eee6589aa9cca68f451227b149277d8c90:app/tests/src/utils/points/api.test.ts:generic-api-key:34
feb433e3553f8a7fa6c724b2de5a3e32ef079880:app/ios/Podfile.lock:generic-api-key:2594
3d0e1b4589680df2451031913d067b1b91dafa60:app/ios/Podfile.lock:generic-api-key:2594
3d0e1b4589680df2451031913d067b1b91dafa60:app/tests/utils/deeplinks.test.ts:generic-api-key:208
app/ios/Podfile.lock:generic-api-key:2594
app/tests/src/navigation/deeplinks.test.ts:generic-api-key:208
circuits/circuits/gcp_jwt_verifier/example_jwt.txt:jwt:1
cadd7ae5b768c261230f84426eac879c1853ce70:app/ios/Podfile.lock:generic-api-key:2586

View File

@@ -77,6 +77,8 @@ Gitleaks will scan staged changes on each commit via `yarn gitleaks`.
## Development Documentation
> **Note:** We do not accept text-only pull request changes. While we appreciate the feedback, we will not merge external pull requests that only modify markdown files or code comments (e.g., typo fixes in documentation or comments). Pull requests must include functional code changes.
For detailed development patterns and conventions, see:
- **[Development Patterns](docs/development-patterns.md)** - React Native architecture, navigation, state management, and code organization

View File

@@ -165,6 +165,18 @@ module.exports = {
},
],
// Custom rule to prevent export * (bad for tree shaking)
// This rule prevents the use of export * which disables tree shaking
// and can significantly increase bundle size. Use selective exports instead.
'no-restricted-syntax': [
'error',
{
selector: 'ExportAllDeclaration',
message:
'export * is forbidden. Use selective exports for better tree shaking. Example: export { specific1, specific2 } from "./module"',
},
],
// Override rules conflicting with TypeScript union formatting
'@typescript-eslint/indent': 'off',
@@ -191,11 +203,11 @@ module.exports = {
{
// Disable export sorting for files with dependency issues
files: [
'src/components/NavBar/BaseNavBar.tsx',
'src/components/navbar/BaseNavBar.tsx',
'src/navigation/index.tsx',
'src/providers/passportDataProvider.tsx',
'src/utils/cloudBackup/helpers.ts',
'src/utils/haptic/index.ts',
'src/services/cloud-backup/helpers.ts',
'src/integrations/haptics/index.ts',
],
rules: {
'sort-exports/sort-exports': 'off',
@@ -268,13 +280,6 @@ module.exports = {
'no-console': 'off',
},
},
{
// Allow require imports for dynamic imports in proving machine
files: ['src/utils/proving/provingMachine.ts'],
rules: {
'@typescript-eslint/no-require-imports': 'off',
},
},
{
// Allow require imports for conditional loading in navigation
files: ['src/navigation/index.tsx'],

View File

@@ -19,6 +19,11 @@ import {
TURNKEY_ORGANIZATION_ID,
} from './env';
import ErrorBoundary from './src/components/ErrorBoundary';
import { initSentry, wrapWithSentry } from './src/config/sentry';
import {
TURNKEY_OAUTH_REDIRECT_URI_ANDROID,
TURNKEY_OAUTH_REDIRECT_URI_IOS,
} from './src/devtools/mocks';
import AppNavigation from './src/navigation';
import { AuthProvider } from './src/providers/authProvider';
import { DatabaseProvider } from './src/providers/databaseProvider';
@@ -28,11 +33,6 @@ import { NotificationTrackingProvider } from './src/providers/notificationTracki
import { PassportProvider } from './src/providers/passportDataProvider';
import { RemoteConfigProvider } from './src/providers/remoteConfigProvider';
import { SelfClientProvider } from './src/providers/selfClientProvider';
import { initSentry, wrapWithSentry } from './src/Sentry';
import {
TURNKEY_OAUTH_REDIRECT_URI_ANDROID,
TURNKEY_OAUTH_REDIRECT_URI_IOS,
} from './src/utils/constants';
import 'react-native-get-random-values';
import 'react-native-url-polyfill/auto';

View File

@@ -22,7 +22,7 @@ GEM
artifactory (3.0.17)
atomos (0.1.3)
aws-eventstream (1.4.0)
aws-partitions (1.1183.0)
aws-partitions (1.1184.0)
aws-sdk-core (3.237.0)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.992.0)

View File

@@ -135,7 +135,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 121
versionName "2.9.1"
versionName "2.9.2"
manifestPlaceholders = [appAuthRedirectScheme: 'com.proofofpassportapp']
externalNativeBuild {
cmake {

71
app/babel.config.test.cjs Normal file
View File

@@ -0,0 +1,71 @@
// 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.
// Babel config for Jest tests that excludes hermes-parser to avoid WebAssembly issues
// Based on React Native babel preset but with hermes parser plugin removed
module.exports = {
presets: [
[
'@babel/preset-env',
{
targets: {
node: 'current',
},
},
],
'@babel/preset-typescript',
[
'@babel/preset-react',
{
runtime: 'automatic',
},
],
],
plugins: [
// Module resolver for @ alias
[
'module-resolver',
{
root: ['./src'],
alias: { '@': './src' },
},
],
// Core React Native transforms (minimal set needed for tests)
['@babel/plugin-transform-class-properties', { loose: true }],
['@babel/plugin-transform-classes', { loose: true }],
['@babel/plugin-transform-private-methods', { loose: true }],
['@babel/plugin-transform-private-property-in-object', { loose: true }],
'@babel/plugin-syntax-dynamic-import',
'@babel/plugin-syntax-export-default-from',
'@babel/plugin-transform-export-namespace-from',
'@babel/plugin-transform-unicode-regex',
['@babel/plugin-transform-destructuring', { useBuiltIns: true }],
'@babel/plugin-transform-spread',
[
'@babel/plugin-transform-object-rest-spread',
{ loose: true, useBuiltIns: true },
],
['@babel/plugin-transform-optional-chaining', { loose: true }],
['@babel/plugin-transform-nullish-coalescing-operator', { loose: true }],
['@babel/plugin-transform-logical-assignment-operators', { loose: true }],
// Flow type stripping to support React Native's Flow-based sources
['@babel/plugin-syntax-flow'],
['@babel/plugin-transform-flow-strip-types', { allowDeclareFields: true }],
// Environment variable support
[
'module:react-native-dotenv',
{
moduleName: '@env',
path: '.env',
blacklist: null,
whitelist: null,
safe: false,
allowUndefined: true,
},
],
],
};

View File

@@ -19,7 +19,7 @@ import App from './App';
import { name as appName } from './app.json';
import tamaguiConfig from './tamagui.config';
import './src/utils/ethers';
import './src/utils/crypto/ethers';
import 'react-native-gesture-handler';
// Set global Buffer before any other imports

View File

@@ -21,7 +21,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>2.9.1</string>
<string>2.9.2</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>

View File

@@ -1465,7 +1465,7 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- react-native-app-auth (8.0.3):
- react-native-app-auth (8.1.0):
- AppAuth (>= 1.7.6)
- React-Core
- react-native-biometrics (3.0.1):
@@ -1560,7 +1560,7 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- react-native-safe-area-context (5.6.1):
- react-native-safe-area-context (5.6.2):
- DoubleConversion
- glog
- hermes-engine
@@ -1573,8 +1573,8 @@ PODS:
- React-featureflags
- React-graphics
- React-ImageManager
- react-native-safe-area-context/common (= 5.6.1)
- react-native-safe-area-context/fabric (= 5.6.1)
- react-native-safe-area-context/common (= 5.6.2)
- react-native-safe-area-context/fabric (= 5.6.2)
- React-NativeModulesApple
- React-RCTFabric
- React-rendererdebug
@@ -1583,7 +1583,7 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- react-native-safe-area-context/common (5.6.1):
- react-native-safe-area-context/common (5.6.2):
- DoubleConversion
- glog
- hermes-engine
@@ -1604,7 +1604,7 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- react-native-safe-area-context/fabric (5.6.1):
- react-native-safe-area-context/fabric (5.6.2):
- DoubleConversion
- glog
- hermes-engine
@@ -2021,7 +2021,7 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- RNLocalize (3.5.3):
- RNLocalize (3.6.0):
- DoubleConversion
- glog
- hermes-engine
@@ -2131,7 +2131,7 @@ PODS:
- ReactCommon/turbomodule/core
- Sentry/HybridSDK (= 8.53.2)
- Yoga
- RNSVG (15.14.0):
- RNSVG (15.15.0):
- DoubleConversion
- glog
- hermes-engine
@@ -2151,9 +2151,9 @@ PODS:
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- RNSVG/common (= 15.14.0)
- RNSVG/common (= 15.15.0)
- Yoga
- RNSVG/common (15.14.0):
- RNSVG/common (15.15.0):
- DoubleConversion
- glog
- hermes-engine
@@ -2583,7 +2583,7 @@ SPEC CHECKSUMS:
React-logger: c4052eb941cca9a097ef01b59543a656dc088559
React-Mapbuffer: 9343a5c14536d4463c80f09a960653d754daae21
React-microtasksnativemodule: c7cafd8f4470cf8a4578ee605daa4c74d3278bf8
react-native-app-auth: eb42594042a25455119a8c57194b4fd25b9352f4
react-native-app-auth: e21c8ee920876b960e38c9381971bd189ebea06b
react-native-biometrics: 43ed5b828646a7862dbc7945556446be00798e7d
react-native-blur: 6334d934a9b5e67718b8f5725c44cc0a12946009
react-native-cloud-storage: 8d89f2bc574cf11068dfd90933905974087fb9e9
@@ -2592,7 +2592,7 @@ SPEC CHECKSUMS:
react-native-netinfo: cec9c4e86083cb5b6aba0e0711f563e2fbbff187
react-native-nfc-manager: 66a00e5ddab9704efebe19d605b1b8afb0bb1bd7
react-native-passkey: 8853c3c635164864da68a6dbbcec7148506c3bcf
react-native-safe-area-context: 90a89cb349c7f8168a707e6452288c2f665b9fd1
react-native-safe-area-context: a7aad44fe544b55e2369a3086e16a01be60ce398
react-native-sqlite-storage: 0c84826214baaa498796c7e46a5ccc9a82e114ed
react-native-webview: 3f45e19f0ffc3701168768a6c37695e0f252410e
React-nativeconfig: 415626a63057638759bcc75e0a96e2e07771a479
@@ -2631,11 +2631,11 @@ SPEC CHECKSUMS:
RNGestureHandler: a63b531307e5b2e6ea21d053a1a7ad4cf9695c57
RNInAppBrowser: 6d3eb68d471b9834335c664704719b8be1bfdb20
RNKeychain: 471ceef8c13f15a5534c3cd2674dbbd9d0680e52
RNLocalize: 7683e450496a5aea9a2dab3745bfefa7341d3f5e
RNLocalize: 4f5e4a46d2bccd04ccb96721e438dcb9de17c2e0
RNReactNativeHapticFeedback: e526ac4a7ca9fb23c7843ea4fd7d823166054c73
RNScreens: 806e1449a8ec63c2a4e4cf8a63cc80203ccda9b8
RNSentry: 6ad982be2c8e32dab912afb4132b6a0d88484ea0
RNSVG: e1cf5a9a5aa12c69f2ec47031defbd87ae7fb697
RNSVG: 39476f26bbbe72ffe6194c6fc8f6acd588087957
segment-analytics-react-native: a0c29c75ede1989118b50cac96b9495ea5c91a1d
Sentry: 59993bffde4a1ac297ba6d268dc4bbce068d7c1b
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748

View File

@@ -546,7 +546,7 @@
"$(PROJECT_DIR)",
"$(PROJECT_DIR)/MoproKit/Libs",
);
MARKETING_VERSION = 2.9.1;
MARKETING_VERSION = 2.9.2;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -686,7 +686,7 @@
"$(PROJECT_DIR)",
"$(PROJECT_DIR)/MoproKit/Libs",
);
MARKETING_VERSION = 2.9.1;
MARKETING_VERSION = 2.9.2;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",

View File

@@ -3,8 +3,18 @@
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
module.exports = {
preset: 'react-native',
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'cjs', 'json', 'node'],
moduleFileExtensions: [
'ios.js',
'android.js',
'native.js',
'ts',
'tsx',
'js',
'jsx',
'cjs',
'json',
'node',
],
transformIgnorePatterns: [
'node_modules/(?!(react-native|@react-native|@react-navigation|@react-native-community|@segment/analytics-react-native|@openpassport|react-native-keychain|react-native-check-version|react-native-nfc-manager|react-native-passport-reader|react-native-gesture-handler|uuid|@stablelib|@react-native-google-signin|react-native-cloud-storage|@react-native-clipboard|@react-native-firebase|@selfxyz|@sentry|@anon-aadhaar|react-native-svg|react-native-svg-circle-country-flags)/)',
],
@@ -16,6 +26,7 @@ module.exports = {
testPathIgnorePatterns: [
'/node_modules/',
'/scripts/tests/', // Node.js native test runner tests
'/babel\\.config\\.test\\.cjs',
],
moduleNameMapper: {
'^@env$': '<rootDir>/tests/__setup__/@env.js',
@@ -50,7 +61,7 @@ module.exports = {
'<rootDir>/../common/node_modules/@anon-aadhaar/core/dist/index.js',
},
transform: {
'\\.[jt]sx?$': 'babel-jest',
'\\.[jt]sx?$': ['babel-jest', { configFile: './babel.config.test.cjs' }],
},
globals: {
'ts-jest': {

View File

@@ -282,17 +282,13 @@ jest.mock(
// Mock react-native-gesture-handler to prevent getConstants errors
jest.mock('react-native-gesture-handler', () => {
const React = require('react');
// Avoid requiring React to prevent nested require memory issues
// Mock the components directly without requiring react-native
// to avoid triggering hermes-parser WASM errors
const MockScrollView = props =>
React.createElement('ScrollView', props, props.children);
const MockTouchableOpacity = props =>
React.createElement('TouchableOpacity', props, props.children);
const MockTouchableHighlight = props =>
React.createElement('TouchableHighlight', props, props.children);
const MockFlatList = props => React.createElement('FlatList', props);
// Mock the components as simple pass-through functions
const MockScrollView = jest.fn(props => props.children || null);
const MockTouchableOpacity = jest.fn(props => props.children || null);
const MockTouchableHighlight = jest.fn(props => props.children || null);
const MockFlatList = jest.fn(props => null);
return {
...jest.requireActual('react-native-gesture-handler/jestSetup'),
@@ -306,13 +302,11 @@ jest.mock('react-native-gesture-handler', () => {
// Mock react-native-safe-area-context
jest.mock('react-native-safe-area-context', () => {
const React = require('react');
// Use React.createElement directly instead of requiring react-native to avoid memory issues
// Avoid requiring React to prevent nested require memory issues
return {
__esModule: true,
SafeAreaProvider: ({ children }) =>
React.createElement('View', null, children),
SafeAreaView: ({ children }) => React.createElement('View', null, children),
SafeAreaProvider: jest.fn(({ children }) => children || null),
SafeAreaView: jest.fn(({ children }) => children || null),
useSafeAreaInsets: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
};
});
@@ -766,8 +760,8 @@ const NativeModules = {
// Make it available globally for any code that expects it
global.NativeModules = NativeModules;
// Mock @/utils/passportReader to properly expose the interface expected by tests
jest.mock('./src/utils/passportReader', () => {
// Mock @/integrations/nfc/passportReader to properly expose the interface expected by tests
jest.mock('./src/integrations/nfc/passportReader', () => {
const mockScanPassport = jest.fn();
// Mock the parameter count for scanPassport (iOS native method takes 9 parameters)
Object.defineProperty(mockScanPassport, 'length', { value: 9 });
@@ -903,53 +897,106 @@ jest.mock('react-native-localize', () => ({
languageTag: 'en-US',
isRTL: false,
}),
default: {
getLocales: jest.fn().mockReturnValue([
{
countryCode: 'US',
languageTag: 'en-US',
languageCode: 'en',
isRTL: false,
},
]),
getCountry: jest.fn().mockReturnValue('US'),
getTimeZone: jest.fn().mockReturnValue('America/New_York'),
getCurrencies: jest.fn().mockReturnValue(['USD']),
getTemperatureUnit: jest.fn().mockReturnValue('celsius'),
getFirstWeekDay: jest.fn().mockReturnValue(0),
uses24HourClock: jest.fn().mockReturnValue(false),
usesMetricSystem: jest.fn().mockReturnValue(false),
findBestAvailableLanguage: jest.fn().mockReturnValue({
languageTag: 'en-US',
isRTL: false,
}),
},
}));
jest.mock('./src/utils/notifications/notificationService', () =>
// Ensure mobile-sdk-alpha's bundled react-native-localize dependency is mocked as well
jest.mock(
'../packages/mobile-sdk-alpha/node_modules/react-native-localize',
() => ({
getLocales: jest.fn().mockReturnValue([
{
countryCode: 'US',
languageTag: 'en-US',
languageCode: 'en',
isRTL: false,
},
]),
getCountry: jest.fn().mockReturnValue('US'),
getTimeZone: jest.fn().mockReturnValue('America/New_York'),
getCurrencies: jest.fn().mockReturnValue(['USD']),
getTemperatureUnit: jest.fn().mockReturnValue('celsius'),
getFirstWeekDay: jest.fn().mockReturnValue(0),
uses24HourClock: jest.fn().mockReturnValue(false),
usesMetricSystem: jest.fn().mockReturnValue(false),
findBestAvailableLanguage: jest.fn().mockReturnValue({
languageTag: 'en-US',
isRTL: false,
}),
default: {
getLocales: jest.fn().mockReturnValue([
{
countryCode: 'US',
languageTag: 'en-US',
languageCode: 'en',
isRTL: false,
},
]),
getCountry: jest.fn().mockReturnValue('US'),
getTimeZone: jest.fn().mockReturnValue('America/New_York'),
getCurrencies: jest.fn().mockReturnValue(['USD']),
getTemperatureUnit: jest.fn().mockReturnValue('celsius'),
getFirstWeekDay: jest.fn().mockReturnValue(0),
uses24HourClock: jest.fn().mockReturnValue(false),
usesMetricSystem: jest.fn().mockReturnValue(false),
findBestAvailableLanguage: jest.fn().mockReturnValue({
languageTag: 'en-US',
isRTL: false,
}),
},
}),
);
jest.mock('./src/services/notifications/notificationService', () =>
require('./tests/__setup__/notificationServiceMock.js'),
);
// Mock react-native-svg
jest.mock('react-native-svg', () => {
const React = require('react');
// Avoid requiring React to prevent nested require memory issues
// Mock SvgXml component that handles XML strings
const SvgXml = React.forwardRef(
({ xml, width, height, style, ...props }, ref) => {
return React.createElement('div', {
ref,
style: {
width: width || 'auto',
height: height || 'auto',
display: 'inline-block',
...style,
},
dangerouslySetInnerHTML: { __html: xml },
...props,
});
},
);
const SvgXml = jest.fn(() => null);
SvgXml.displayName = 'SvgXml';
return {
__esModule: true,
default: SvgXml,
SvgXml,
Svg: props => React.createElement('Svg', props, props.children),
Circle: props => React.createElement('Circle', props, props.children),
Path: props => React.createElement('Path', props, props.children),
G: props => React.createElement('G', props, props.children),
Rect: props => React.createElement('Rect', props, props.children),
Defs: props => React.createElement('Defs', props, props.children),
LinearGradient: props =>
React.createElement('LinearGradient', props, props.children),
Stop: props => React.createElement('Stop', props, props.children),
ClipPath: props => React.createElement('ClipPath', props, props.children),
Polygon: props => React.createElement('Polygon', props, props.children),
Polyline: props => React.createElement('Polyline', props, props.children),
Line: props => React.createElement('Line', props, props.children),
Text: props => React.createElement('Text', props, props.children),
TSpan: props => React.createElement('TSpan', props, props.children),
Svg: jest.fn(() => null),
Circle: jest.fn(() => null),
Path: jest.fn(() => null),
G: jest.fn(() => null),
Rect: jest.fn(() => null),
Defs: jest.fn(() => null),
LinearGradient: jest.fn(() => null),
Stop: jest.fn(() => null),
ClipPath: jest.fn(() => null),
Polygon: jest.fn(() => null),
Polyline: jest.fn(() => null),
Line: jest.fn(() => null),
Text: jest.fn(() => null),
TSpan: jest.fn(() => null),
};
});
@@ -998,12 +1045,11 @@ jest.mock('@react-navigation/core', () => {
});
// Mock react-native-webview globally to avoid ESM parsing and native behaviors
// Note: Individual test files can override this with their own more specific mocks
jest.mock('react-native-webview', () => {
const React = require('react');
// Use React.createElement directly instead of requiring react-native to avoid memory issues
const MockWebView = React.forwardRef((props, ref) => {
return React.createElement('View', { ref, testID: 'webview', ...props });
});
// Avoid requiring React to prevent nested require memory issues
// Return a simple pass-through mock - tests can override with JSX mocks if needed
const MockWebView = jest.fn(() => null);
MockWebView.displayName = 'MockWebView';
return {
__esModule: true,
@@ -1014,15 +1060,12 @@ jest.mock('react-native-webview', () => {
// Mock ExpandableBottomLayout to simple containers to avoid SDK internals in tests
jest.mock('@/layouts/ExpandableBottomLayout', () => {
const React = require('react');
// Use React.createElement directly instead of requiring react-native to avoid memory issues
const Layout = ({ children }) => React.createElement('View', null, children);
const TopSection = ({ children }) =>
React.createElement('View', null, children);
const BottomSection = ({ children }) =>
React.createElement('View', null, children);
const FullSection = ({ children }) =>
React.createElement('View', null, children);
// Avoid requiring React to prevent nested require memory issues
// These need to pass through children so WebView is rendered
const Layout = ({ children, ...props }) => children;
const TopSection = ({ children, ...props }) => children;
const BottomSection = ({ children, ...props }) => children;
const FullSection = ({ children, ...props }) => children;
return {
__esModule: true,
ExpandableBottomLayout: { Layout, TopSection, BottomSection, FullSection },
@@ -1031,21 +1074,26 @@ jest.mock('@/layouts/ExpandableBottomLayout', () => {
// Mock mobile-sdk-alpha components used by NavBar (Button, XStack)
jest.mock('@selfxyz/mobile-sdk-alpha/components', () => {
const React = require('react');
// Use React.createElement directly instead of requiring react-native to avoid memory issues
const Button = ({ children, onPress, icon, ...props }) =>
React.createElement(
'TouchableOpacity',
{ onPress, ...props, testID: 'msdk-button' },
icon
? React.createElement('View', { testID: 'msdk-button-icon' }, icon)
: null,
children,
// Avoid requiring React to prevent nested require memory issues
// Create mock components that work with React testing library
// Button needs to render a host element with onPress so tests can interact with it
const Button = jest.fn(({ testID, icon, onPress, children, ...props }) => {
// Render as a mock-touchable-opacity host element so fireEvent.press works
// This allows tests to query by testID and press the button
return (
<mock-touchable-opacity testID={testID} onPress={onPress} {...props}>
{icon || children || null}
</mock-touchable-opacity>
);
const XStack = ({ children, ...props }) =>
React.createElement('View', { ...props, testID: 'msdk-xstack' }, children);
const Text = ({ children, ...props }) =>
React.createElement('Text', { ...props }, children);
});
Button.displayName = 'MockButton';
const XStack = jest.fn(({ children, ...props }) => children || null);
XStack.displayName = 'MockXStack';
const Text = jest.fn(({ children, ...props }) => children || null);
Text.displayName = 'MockText';
return {
__esModule: true,
Button,
@@ -1055,18 +1103,110 @@ jest.mock('@selfxyz/mobile-sdk-alpha/components', () => {
};
});
// Mock Tamagui to avoid hermes-parser WASM memory issues during transformation
jest.mock('tamagui', () => {
// Avoid requiring React to prevent nested require memory issues
// Create mock components that work with React testing library
// Helper to create a simple pass-through mock component
const createMockComponent = displayName => {
const Component = jest.fn(props => props.children || null);
Component.displayName = displayName;
return Component;
};
// Mock styled function - simplified version that returns the component
const styled = jest.fn(Component => Component);
// Create all Tamagui component mocks
const Button = createMockComponent('MockButton');
const XStack = createMockComponent('MockXStack');
const YStack = createMockComponent('MockYStack');
const ZStack = createMockComponent('MockZStack');
const Text = createMockComponent('MockText');
const View = createMockComponent('MockView');
const ScrollView = createMockComponent('MockScrollView');
const Spinner = createMockComponent('MockSpinner');
const Image = createMockComponent('MockImage');
const Card = createMockComponent('MockCard');
const Separator = createMockComponent('MockSeparator');
const TextArea = createMockComponent('MockTextArea');
const Input = createMockComponent('MockInput');
const Anchor = createMockComponent('MockAnchor');
// Mock Select component with nested components
const Select = Object.assign(createMockComponent('MockSelect'), {
Trigger: createMockComponent('MockSelectTrigger'),
Value: createMockComponent('MockSelectValue'),
Content: createMockComponent('MockSelectContent'),
Item: createMockComponent('MockSelectItem'),
Group: createMockComponent('MockSelectGroup'),
Label: createMockComponent('MockSelectLabel'),
Viewport: createMockComponent('MockSelectViewport'),
ScrollUpButton: createMockComponent('MockSelectScrollUpButton'),
ScrollDownButton: createMockComponent('MockSelectScrollDownButton'),
});
// Mock Sheet component with nested components
const Sheet = Object.assign(createMockComponent('MockSheet'), {
Frame: createMockComponent('MockSheetFrame'),
Overlay: createMockComponent('MockSheetOverlay'),
Handle: createMockComponent('MockSheetHandle'),
ScrollView: createMockComponent('MockSheetScrollView'),
});
// Mock Adapt component
const Adapt = createMockComponent('MockAdapt');
// Mock TamaguiProvider - simple pass-through that renders children
const TamaguiProvider = jest.fn(({ children }) => children || null);
TamaguiProvider.displayName = 'MockTamaguiProvider';
// Mock configuration factory functions
const createFont = jest.fn(() => ({}));
const createTamagui = jest.fn(() => ({}));
return {
__esModule: true,
styled,
Button,
XStack,
YStack,
ZStack,
Text,
View,
ScrollView,
Spinner,
Image,
Card,
Separator,
TextArea,
Input,
Anchor,
Select,
Sheet,
Adapt,
TamaguiProvider,
createFont,
createTamagui,
// Provide default exports for other common components
default: jest.fn(() => null),
};
});
// Mock Tamagui lucide icons to simple components to avoid theme context
jest.mock('@tamagui/lucide-icons', () => {
const React = require('react');
// Use React.createElement directly instead of requiring react-native to avoid memory issues
// Avoid requiring React to prevent nested require memory issues
// Return mock components that can be queried by testID
const makeIcon = name => {
const Icon = ({ size, color, opacity }) =>
React.createElement('View', {
testID: `icon-${name}`,
size,
color,
opacity,
});
// Use a mock element tag that React can render
const Icon = props => ({
$$typeof: Symbol.for('react.element'),
type: `mock-icon-${name}`,
props: { testID: `icon-${name}`, ...props },
key: null,
ref: null,
});
Icon.displayName = `MockIcon(${name})`;
return Icon;
};
@@ -1074,14 +1214,13 @@ jest.mock('@tamagui/lucide-icons', () => {
__esModule: true,
ExternalLink: makeIcon('external-link'),
X: makeIcon('x'),
Clipboard: makeIcon('clipboard'),
};
});
// Mock WebViewFooter to avoid SDK rendering complexity
jest.mock('@/components/WebViewFooter', () => {
const React = require('react');
// Use React.createElement directly instead of requiring react-native to avoid memory issues
const WebViewFooter = () =>
React.createElement('View', { testID: 'webview-footer' });
// Avoid requiring React to prevent nested require memory issues
const WebViewFooter = jest.fn(() => null);
return { __esModule: true, WebViewFooter };
});

View File

@@ -1,6 +1,6 @@
{
"name": "@selfxyz/mobile-app",
"version": "2.9.1",
"version": "2.9.2",
"private": true,
"type": "module",
"scripts": {
@@ -56,17 +56,18 @@
"sync-versions": "bundle exec fastlane ios sync_version && bundle exec fastlane android sync_version",
"tag:release": "node scripts/tag.cjs release",
"tag:remove": "node scripts/tag.cjs remove",
"test": "yarn build:deps && jest --passWithNoTests && node --test scripts/tests/*.cjs",
"test": "yarn build:deps && yarn jest:run --passWithNoTests && node --test scripts/tests/*.cjs",
"test:build": "yarn build:deps && yarn types && node ./scripts/bundle-analyze-ci.cjs ios && yarn test",
"test:ci": "jest --passWithNoTests && node --test scripts/tests/*.cjs",
"test:coverage": "jest --coverage --passWithNoTests",
"test:coverage:ci": "jest --coverage --passWithNoTests --ci --coverageReporters=lcov --coverageReporters=text --coverageReporters=json",
"test:ci": "yarn jest:run --passWithNoTests && node --test scripts/tests/*.cjs",
"test:coverage": "yarn jest:run --coverage --passWithNoTests",
"test:coverage:ci": "yarn jest:run --coverage --passWithNoTests --ci --coverageReporters=lcov --coverageReporters=text --coverageReporters=json",
"test:e2e:android": "./scripts/mobile-ci-build-android.sh && maestro test tests/e2e/launch.android.flow.yaml",
"test:e2e:ios": "xcodebuild -workspace ios/OpenPassport.xcworkspace -scheme OpenPassport -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build && maestro test tests/e2e/launch.ios.flow.yaml",
"test:fastlane": "bundle exec ruby -Itest fastlane/test/helpers_test.rb",
"test:tree-shaking": "node ./scripts/test-tree-shaking.cjs",
"test:web-build": "jest tests/web-build-render.test.ts --testTimeout=180000",
"test:web-build": "yarn jest:run tests/web-build-render.test.ts --testTimeout=180000",
"types": "tsc --noEmit",
"jest:run": "node ./node_modules/jest/bin/jest.js",
"watch:sdk": "yarn workspace @selfxyz/mobile-sdk-alpha watch",
"web": "vite",
"web:build": "yarn build:deps && vite build",
@@ -168,9 +169,13 @@
},
"devDependencies": {
"@babel/core": "^7.28.3",
"@babel/plugin-syntax-flow": "^7.27.1",
"@babel/plugin-transform-classes": "^7.27.1",
"@babel/plugin-transform-export-namespace-from": "^7.27.1",
"@babel/plugin-transform-flow-strip-types": "^7.27.1",
"@babel/plugin-transform-private-methods": "^7.27.1",
"@babel/preset-env": "^7.28.3",
"@babel/preset-react": "^7.27.1",
"@react-native-community/cli": "^16.0.3",
"@react-native/babel-preset": "0.76.9",
"@react-native/eslint-config": "0.76.9",

View File

@@ -179,14 +179,14 @@ describe('alias-imports transform', () => {
const appRoot = tempRoot;
const srcDir = join(appRoot, 'src');
const testsSrcDir = join(appRoot, 'tests', 'src');
const fileHaptic = join(srcDir, 'utils', 'haptic.ts');
const fileHaptic = join(srcDir, 'integrations', 'haptics.ts');
const deepSpecDir = join(testsSrcDir, 'deep');
const deepSpecFile = join(deepSpecDir, 'spec.ts');
writeFileEnsured(fileHaptic, 'export const h = 1;\n');
writeFileEnsured(
deepSpecFile,
"import { h } from '../../../src/utils/haptic';\nexport const v = h;\n",
"import { h } from '../../../src/integrations/haptics';\nexport const v = h;\n",
);
const project = new Project({
@@ -203,21 +203,24 @@ describe('alias-imports transform', () => {
const specFile = project.getSourceFileOrThrow(deepSpecFile);
const imports = specFile.getImportDeclarations();
assert.strictEqual(imports.length, 1);
assert.strictEqual(imports[0].getModuleSpecifierValue(), '@/utils/haptic');
assert.strictEqual(
imports[0].getModuleSpecifierValue(),
'@/integrations/haptics',
);
});
it("transforms deep relative require '../../../src/...' to @src alias from tests", () => {
const appRoot = tempRoot;
const srcDir = join(appRoot, 'src');
const testsSrcDir = join(appRoot, 'tests', 'src');
const fileHaptic = join(srcDir, 'utils', 'haptic.ts');
const fileHaptic = join(srcDir, 'integrations', 'haptics.ts');
const deepSpecDir = join(testsSrcDir, 'deep');
const deepSpecFile = join(deepSpecDir, 'req.ts');
writeFileEnsured(fileHaptic, 'module.exports = { h: 1 };\n');
writeFileEnsured(
deepSpecFile,
"const h = require('../../../src/utils/haptic');\nexport const v = h;\n",
"const h = require('../../../src/integrations/haptics');\nexport const v = h;\n",
);
const project = new Project({
@@ -232,7 +235,7 @@ describe('alias-imports transform', () => {
transformProjectToAliasImports(project, appRoot);
const specFile = project.getSourceFileOrThrow(deepSpecFile);
assert.ok(specFile.getText().includes("require('@/utils/haptic')"));
assert.ok(specFile.getText().includes("require('@/integrations/haptics')"));
});
it('aliases export star re-exports with ../ from sibling directory', () => {

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

Before

Width:  |  Height:  |  Size: 845 B

After

Width:  |  Height:  |  Size: 845 B

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 444 B

After

Width:  |  Height:  |  Size: 444 B

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 505 B

After

Width:  |  Height:  |  Size: 505 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 105 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 223 B

After

Width:  |  Height:  |  Size: 223 B

View File

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 767 B

After

Width:  |  Height:  |  Size: 767 B

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 326 B

After

Width:  |  Height:  |  Size: 326 B

View File

Before

Width:  |  Height:  |  Size: 162 KiB

After

Width:  |  Height:  |  Size: 162 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 205 KiB

After

Width:  |  Height:  |  Size: 205 KiB

View File

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 152 KiB

View File

Before

Width:  |  Height:  |  Size: 186 KiB

After

Width:  |  Height:  |  Size: 186 KiB

View File

Before

Width:  |  Height:  |  Size: 208 KiB

After

Width:  |  Height:  |  Size: 208 KiB

View File

Before

Width:  |  Height:  |  Size: 839 B

After

Width:  |  Height:  |  Size: 839 B

View File

Before

Width:  |  Height:  |  Size: 860 B

After

Width:  |  Height:  |  Size: 860 B

View File

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

Before

Width:  |  Height:  |  Size: 131 KiB

After

Width:  |  Height:  |  Size: 131 KiB

View File

Before

Width:  |  Height:  |  Size: 468 KiB

After

Width:  |  Height:  |  Size: 468 KiB

View File

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -9,9 +9,9 @@ import type { Country3LetterCode } from '@selfxyz/common/constants';
import { countryCodes } from '@selfxyz/common/constants';
import type { SelfAppDisclosureConfig } from '@selfxyz/common/utils';
import { BodyText } from '@selfxyz/mobile-sdk-alpha/components';
import { slate200, slate500 } from '@selfxyz/mobile-sdk-alpha/constants/colors';
import CheckMark from '@/images/icons/checkmark.svg';
import { slate200, slate500 } from '@/utils/colors';
import CheckMark from '@/assets/icons/checkmark.svg';
interface DisclosureProps {
disclosures: SelfAppDisclosureConfig;

View File

@@ -6,8 +6,8 @@ import type { ErrorInfo } from 'react';
import React, { Component } from 'react';
import { Text, View } from 'react-native';
import { captureException } from '@/Sentry';
import { flushAllAnalytics, trackNfcEvent } from '@/utils/analytics';
import { captureException } from '@/config/sentry';
import { flushAllAnalytics, trackNfcEvent } from '@/services/analytics';
interface Props {
children: React.ReactNode;

View File

@@ -7,9 +7,14 @@ import { Alert, Modal, StyleSheet, Text, TextInput, View } from 'react-native';
import { Button, XStack, YStack } from 'tamagui';
import { Caption } from '@selfxyz/mobile-sdk-alpha/components';
import { black, slate400, white, zinc800, zinc900 } from '@/utils/colors';
import { advercase, dinot } from '@/utils/fonts';
import {
black,
slate400,
white,
zinc800,
zinc900,
} from '@selfxyz/mobile-sdk-alpha/constants/colors';
import { advercase, dinot } from '@selfxyz/mobile-sdk-alpha/constants/fonts';
interface FeedbackModalProps {
visible: boolean;

View File

@@ -12,11 +12,11 @@ import {
SecondaryButton,
Title,
} from '@selfxyz/mobile-sdk-alpha/components';
import { white } from '@selfxyz/mobile-sdk-alpha/constants/colors';
import ModalClose from '@/images/icons/modal_close.svg';
import LogoInversed from '@/images/logo_inversed.svg';
import { white } from '@/utils/colors';
import { confirmTap, impactLight } from '@/utils/haptic';
import ModalClose from '@/assets/icons/modal_close.svg';
import LogoInversed from '@/assets/images/logo_inversed.svg';
import { confirmTap, impactLight } from '@/integrations/haptics';
const ModalBackDrop = styled(View, {
display: 'flex',

View File

@@ -8,9 +8,6 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { Text, View, XStack, YStack } from 'tamagui';
import { DelayedLottieView } from '@selfxyz/mobile-sdk-alpha';
import CloseWarningIcon from '@/images/icons/close-warning.svg';
import Plus from '@/images/icons/plus_slate600.svg';
import {
black,
cyan300,
@@ -19,9 +16,12 @@ import {
white,
zinc500,
zinc900,
} from '@/utils/colors';
import { extraYPadding } from '@/utils/constants';
import { advercase, dinot } from '@/utils/fonts';
} from '@selfxyz/mobile-sdk-alpha/constants/colors';
import { advercase, dinot } from '@selfxyz/mobile-sdk-alpha/constants/fonts';
import CloseWarningIcon from '@/assets/icons/close_warning.svg';
import Plus from '@/assets/icons/plus_slate600.svg';
import { extraYPadding } from '@/utils/styleUtils';
interface LoadingUIProps {
animationSource: LottieView['props']['source'];

View File

@@ -6,7 +6,6 @@ import React, { useCallback, useState } from 'react';
import { Button, Text, XStack, YStack } from 'tamagui';
import Clipboard from '@react-native-clipboard/clipboard';
import { useSettingStore } from '@/stores/settingStore';
import {
black,
slate50,
@@ -15,8 +14,10 @@ import {
slate500,
teal500,
white,
} from '@/utils/colors';
import { confirmTap } from '@/utils/haptic';
} from '@selfxyz/mobile-sdk-alpha/constants/colors';
import { confirmTap } from '@/integrations/haptics';
import { useSettingStore } from '@/stores/settingStore';
interface MnemonicProps {
words?: string[];

View File

@@ -1,8 +0,0 @@
// 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.
export { AadhaarNavBar } from '@/components/NavBar/AadhaarNavBar';
export { DefaultNavBar } from '@/components/NavBar/DefaultNavBar';
export { HomeNavBar } from '@/components/NavBar/HomeNavBar';
export { IdDetailsNavBar } from '@/components/NavBar/IdDetailsNavBar';

View File

@@ -13,10 +13,6 @@ import { Card, Text, View, XStack, YStack } from 'tamagui';
import { useSelfClient } from '@selfxyz/mobile-sdk-alpha';
import { PointEvents } from '@selfxyz/mobile-sdk-alpha/constants/analytics';
import HeartIcon from '@/images/icons/heart.svg';
import StarBlackIcon from '@/images/icons/star_black.svg';
import { usePointEventStore } from '@/stores/pointEventStore';
import {
black,
blue600,
@@ -26,9 +22,13 @@ import {
slate400,
slate500,
white,
} from '@/utils/colors';
import { dinot, plexMono } from '@/utils/fonts';
import type { PointEvent } from '@/utils/points';
} from '@selfxyz/mobile-sdk-alpha/constants/colors';
import { dinot, plexMono } from '@selfxyz/mobile-sdk-alpha/constants/fonts';
import HeartIcon from '@/assets/icons/heart.svg';
import StarBlackIcon from '@/assets/icons/star_black.svg';
import type { PointEvent } from '@/services/points';
import { usePointEventStore } from '@/stores/pointEventStore';
type Section = {
title: string;

View File

@@ -6,8 +6,7 @@ import React from 'react';
import { Text, View } from 'tamagui';
import { Caption } from '@selfxyz/mobile-sdk-alpha/components';
import { slate500 } from '@/utils/colors';
import { slate500 } from '@selfxyz/mobile-sdk-alpha/constants/colors';
export interface TipProps {
title: string;

View File

@@ -6,9 +6,13 @@ import React from 'react';
import { ArrowLeft, ArrowRight, RotateCcw } from '@tamagui/lucide-icons';
import { Button, XStack, YStack } from '@selfxyz/mobile-sdk-alpha/components';
import {
black,
slate50,
slate400,
} from '@selfxyz/mobile-sdk-alpha/constants/colors';
import { black, slate50, slate400 } from '@/utils/colors';
import { buttonTap } from '@/utils/haptic';
import { buttonTap } from '@/integrations/haptics';
export interface WebViewFooterProps {
canGoBack: boolean;

View File

@@ -14,11 +14,6 @@ import {
} from '@selfxyz/common/constants';
import type { PassportData } from '@selfxyz/common/types/passport';
import { isAadhaarDocument, isMRZDocument } from '@selfxyz/common/utils/types';
import AadhaarIcon from '@selfxyz/mobile-sdk-alpha/svgs/icons/aadhaar.svg';
import EPassport from '@selfxyz/mobile-sdk-alpha/svgs/icons/epassport.svg';
import { SvgXml } from '@/components/homeScreen/SvgXmlWrapper';
import LogoGray from '@/images/logo_gray.svg';
import {
black,
slate100,
@@ -26,8 +21,13 @@ import {
slate400,
slate500,
white,
} from '@/utils/colors';
import { dinot, plexMono } from '@/utils/fonts';
} from '@selfxyz/mobile-sdk-alpha/constants/colors';
import { dinot, plexMono } from '@selfxyz/mobile-sdk-alpha/constants/fonts';
import AadhaarIcon from '@selfxyz/mobile-sdk-alpha/svgs/icons/aadhaar.svg';
import EPassport from '@selfxyz/mobile-sdk-alpha/svgs/icons/epassport.svg';
import LogoGray from '@/assets/images/logo_gray.svg';
import { SvgXml } from '@/components/homescreen/SvgXmlWrapper';
// Import the logo SVG as a string
const logoSvg = `<svg width="47" height="46" viewBox="0 0 47 46" fill="none" xmlns="http://www.w3.org/2000/svg">

View File

@@ -4,5 +4,5 @@
// Re-export from the native version - Metro resolver will automatically
// pick the appropriate platform-specific file (.web.tsx or .native.tsx)
export { SvgXml } from '@/components/homeScreen/SvgXmlWrapper.native';
export { default } from '@/components/homeScreen/SvgXmlWrapper.native';
export { SvgXml } from '@/components/homescreen/SvgXmlWrapper.native';
export { default } from '@/components/homescreen/SvgXmlWrapper.native';

View File

@@ -8,12 +8,16 @@ import type { NativeStackHeaderProps } from '@react-navigation/native-stack';
import { ChevronLeft, HelpCircle } from '@tamagui/lucide-icons';
import { Button, XStack, YStack } from '@selfxyz/mobile-sdk-alpha/components';
import {
black,
slate100,
slate300,
} from '@selfxyz/mobile-sdk-alpha/constants/colors';
import { dinot } from '@selfxyz/mobile-sdk-alpha/constants/fonts';
import { NavBar } from '@/components/NavBar/BaseNavBar';
import { black, slate100, slate300 } from '@/utils/colors';
import { extraYPadding } from '@/utils/constants';
import { dinot } from '@/utils/fonts';
import { buttonTap } from '@/utils/haptic';
import { NavBar } from '@/components/navbar/BaseNavBar';
import { buttonTap } from '@/integrations/haptics';
import { extraYPadding } from '@/utils/styleUtils';
export const AadhaarNavBar = (props: NativeStackHeaderProps) => {
const insets = useSafeAreaInsets();

View File

@@ -7,10 +7,11 @@ import type { TextStyle, ViewStyle } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import type { NativeStackHeaderProps } from '@react-navigation/native-stack';
import { NavBar } from '@/components/NavBar/BaseNavBar';
import { white } from '@/utils/colors';
import { extraYPadding } from '@/utils/constants';
import { buttonTap } from '@/utils/haptic';
import { white } from '@selfxyz/mobile-sdk-alpha/constants/colors';
import { NavBar } from '@/components/navbar/BaseNavBar';
import { buttonTap } from '@/integrations/haptics';
import { extraYPadding } from '@/utils/styleUtils';
export const DefaultNavBar = (props: NativeStackHeaderProps) => {
const { goBack, canGoBack } = props.navigation;

View File

@@ -7,9 +7,10 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { useNavigation } from '@react-navigation/native';
import { HelpCircle } from '@tamagui/lucide-icons';
import { NavBar } from '@/components/NavBar/BaseNavBar';
import { slate100 } from '@/utils/colors';
import { dinot } from '@/utils/fonts';
import { slate100 } from '@selfxyz/mobile-sdk-alpha/constants/colors';
import { dinot } from '@selfxyz/mobile-sdk-alpha/constants/fonts';
import { NavBar } from '@/components/navbar/BaseNavBar';
export const DocumentFlowNavBar = ({
title,

View File

@@ -11,14 +11,18 @@ import { Clipboard as ClipboardIcon } from '@tamagui/lucide-icons';
import type { SelfApp } from '@selfxyz/common/utils/appType';
import { useSelfClient } from '@selfxyz/mobile-sdk-alpha';
import {
black,
charcoal,
slate50,
} from '@selfxyz/mobile-sdk-alpha/constants/colors';
import { NavBar } from '@/components/NavBar/BaseNavBar';
import CogHollowIcon from '@/images/icons/cog_hollow.svg';
import PlusCircleIcon from '@/images/icons/plus_circle.svg';
import ScanIcon from '@/images/icons/qr_scan.svg';
import { black, charcoal, slate50 } from '@/utils/colors';
import { extraYPadding } from '@/utils/constants';
import { buttonTap } from '@/utils/haptic';
import CogHollowIcon from '@/assets/icons/cog_hollow.svg';
import PlusCircleIcon from '@/assets/icons/plus_circle.svg';
import ScanIcon from '@/assets/icons/qr_scan.svg';
import { NavBar } from '@/components/navbar/BaseNavBar';
import { buttonTap } from '@/integrations/haptics';
import { extraYPadding } from '@/utils/styleUtils';
export const HomeNavBar = (props: NativeStackHeaderProps) => {
const selfClient = useSelfClient();

View File

@@ -7,11 +7,15 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context';
import type { NativeStackHeaderProps } from '@react-navigation/native-stack';
import { Button, Text, View } from '@selfxyz/mobile-sdk-alpha/components';
import {
black,
charcoal,
slate50,
} from '@selfxyz/mobile-sdk-alpha/constants/colors';
import { NavBar } from '@/components/NavBar/BaseNavBar';
import { black, charcoal, slate50 } from '@/utils/colors';
import { extraYPadding } from '@/utils/constants';
import { buttonTap } from '@/utils/haptic';
import { NavBar } from '@/components/navbar/BaseNavBar';
import { buttonTap } from '@/integrations/haptics';
import { extraYPadding } from '@/utils/styleUtils';
export const IdDetailsNavBar = (props: NativeStackHeaderProps) => {
const insets = useSafeAreaInsets();

View File

@@ -12,20 +12,6 @@ import { HelpCircle } from '@tamagui/lucide-icons';
import { useSelfClient } from '@selfxyz/mobile-sdk-alpha';
import { PointEvents } from '@selfxyz/mobile-sdk-alpha/constants/analytics';
import { PointHistoryList } from '@/components/PointHistoryList';
import { useIncomingPoints, usePoints } from '@/hooks/usePoints';
import { usePointsGuardrail } from '@/hooks/usePointsGuardrail';
import BellWhiteIcon from '@/images/icons/bell_white.svg';
import ClockIcon from '@/images/icons/clock.svg';
import LockWhiteIcon from '@/images/icons/lock_white.svg';
import StarBlackIcon from '@/images/icons/star_black.svg';
import LogoInversed from '@/images/logo_inversed.svg';
import MajongImage from '@/images/majong.png';
import type { RootStackParamList } from '@/navigation';
import { usePointEventStore } from '@/stores/pointEventStore';
import { useSettingStore } from '@/stores/settingStore';
import analytics from '@/utils/analytics';
import {
black,
blue600,
@@ -33,20 +19,34 @@ import {
slate200,
slate500,
white,
} from '@/utils/colors';
import { dinot } from '@/utils/fonts';
import { registerModalCallbacks } from '@/utils/modalCallbackRegistry';
} from '@selfxyz/mobile-sdk-alpha/constants/colors';
import { dinot } from '@selfxyz/mobile-sdk-alpha/constants/fonts';
import BellWhiteIcon from '@/assets/icons/bell_white.svg';
import ClockIcon from '@/assets/icons/clock.svg';
import LockWhiteIcon from '@/assets/icons/lock_white.svg';
import StarBlackIcon from '@/assets/icons/star_black.svg';
import LogoInversed from '@/assets/images/logo_inversed.svg';
import MajongImage from '@/assets/images/majong.png';
import { PointHistoryList } from '@/components/PointHistoryList';
import { useIncomingPoints, usePoints } from '@/hooks/usePoints';
import { usePointsGuardrail } from '@/hooks/usePointsGuardrail';
import type { RootStackParamList } from '@/navigation';
import analytics from '@/services/analytics';
import {
isTopicSubscribed,
requestNotificationPermission,
subscribeToTopics,
} from '@/utils/notifications/notificationService';
} from '@/services/notifications/notificationService';
import {
formatTimeUntilDate,
POINT_VALUES,
recordBackupPointEvent,
recordNotificationPointEvent,
} from '@/utils/points';
import { POINT_VALUES } from '@/utils/points/types';
} from '@/services/points';
import { usePointEventStore } from '@/stores/pointEventStore';
import { useSettingStore } from '@/stores/settingStore';
import { registerModalCallbacks } from '@/utils/modalCallbackRegistry';
const Points: React.FC = () => {
const selfClient = useSelfClient();

View File

@@ -7,11 +7,11 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context';
import type { NativeStackHeaderProps } from '@react-navigation/native-stack';
import { Text, View } from '@selfxyz/mobile-sdk-alpha/components';
import { black, slate50 } from '@selfxyz/mobile-sdk-alpha/constants/colors';
import { NavBar } from '@/components/NavBar/BaseNavBar';
import { black, slate50 } from '@/utils/colors';
import { extraYPadding } from '@/utils/constants';
import { buttonTap } from '@/utils/haptic';
import { NavBar } from '@/components/navbar/BaseNavBar';
import { buttonTap } from '@/integrations/haptics';
import { extraYPadding } from '@/utils/styleUtils';
export const PointsNavBar = (props: NativeStackHeaderProps) => {
const insets = useSafeAreaInsets();

View File

@@ -8,10 +8,10 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { ExternalLink, X } from '@tamagui/lucide-icons';
import { Button, XStack } from '@selfxyz/mobile-sdk-alpha/components';
import { black } from '@selfxyz/mobile-sdk-alpha/constants/colors';
import { dinot } from '@selfxyz/mobile-sdk-alpha/constants/fonts';
import { black } from '@/utils/colors';
import { dinot } from '@/utils/fonts';
import { buttonTap } from '@/utils/haptic';
import { buttonTap } from '@/integrations/haptics';
export interface WebViewNavBarProps {
title?: string;

Some files were not shown because too many files have changed in this diff Show More