App polish for 2.9 rd1 (#1359)

* add useSafeBottomPadding

* add bottom padding to dev screen

* use safe bottom padding

* skip uploading if building android bundle locally

* fix tests

* cache fix script

* clean up country picker, fix font color

* sort package jsons, add watcher for mobile sdk

* formatting

* only bump versions for successfull builds

* move all css

* cleaner script

* kill watchers before starting new one
This commit is contained in:
Justin Hernandez
2025-11-07 10:26:08 -08:00
committed by GitHub
parent 394668e5df
commit ccb9e148be
24 changed files with 240 additions and 158 deletions

View File

@@ -52,41 +52,40 @@ secrets-ignore:
- "RSA Private Key" # For mock RSA keys
- "EC Private Key" # For mock EC keys
secret:
ignored_matches:
- match: 2036b4e50ad3042969b290e354d9864465107a14de6f5a36d49f81ea8290def8
name: prebuilt-ios-arm64-apple-ios.private.swiftinterface
- match: 2036b4e50ad3042969b290e354d9864465107a14de6f5a36d49f81ea8290def8
name: prebuilt-ios-arm64-apple-ios.private.swiftinterface
ignored_paths:
- '**/*.swiftinterface'
- '**/*.xcframework/**'
- '**/packages/mobile-sdk-alpha/ios/Frameworks/**'
- '**/OpenSSL.xcframework/**'
- '**/demo-app/**/mock/**'
- common/src/mock_certificates/aadhaar/mockAadhaarCert.ts
- '**/NFCPassportReader.xcframework/**'
- common/src/utils/passports/genMockIdDoc.ts
- '**/tests/**/*.crt'
- '**/mock_certificates/**/*.crt'
- '**/mock_certificates/**/*.key'
- '**/demo-app/**/test-data/**'
- '**/generated/**/*.key'
- '**/SelfSDK.xcframework/**'
- '**/mock/**/*.crt'
- '**/generated/**/*.crt'
- '**/test/**/*.key'
- '**/mock/**/*.key'
- '**/test/**/*.crt'
- '**/test/**/*.pem'
- '**/constants/mockCertificates.ts'
- '**/mock/**/*.pem'
- '**/mock_certificates/**/*.pem'
- '**/mock-data/**'
- '**/packages/mobile-sdk-alpha/ios/SelfSDK/**'
- '**/tests/**/*.key'
- '**/generated/**/*.pem'
- '**/tests/**/*.pem'
- '**/test-data/**'
- common/src/mock_certificates/**
- '**/*.xcframework'
- "**/*.swiftinterface"
- "**/*.xcframework/**"
- "**/packages/mobile-sdk-alpha/ios/Frameworks/**"
- "**/OpenSSL.xcframework/**"
- "**/demo-app/**/mock/**"
- common/src/mock_certificates/aadhaar/mockAadhaarCert.ts
- "**/NFCPassportReader.xcframework/**"
- common/src/utils/passports/genMockIdDoc.ts
- "**/tests/**/*.crt"
- "**/mock_certificates/**/*.crt"
- "**/mock_certificates/**/*.key"
- "**/demo-app/**/test-data/**"
- "**/generated/**/*.key"
- "**/SelfSDK.xcframework/**"
- "**/mock/**/*.crt"
- "**/generated/**/*.crt"
- "**/test/**/*.key"
- "**/mock/**/*.key"
- "**/test/**/*.crt"
- "**/test/**/*.pem"
- "**/constants/mockCertificates.ts"
- "**/mock/**/*.pem"
- "**/mock_certificates/**/*.pem"
- "**/mock-data/**"
- "**/packages/mobile-sdk-alpha/ios/SelfSDK/**"
- "**/tests/**/*.key"
- "**/generated/**/*.pem"
- "**/tests/**/*.pem"
- "**/test-data/**"
- common/src/mock_certificates/**
- "**/*.xcframework"
version: 2

View File

@@ -76,7 +76,7 @@ jobs:
with:
cache-version: ${{ env.GH_CACHE_VERSION }}-${{ env.NODE_VERSION_SANITIZED }}
- name: Build dependencies (cache miss)
# Temporarily disabled due to `yarn types` failures when cache is used.
# Temporarily disabled due to `yarn types` failures when cache is used.
# if: steps.built-deps.outputs.cache-hit != 'true'
run: |
echo "Cache miss for built dependencies. Building now..."

View File

@@ -1276,17 +1276,21 @@ jobs:
const version = JSON.parse(fs.readFileSync('version.json', 'utf8'));
const timestamp = new Date().toISOString();
version.ios.build = $IOS_BUILD;
version.android.build = $ANDROID_BUILD;
// Update lastDeployed timestamp for successful builds
// Only bump build numbers for successful builds
if ('$IOS_SUCCESS' === 'success') {
version.ios.build = $IOS_BUILD;
version.ios.lastDeployed = timestamp;
console.log('✅ Updated iOS lastDeployed timestamp');
console.log('✅ Updated iOS build number to $IOS_BUILD and lastDeployed timestamp');
} else {
console.log('⏭️ Skipped iOS build number bump (build did not succeed)');
}
if ('$ANDROID_SUCCESS' === 'success') {
version.android.build = $ANDROID_BUILD;
version.android.lastDeployed = timestamp;
console.log('✅ Updated Android lastDeployed timestamp');
console.log('✅ Updated Android build number to $ANDROID_BUILD and lastDeployed timestamp');
} else {
console.log('⏭️ Skipped Android build number bump (build did not succeed)');
}
fs.writeFileSync('version.json', JSON.stringify(version, null, 2) + '\n');

View File

@@ -319,7 +319,8 @@ jobs:
echo "::add-mask::${SELFXYZ_INTERNAL_REPO_PAT}"
fi
cd packages/mobile-sdk-demo/ios
pod install
echo "📦 Installing pods via cache-fix script…"
bash scripts/pod-install-with-cache-fix.sh
env:
SELFXYZ_INTERNAL_REPO_PAT: ${{ secrets.SELFXYZ_INTERNAL_REPO_PAT }}
GIT_TERMINAL_PROMPT: 0

View File

@@ -8,7 +8,7 @@ on:
- "sdk/core/package.json"
- "sdk/qrcode/package.json"
- "common/package.json"
- 'packages/mobile-sdk-alpha/package.json'
- "packages/mobile-sdk-alpha/package.json"
- "sdk/qrcode-angular/package.json"
- "contracts/package.json"
workflow_dispatch:

View File

@@ -25,7 +25,7 @@ GEM
artifactory (3.0.17)
atomos (0.1.3)
aws-eventstream (1.4.0)
aws-partitions (1.1179.0)
aws-partitions (1.1181.0)
aws-sdk-core (3.236.0)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.992.0)
@@ -37,7 +37,7 @@ GEM
aws-sdk-kms (1.116.0)
aws-sdk-core (~> 3, >= 3.234.0)
aws-sigv4 (~> 1.5)
aws-sdk-s3 (1.202.0)
aws-sdk-s3 (1.203.0)
aws-sdk-core (~> 3, >= 3.234.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.5)

