mirror of
https://github.com/selfxyz/self.git
synced 2026-02-19 02:24:25 -05:00
Prepares app for Euclid (#1473)
* setup IS_EUCLID build variable for conditionally using euclid desgins create a headless header that only handles the status bar, for the new screens since they manage their own make sure new screens get proper insets add recoveryphrase 3.0 fix country picker * this lint runs twice. once in repo wide lint and once here. so lets just run once to save resources Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
17
app/src/components/navbar/HeadlessNavForEuclid.tsx
Normal file
17
app/src/components/navbar/HeadlessNavForEuclid.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
// 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 { SystemBars } from 'react-native-edge-to-edge';
|
||||
import type { NativeStackHeaderProps } from '@react-navigation/native-stack';
|
||||
|
||||
export const HeadlessNavForEuclid = (props: NativeStackHeaderProps) => {
|
||||
return (
|
||||
<>
|
||||
<SystemBars
|
||||
style={props.options.statusBarStyle}
|
||||
hidden={props.options.statusBarHidden}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
16
app/src/hooks/useSafeAreaInsets.ts
Normal file
16
app/src/hooks/useSafeAreaInsets.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
// 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 { Platform } from 'react-native';
|
||||
import { useSafeAreaInsets as useSafeAreaInsetsOriginal } from 'react-native-safe-area-context';
|
||||
|
||||
// gives bare minimums in case safe area doesnt provide for example space for status bar icons.
|
||||
export function useSafeAreaInsets() {
|
||||
const insets = useSafeAreaInsetsOriginal();
|
||||
const minimum = Platform.select({ ios: 54, android: 26, web: 48 });
|
||||
return {
|
||||
...insets,
|
||||
top: Math.max(insets.top, minimum || 0),
|
||||
};
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
white,
|
||||
} from '@selfxyz/mobile-sdk-alpha/constants/colors';
|
||||
|
||||
import { HeadlessNavForEuclid } from '@/components/navbar/HeadlessNavForEuclid';
|
||||
import AccountRecoveryChoiceScreen from '@/screens/account/recovery/AccountRecoveryChoiceScreen';
|
||||
import AccountRecoveryScreen from '@/screens/account/recovery/AccountRecoveryScreen';
|
||||
import DocumentDataNotFoundScreen from '@/screens/account/recovery/DocumentDataNotFoundScreen';
|
||||
@@ -17,6 +18,7 @@ import RecoverWithPhraseScreen from '@/screens/account/recovery/RecoverWithPhras
|
||||
import CloudBackupScreen from '@/screens/account/settings/CloudBackupScreen';
|
||||
import SettingsScreen from '@/screens/account/settings/SettingsScreen';
|
||||
import ShowRecoveryPhraseScreen from '@/screens/account/settings/ShowRecoveryPhraseScreen';
|
||||
import { IS_EUCLID_ENABLED } from '@/utils/devUtils';
|
||||
|
||||
const accountScreens = {
|
||||
AccountRecovery: {
|
||||
@@ -79,14 +81,22 @@ const accountScreens = {
|
||||
screens: {},
|
||||
},
|
||||
},
|
||||
|
||||
ShowRecoveryPhrase: {
|
||||
screen: ShowRecoveryPhraseScreen,
|
||||
options: {
|
||||
title: 'Recovery Phrase',
|
||||
headerStyle: {
|
||||
backgroundColor: white,
|
||||
},
|
||||
} as NativeStackNavigationOptions,
|
||||
options: IS_EUCLID_ENABLED
|
||||
? ({
|
||||
headerShown: true,
|
||||
header: HeadlessNavForEuclid,
|
||||
statusBarStyle: ShowRecoveryPhraseScreen.statusBarStyle,
|
||||
statusBarHidden: ShowRecoveryPhraseScreen.statusBarHidden,
|
||||
} as NativeStackNavigationOptions)
|
||||
: ({
|
||||
title: 'Recovery Phrase',
|
||||
headerStyle: {
|
||||
backgroundColor: white,
|
||||
},
|
||||
} as NativeStackNavigationOptions),
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import type { NativeStackNavigationOptions } from '@react-navigation/native-stac
|
||||
import { black, white } from '@selfxyz/mobile-sdk-alpha/constants/colors';
|
||||
|
||||
import { AadhaarNavBar, IdDetailsNavBar } from '@/components/navbar';
|
||||
import { HeadlessNavForEuclid } from '@/components/navbar/HeadlessNavForEuclid';
|
||||
import AadhaarUploadedSuccessScreen from '@/screens/documents/aadhaar/AadhaarUploadedSuccessScreen';
|
||||
import AadhaarUploadErrorScreen from '@/screens/documents/aadhaar/AadhaarUploadErrorScreen';
|
||||
import AadhaarUploadScreen from '@/screens/documents/aadhaar/AadhaarUploadScreen';
|
||||
@@ -22,6 +23,7 @@ import ConfirmBelongingScreen from '@/screens/documents/selection/ConfirmBelongi
|
||||
import CountryPickerScreen from '@/screens/documents/selection/CountryPickerScreen';
|
||||
import DocumentOnboardingScreen from '@/screens/documents/selection/DocumentOnboardingScreen';
|
||||
import IDPickerScreen from '@/screens/documents/selection/IDPickerScreen';
|
||||
import { IS_EUCLID_ENABLED } from '@/utils/devUtils';
|
||||
|
||||
const documentsScreens = {
|
||||
DocumentCamera: {
|
||||
@@ -75,9 +77,16 @@ const documentsScreens = {
|
||||
},
|
||||
CountryPicker: {
|
||||
screen: CountryPickerScreen,
|
||||
options: {
|
||||
headerShown: false,
|
||||
} as NativeStackNavigationOptions,
|
||||
options: IS_EUCLID_ENABLED
|
||||
? ({
|
||||
header: HeadlessNavForEuclid,
|
||||
statusBarHidden: CountryPickerScreen.statusBar?.hidden,
|
||||
statusBarStyle: CountryPickerScreen.statusBar?.style,
|
||||
headerShown: true,
|
||||
} as NativeStackNavigationOptions)
|
||||
: {
|
||||
headerShown: false,
|
||||
},
|
||||
},
|
||||
IDPicker: {
|
||||
screen: IDPickerScreen,
|
||||
|
||||
@@ -2,21 +2,85 @@
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
|
||||
|
||||
import React, { useCallback } from 'react';
|
||||
import React, { useCallback, useEffect, useRef } from 'react';
|
||||
import Clipboard from '@react-native-clipboard/clipboard';
|
||||
|
||||
import type { RecoveryPhraseVariant } from '@selfxyz/euclid';
|
||||
import { RecoveryPhraseScreen } from '@selfxyz/euclid';
|
||||
import { useSelfClient } from '@selfxyz/mobile-sdk-alpha';
|
||||
import { Description } from '@selfxyz/mobile-sdk-alpha/components';
|
||||
|
||||
import Mnemonic from '@/components/Mnemonic';
|
||||
import useMnemonic from '@/hooks/useMnemonic';
|
||||
import { useSafeAreaInsets } from '@/hooks/useSafeAreaInsets';
|
||||
import { ExpandableBottomLayout } from '@/layouts/ExpandableBottomLayout';
|
||||
import { useSettingStore } from '@/stores/settingStore';
|
||||
import { IS_EUCLID_ENABLED } from '@/utils/devUtils';
|
||||
|
||||
const ShowRecoveryPhraseScreen: React.FC = () => {
|
||||
function useCopyRecoveryPhrase(mnemonic: string[] | undefined) {
|
||||
const [copied, setCopied] = React.useState(false);
|
||||
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
const onCopy = useCallback(() => {
|
||||
if (!mnemonic) return;
|
||||
Clipboard.setString(mnemonic.join(' '));
|
||||
setCopied(true);
|
||||
|
||||
// Clear any existing timeout
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
|
||||
// Set new timeout and store its ID
|
||||
timeoutRef.current = setTimeout(() => setCopied(false), 2500);
|
||||
}, [mnemonic]);
|
||||
|
||||
// Cleanup timeout on unmount
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
return { copied, onCopy };
|
||||
}
|
||||
|
||||
const ShowRecoveryPhraseScreen: React.FC & {
|
||||
statusBarStyle: string;
|
||||
statusBarHidden: boolean;
|
||||
} = () => {
|
||||
const { mnemonic, loadMnemonic } = useMnemonic();
|
||||
const self = useSelfClient();
|
||||
const { copied, onCopy } = useCopyRecoveryPhrase(mnemonic);
|
||||
const { setHasViewedRecoveryPhrase } = useSettingStore();
|
||||
|
||||
const onRevealWords = useCallback(async () => {
|
||||
const onReveal = useCallback(async () => {
|
||||
await loadMnemonic();
|
||||
}, [loadMnemonic]);
|
||||
setHasViewedRecoveryPhrase(true);
|
||||
}, [loadMnemonic, setHasViewedRecoveryPhrase]);
|
||||
|
||||
const insets = useSafeAreaInsets();
|
||||
if (IS_EUCLID_ENABLED) {
|
||||
const variant: RecoveryPhraseVariant = !mnemonic
|
||||
? 'hidden'
|
||||
: copied
|
||||
? 'copied'
|
||||
: 'revealed';
|
||||
return (
|
||||
<>
|
||||
<RecoveryPhraseScreen
|
||||
insets={insets}
|
||||
onReveal={onReveal}
|
||||
words={mnemonic}
|
||||
onBack={self.goBack}
|
||||
variant={variant}
|
||||
onCopy={onCopy}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<ExpandableBottomLayout.Layout backgroundColor="white">
|
||||
<ExpandableBottomLayout.BottomSection
|
||||
@@ -24,7 +88,7 @@ const ShowRecoveryPhraseScreen: React.FC = () => {
|
||||
justifyContent="center"
|
||||
gap={20}
|
||||
>
|
||||
<Mnemonic words={mnemonic} onRevealWords={onRevealWords} />
|
||||
<Mnemonic words={mnemonic} onRevealWords={loadMnemonic} />
|
||||
<Description>
|
||||
This phrase is the only way to recover your account. Keep it secret,
|
||||
keep it safe.
|
||||
@@ -35,3 +99,7 @@ const ShowRecoveryPhraseScreen: React.FC = () => {
|
||||
};
|
||||
|
||||
export default ShowRecoveryPhraseScreen;
|
||||
|
||||
ShowRecoveryPhraseScreen.statusBarHidden =
|
||||
RecoveryPhraseScreen.statusBar.hidden;
|
||||
ShowRecoveryPhraseScreen.statusBarStyle = RecoveryPhraseScreen.statusBar.style;
|
||||
|
||||
@@ -2,8 +2,21 @@
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
|
||||
|
||||
import type React from 'react';
|
||||
|
||||
import SDKCountryPickerScreen from '@selfxyz/mobile-sdk-alpha/onboarding/country-picker-screen';
|
||||
|
||||
export default function CountryPickerScreen() {
|
||||
return <SDKCountryPickerScreen />;
|
||||
}
|
||||
import { useSafeAreaInsets } from '@/hooks/useSafeAreaInsets';
|
||||
|
||||
type CountryPickerScreenComponent = React.FC & {
|
||||
statusBar: typeof SDKCountryPickerScreen.statusBar;
|
||||
};
|
||||
|
||||
const CountryPickerScreen: CountryPickerScreenComponent = () => {
|
||||
const insets = useSafeAreaInsets();
|
||||
return <SDKCountryPickerScreen insets={insets} />;
|
||||
};
|
||||
|
||||
CountryPickerScreen.statusBar = SDKCountryPickerScreen.statusBar;
|
||||
|
||||
export default CountryPickerScreen;
|
||||
|
||||
@@ -8,3 +8,4 @@
|
||||
* Use this constant instead of checking __DEV__ directly throughout the codebase.
|
||||
*/
|
||||
export const IS_DEV_MODE = typeof __DEV__ !== 'undefined' && __DEV__;
|
||||
export const IS_EUCLID_ENABLED = IS_DEV_MODE; // just in case we forgot to turn it off before pushing to prod.
|
||||
|
||||
Reference in New Issue
Block a user