View File

@@ -306,6 +306,14 @@ platform :android do
skip_upload = options[:skip_upload] == true || options[:skip_upload] == "true"
version_bump = options[:version_bump] || "build"
# Automatically skip uploads in local development (no local permissions for Play Store)
# Uploads must be done by CI/CD machines with proper authentication
if local_development && !skip_upload
skip_upload = true
UI.important("🏠 LOCAL DEVELOPMENT: Automatically skipping Play Store upload")
UI.important(" Uploads require CI/CD machine permissions and will be handled automatically")
end
if local_development
if ENV["ANDROID_KEYSTORE_PATH"].nil?
ENV["ANDROID_KEYSTORE_PATH"] = Fastlane::Helpers.android_create_keystore(android_keystore_path)

View File

@@ -30,6 +30,8 @@ module.exports = {
'<rootDir>/../packages/mobile-sdk-alpha/dist/cjs/index.cjs',
'^@selfxyz/mobile-sdk-alpha/components$':
'<rootDir>/../packages/mobile-sdk-alpha/dist/cjs/components/index.cjs',
'^@selfxyz/mobile-sdk-alpha/hooks$':
'<rootDir>/../packages/mobile-sdk-alpha/dist/cjs/hooks/index.cjs',
'^@selfxyz/mobile-sdk-alpha/onboarding/(.*)$':
'<rootDir>/../packages/mobile-sdk-alpha/dist/cjs/flows/onboarding/$1.cjs',
'^@selfxyz/mobile-sdk-alpha/disclosing/(.*)$':

View File

@@ -50,8 +50,8 @@
"release:patch": "./scripts/release.sh patch",
"setup": "yarn clean:build && yarn install && yarn build:deps && yarn setup:android-deps && cd ios && bundle install && bundle exec pod install --repo-update && cd .. && yarn clean:xcode-env-local",
"setup:android-deps": "node scripts/setup-private-modules.cjs",
"start": "watchman watch-del-all && react-native start",
"start:clean": "watchman watch-del-all && cd android && ./gradlew clean && cd .. && react-native start --reset-cache",
"start": "watchman watch-del-all && yarn watch:sdk & react-native start",
"start:clean": "watchman watch-del-all && cd android && ./gradlew clean && cd .. && yarn watch:sdk & react-native start --reset-cache",
"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",
@@ -66,6 +66,7 @@
"test:tree-shaking": "node ./scripts/test-tree-shaking.cjs",
"test:web-build": "jest tests/web-build-render.test.ts --testTimeout=180000",
"types": "tsc --noEmit",
"watch:sdk": "yarn workspace @selfxyz/mobile-sdk-alpha watch",
"web": "vite",
"web:build": "yarn build:deps && vite build",
"web:preview": "vite preview"

View File

@@ -17,6 +17,8 @@ import { useNavigation } from '@react-navigation/native';
import type { NativeStackScreenProps } from '@react-navigation/native-stack';
import { Check, ChevronDown, ChevronRight } from '@tamagui/lucide-icons';
import { useSafeBottomPadding } from '@selfxyz/mobile-sdk-alpha/hooks';
import BugIcon from '@/images/icons/bug_icon.svg';
import IdIcon from '@/images/icons/id_icon.svg';
import WarningIcon from '@/images/icons/warning.svg';
@@ -295,6 +297,7 @@ const DevSettingsScreen: React.FC<DevSettingsScreenProps> = ({}) => {
const subscribedTopics = useSettingStore(state => state.subscribedTopics);
const [hasNotificationPermission, setHasNotificationPermission] =
useState(false);
const paddingBottom = useSafeBottomPadding(20);
// Check notification permissions on mount
useEffect(() => {
@@ -466,6 +469,7 @@ const DevSettingsScreen: React.FC<DevSettingsScreenProps> = ({}) => {
flex={1}
paddingHorizontal="$4"
paddingTop="$4"
paddingBottom={paddingBottom}
>
<ParameterSection
icon={<IdIcon />}

View File

@@ -14,10 +14,10 @@ import {
SecondaryButton,
} from '@selfxyz/mobile-sdk-alpha/components';
import { AadhaarEvents } from '@selfxyz/mobile-sdk-alpha/constants/analytics';
import { useSafeBottomPadding } from '@selfxyz/mobile-sdk-alpha/hooks';
import { getErrorMessages } from '@selfxyz/mobile-sdk-alpha/onboarding/import-aadhaar';
import WarningIcon from '@/images/warning.svg';
import { useSafeAreaInsets } from '@/mocks/react-native-safe-area-context';
import { black, slate100, slate200, slate500, white } from '@/utils/colors';
import { extraYPadding } from '@/utils/constants';
@@ -31,7 +31,7 @@ type AadhaarUploadErrorRoute = RouteProp<
>;
const AadhaarUploadErrorScreen: React.FC = () => {
const { bottom } = useSafeAreaInsets();
const paddingBottom = useSafeBottomPadding(extraYPadding + 35);
const navigation = useNavigation();
const route = useRoute<AadhaarUploadErrorRoute>();
const { trackEvent } = useSelfClient();
@@ -78,7 +78,7 @@ const AadhaarUploadErrorScreen: React.FC = () => {
<YStack
paddingHorizontal={25}
backgroundColor={white}
paddingBottom={bottom + extraYPadding + 35}
paddingBottom={paddingBottom}
paddingTop={25}
>
<XStack gap="$3" alignItems="stretch">

View File

@@ -12,11 +12,11 @@ import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { useSelfClient } from '@selfxyz/mobile-sdk-alpha';
import { BodyText, PrimaryButton } from '@selfxyz/mobile-sdk-alpha/components';
import { AadhaarEvents } from '@selfxyz/mobile-sdk-alpha/constants/analytics';
import { useSafeBottomPadding } from '@selfxyz/mobile-sdk-alpha/hooks';
import { useAadhaar } from '@selfxyz/mobile-sdk-alpha/onboarding/import-aadhaar';
import { useModal } from '@/hooks/useModal';
import AadhaarImage from '@/images/512w.png';
import { useSafeAreaInsets } from '@/mocks/react-native-safe-area-context';
import type { RootStackParamList } from '@/navigation';
import { slate100, slate200, slate400, slate500, white } from '@/utils/colors';
import { extraYPadding } from '@/utils/constants';
@@ -26,7 +26,7 @@ import {
} from '@/utils/qrScanner';
const AadhaarUploadScreen: React.FC = () => {
const { bottom } = useSafeAreaInsets();
const paddingBottom = useSafeBottomPadding(extraYPadding + 50);
const navigation =
useNavigation<NativeStackNavigationProp<RootStackParamList>>();
@@ -140,11 +140,7 @@ const AadhaarUploadScreen: React.FC = () => {
]);
return (
<YStack
flex={1}
backgroundColor={slate100}
paddingBottom={bottom + extraYPadding + 50}
>
<YStack flex={1} backgroundColor={slate100} paddingBottom={paddingBottom}>
<YStack flex={1} paddingHorizontal={20} paddingTop={20}>
<YStack
flex={1}

View File

@@ -10,15 +10,15 @@ import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { useSelfClient } from '@selfxyz/mobile-sdk-alpha';
import { BodyText, PrimaryButton } from '@selfxyz/mobile-sdk-alpha/components';
import { AadhaarEvents } from '@selfxyz/mobile-sdk-alpha/constants/analytics';
import { useSafeBottomPadding } from '@selfxyz/mobile-sdk-alpha/hooks';
import BlueCheckIcon from '@/images/blue_check.svg';
import { useSafeAreaInsets } from '@/mocks/react-native-safe-area-context';
import type { RootStackParamList } from '@/navigation';
import { black, slate100, slate200, slate500, white } from '@/utils/colors';
import { extraYPadding } from '@/utils/constants';
const AadhaarUploadedSuccessScreen: React.FC = () => {
const { bottom } = useSafeAreaInsets();
const paddingBottom = useSafeBottomPadding(extraYPadding + 35);
const navigation =
useNavigation<NativeStackNavigationProp<RootStackParamList>>();
const { trackEvent } = useSelfClient();
@@ -62,7 +62,7 @@ const AadhaarUploadedSuccessScreen: React.FC = () => {
<YStack
paddingHorizontal={25}
backgroundColor={white}
paddingBottom={bottom + extraYPadding + 35}
paddingBottom={paddingBottom}
paddingTop={25}
>
<PrimaryButton

View File

@@ -110,10 +110,10 @@
],
"scripts": {
"build": "yarn build:android && yarn build:ios && tsup && yarn postbuild",
"build:ts-only": "tsup && yarn postbuild",
"postbuild": "node ./scripts/postBuild.mjs",
"build:android": "sh ./scripts/build-android.sh",
"build:ios": "sh ./scripts/build-ios.sh",
"postbuild": "node ./scripts/postBuild.mjs",
"build:ts-only": "tsup && yarn postbuild",
"fmt": "prettier --check .",
"fmt:fix": "prettier --write .",
"format": "sh -c 'if [ -z \"$SKIP_BUILD_DEPS\" ]; then yarn nice; else yarn fmt:fix; fi'",
@@ -127,7 +127,8 @@
"typecheck": "tsc -p tsconfig.json --noEmit",
"types": "tsc -p tsconfig.json --noEmit",
"validate:exports": "node ./scripts/validate-exports.mjs",
"validate:pkg": "node ./scripts/verify-conditions.mjs"
"validate:pkg": "node ./scripts/verify-conditions.mjs",
"watch": "pkill -f 'tsup.*--watch' 2>/dev/null || true && tsup && yarn postbuild && tsup --watch"
},
"dependencies": {
"@babel/runtime": "^7.28.3",

View File

@@ -45,9 +45,9 @@ export function useCountries() {
if (result.status === 'success') {
setCountryData(result.data);
if (__DEV__) {
console.log('Set country data:', result.data);
}
// if (__DEV__) {
// console.log('Set country data:', result.data);
// }
} else {
console.error('API returned non-success status:', result.status);
}

View File

@@ -2,8 +2,8 @@
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
import { useCallback, useEffect, useMemo } from 'react';
import { Dimensions, StyleSheet } from 'react-native';
import { useCallback, useEffect } from 'react';
import { StyleSheet } from 'react-native';
import type { DocumentCategory } from '@selfxyz/common/utils/types';
@@ -17,6 +17,7 @@ import { black, white } from '../../constants/colors';
import { useSelfClient } from '../../context';
import { loadSelectedDocument } from '../../documents/utils';
import { notificationSuccess } from '../../haptic';
import { useSafeBottomPadding } from '../../hooks/useSafeBottomPadding';
import { ExpandableBottomLayout } from '../../layouts/ExpandableBottomLayout';
import { SdkEvents } from '../../types/events';
import type { SelfClient } from '../../types/public';
@@ -38,17 +39,7 @@ export const ConfirmIdentificationScreen = ({ onBeforeConfirm }: { onBeforeConfi
await onConfirm(selfClient);
}, [onBeforeConfirm, selfClient]);
// Calculate total bottom padding: base padding + fallback for smaller screens
const paddingBottom = useMemo(() => {
const basePadding = 20;
// Estimate for smaller screens to account for safe areas
const windowHeight = Dimensions.get('window').height;
const isSmallScreen = windowHeight < 900;
const fallbackPadding = isSmallScreen ? 50 : 0;
return basePadding + fallbackPadding;
}, []);
const paddingBottom = useSafeBottomPadding(20);
return (
<ExpandableBottomLayout.Layout backgroundColor={black}>

View File

@@ -3,7 +3,7 @@
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
import { memo, useCallback } from 'react';
import { ActivityIndicator, FlatList, TouchableOpacity, View } from 'react-native';
import { ActivityIndicator, FlatList, StyleSheet, TouchableOpacity, View } from 'react-native';
import { commonNames } from '@selfxyz/common/constants/countries';
@@ -32,15 +32,10 @@ const CountryItem = memo<{
if (!countryName) return null;
return (
<TouchableOpacity
onPress={() => onSelect(countryCode)}
style={{
paddingVertical: 13,
}}
>
<XStack alignItems="center" gap={16}>
<TouchableOpacity onPress={() => onSelect(countryCode)} style={styles.countryItemContainer}>
<XStack style={styles.countryItemContent}>
<RoundFlag countryCode={countryCode} size={FLAG_SIZE} />
<BodyText style={{ fontSize: 16, color: black, flex: 1 }}>{countryName}</BodyText>
<BodyText style={styles.countryItemText}>{countryName}</BodyText>
</XStack>
</TouchableOpacity>
);
@@ -49,7 +44,7 @@ const CountryItem = memo<{
CountryItem.displayName = 'CountryItem';
const Loading = () => (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<View style={styles.loadingContainer}>
<ActivityIndicator size="small" />
</View>
);
@@ -63,11 +58,11 @@ const CountryPickerScreen: React.FC = () => {
const onPressCountry = useCallback(
(countryCode: string) => {
buttonTap();
if (__DEV__) {
console.log('Selected country code:', countryCode);
console.log('Current countryData:', countryData);
console.log('Available country codes:', Object.keys(countryData));
}
// if (__DEV__) {
// console.log('Selected country code:', countryCode);
// console.log('Current countryData:', countryData);
// console.log('Available country codes:', Object.keys(countryData));
// }
const documentTypes = countryData[countryCode];
if (__DEV__) {
console.log('documentTypes for', countryCode, ':', documentTypes);
@@ -111,8 +106,8 @@ const CountryPickerScreen: React.FC = () => {
return (
<YStack flex={1} paddingTop="$4" paddingHorizontal="$4" backgroundColor={slate100}>
<YStack marginTop="$4" marginBottom="$6">
<BodyText style={{ fontSize: 29, fontFamily: advercase }}>Select the country that issued your ID</BodyText>
<BodyText style={{ fontSize: 16, color: slate500, marginTop: 20 }}>
<BodyText style={styles.titleText}>Select the country that issued your ID</BodyText>
<BodyText style={styles.subtitleText}>
Self has support for over 300 ID types. You can select the type of ID in the next step
</BodyText>
</YStack>
@@ -122,32 +117,12 @@ const CountryPickerScreen: React.FC = () => {
<YStack flex={1}>
{showSuggestion && (
<YStack marginBottom="$2">
<BodyText
style={{
fontSize: 16,
color: black,
fontFamily: dinot,
letterSpacing: 0.8,
marginBottom: 8,
}}
>
SUGGESTION
</BodyText>
<BodyText style={styles.sectionLabel}>SUGGESTION</BodyText>
<CountryItem
countryCode={userCountryCode as string /*safe due to showSuggestion*/}
onSelect={onPressCountry}
/>
<BodyText
style={{
fontSize: 16,
color: black,
fontFamily: dinot,
letterSpacing: 0.8,
marginTop: 20,
}}
>
SELECT AN ISSUING COUNTRY
</BodyText>
<BodyText style={styles.sectionLabelBottom}>SELECT AN ISSUING COUNTRY</BodyText>
</YStack>
)}
<FlatList
@@ -169,4 +144,48 @@ const CountryPickerScreen: React.FC = () => {
};
CountryPickerScreen.displayName = 'CountryPickerScreen';
const styles = StyleSheet.create({
countryItemContainer: {
paddingVertical: 13,
},
countryItemContent: {
alignItems: 'center',
gap: 16,
},
countryItemText: {
fontSize: 16,
color: black,
flex: 1,
},
loadingContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
titleText: {
fontSize: 29,
fontFamily: advercase,
color: black,
},
subtitleText: {
fontSize: 16,
color: slate500,
marginTop: 20,
},
sectionLabel: {
fontSize: 16,
color: black,
fontFamily: dinot,
letterSpacing: 0.8,
marginBottom: 8,
},
sectionLabelBottom: {
fontSize: 16,
color: black,
fontFamily: dinot,
letterSpacing: 0.8,
marginTop: 20,
},
});
export default CountryPickerScreen;

View File

@@ -3,6 +3,7 @@
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
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';
@@ -105,16 +106,7 @@ const IDSelectionScreen: React.FC<IDSelectionScreenProps> = props => {
<SelfLogo width={24} height={24} />
</YStack>
</XStack>
<BodyText
style={{
marginTop: 48,
fontSize: 29,
fontFamily: advercase,
textAlign: 'center',
}}
>
Select an ID type
</BodyText>
<BodyText style={styles.titleText}>Select an ID type</BodyText>
</YStack>
<YStack gap="$3">
{documentTypes.map((docType: string) => (
@@ -135,35 +127,42 @@ const IDSelectionScreen: React.FC<IDSelectionScreenProps> = props => {
<XStack alignItems="center" gap={'$3'} flex={1}>
{getDocumentLogo(docType)}
<YStack gap={'$1'}>
<BodyText style={{ fontSize: 24, fontFamily: dinot, color: black }}>
{getDocumentName(docType)}
</BodyText>
<BodyText
style={{
fontSize: 14,
fontFamily: dinot,
color: slate400,
}}
>
{getDocumentDescription(docType)}
</BodyText>
<BodyText style={styles.documentNameText}>{getDocumentName(docType)}</BodyText>
<BodyText style={styles.documentDescriptionText}>{getDocumentDescription(docType)}</BodyText>
</YStack>
</XStack>
</XStack>
))}
<BodyText
style={{
fontSize: 18,
fontFamily: dinot,
color: slate400,
textAlign: 'center',
}}
>
Be sure your document is ready to scan
</BodyText>
<BodyText style={styles.footerText}>Be sure your document is ready to scan</BodyText>
</YStack>
</YStack>
);
};
const styles = StyleSheet.create({
titleText: {
marginTop: 48,
fontSize: 29,
fontFamily: advercase,
textAlign: 'center',
color: black,
},
documentNameText: {
fontSize: 24,
fontFamily: dinot,
color: black,
},
documentDescriptionText: {
fontSize: 14,
fontFamily: dinot,
color: slate400,
},
footerText: {
fontSize: 18,
fontFamily: dinot,
color: slate400,
textAlign: 'center',
},
});
export default IDSelectionScreen;

View File

@@ -0,0 +1,5 @@
// 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 { useSafeBottomPadding } from './useSafeBottomPadding';

View File

@@ -0,0 +1,33 @@
// 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 { useMemo } from 'react';
import { Dimensions } from 'react-native';
/**
* Custom hook to calculate bottom padding that prevents UI elements from bleeding
* into the system navigation area on smaller screens.
*
* This hook uses screen height detection to add extra padding for smaller screens
* (< 900px height) to account for system navigation bars and safe areas.
*
* @param basePadding - Base padding to add (default: 20)
* @returns Total bottom padding value
*
* @example
* ```tsx
* // For use with ExpandableBottomLayout.BottomSection
* const bottomPadding = useSafeBottomPadding(20);
* <ExpandableBottomLayout.BottomSection paddingBottom={bottomPadding} />
* ```
*/
export const useSafeBottomPadding = (basePadding: number = 20): number => {
const { height: windowHeight } = Dimensions.get('window');
return useMemo(() => {
const isSmallScreen = windowHeight < 900;
const fallbackPadding = isSmallScreen ? 50 : 0;
return basePadding + fallbackPadding;
}, [windowHeight, basePadding]);
};

View File

@@ -40,6 +40,8 @@ const entry = {
'constants/analytics': 'src/constants/analytics.ts',
'constants/colors': 'src/constants/colors.ts',
'components/index': 'src/components/index.ts',
'hooks/index': 'src/hooks/index.ts',
'hooks/useSafeBottomPadding': 'src/hooks/useSafeBottomPadding.ts',
stores: 'src/stores/index.ts',
...flowEntries,
};

View File

@@ -0,0 +1,22 @@
#!/bin/bash
# Pod install with hermes-engine cache fix for React Native upgrades
# This script handles CocoaPods cache mismatches that occur after React Native version upgrades
set -e # Exit on any error
echo "🧹 Clearing CocoaPods cache to prevent hermes-engine version conflicts..."
pod cache clean --all > /dev/null 2>&1 || true
rm -rf ~/Library/Caches/CocoaPods > /dev/null 2>&1 || true
echo "📦 Attempting pod install..."
if pod install; then
echo "✅ Pods installed successfully"
else
echo "⚠️ Pod install failed, likely due to hermes-engine cache mismatch after React Native upgrade"
echo "🔧 Running targeted fix: pod update hermes-engine..."
pod update hermes-engine --no-repo-update
echo "🔄 Retrying pod install..."
pod install
echo "✅ Pods installed successfully after cache fix"
fi

View File

@@ -23,9 +23,9 @@
"reinstall": "yarn clean && yarn install && yarn prebuild && cd ios && pod install && cd ..",
"start": "react-native start",
"test": "vitest run",
"test:e2e:android": "bash scripts/e2e-android-ci.sh",
"test:watch": "vitest",
"types": "yarn prebuild && tsc --noEmit",
"test:e2e:android": "bash scripts/e2e-android-ci.sh"
"types": "yarn prebuild && tsc --noEmit"
},
"dependencies": {
"@babel/runtime": "^7.28.3",

View File

@@ -11,10 +11,5 @@
"output": "animations"
}
],
"allowedNonPeerDependencies": [
"angularx-qrcode",
"lottie-web",
"socket.io-client",
"uuid"
]
"allowedNonPeerDependencies": ["angularx-qrcode", "lottie-web", "socket.io-client", "uuid"]
}