diff --git a/native/account/registration/registration-navigator.react.js b/native/account/registration/registration-navigator.react.js --- a/native/account/registration/registration-navigator.react.js +++ b/native/account/registration/registration-navigator.react.js @@ -3,8 +3,19 @@ import type { StackNavigationProp, StackNavigationHelpers, + ParamListBase, + StackNavigatorProps, + StackNavigationState, + StackOptions, + StackRouterOptions, + StackNavigationEventMap, + ExtraStackNavigatorProps, } from '@react-navigation/core'; -import { createStackNavigator } from '@react-navigation/stack'; +import { + createNavigatorFactory, + useNavigationBuilder, +} from '@react-navigation/native'; +import { StackView } from '@react-navigation/stack'; import * as React from 'react'; import AccountDoesNotExist from './account-does-not-exist.react.js'; @@ -16,6 +27,10 @@ import ExistingEthereumAccount from './existing-ethereum-account.react.js'; import KeyserverSelection from './keyserver-selection.react.js'; import PasswordSelection from './password-selection.react.js'; +import RegistrationRouter, { + type RegistrationRouterExtraNavigationHelpers, + type RegistrationRouterNavigationAction, +} from './registration-router.js'; import RegistrationTerms from './registration-terms.react.js'; import { CreateSIWEBackupMessage } from './siwe-backup-message-creation.react.js'; import UsernameSelection from './username-selection.react.js'; @@ -39,17 +54,73 @@ type RegistrationParamList, } from '../../navigation/route-names.js'; +export type RegistrationNavigationHelpers< + ParamList: ParamListBase = ParamListBase, +> = { + ...$Exact>, + ...RegistrationRouterExtraNavigationHelpers, +}; + +type RegistrationNavigatorProps = StackNavigatorProps< + RegistrationNavigationHelpers<>, +>; +function RegistrationNavigator({ + initialRouteName, + children, + screenOptions, + defaultScreenOptions, + screenListeners, + id, + ...rest +}: RegistrationNavigatorProps) { + const { state, descriptors, navigation } = useNavigationBuilder< + StackNavigationState, + RegistrationRouterNavigationAction, + StackOptions, + StackRouterOptions, + RegistrationNavigationHelpers<>, + StackNavigationEventMap, + ExtraStackNavigatorProps, + >(RegistrationRouter, { + id, + initialRouteName, + children, + screenOptions, + defaultScreenOptions, + screenListeners, + }); + return ( + + ); +} +const createRegistrationNavigator = createNavigatorFactory< + StackNavigationState, + StackOptions, + StackNavigationEventMap, + RegistrationNavigationHelpers<>, + ExtraStackNavigatorProps, +>(RegistrationNavigator); + export type RegistrationNavigationProp< RouteName: $Keys = $Keys, -> = StackNavigationProp; +> = { + ...StackNavigationProp, + ...RegistrationRouterExtraNavigationHelpers, +}; -const Registration = createStackNavigator< +const Registration = createRegistrationNavigator< ScreenParamList, RegistrationParamList, StackNavigationHelpers, >(); const screenOptions = { + headerShown: true, headerTransparent: true, headerBackTitleVisible: false, headerTitle: '', @@ -68,7 +139,7 @@ ... }; // eslint-disable-next-line no-unused-vars -function RegistrationNavigator(props: Props): React.Node { +function RegistrationComponent(props: Props): React.Node { return ( void, +}; + +function RegistrationRouter( + routerOptions: StackRouterOptions, +): Router { + const { + getStateForAction: baseGetStateForAction, + actionCreators: baseActionCreators, + ...rest + } = StackRouter(routerOptions); + return { + ...rest, + getStateForAction: ( + lastState: StackNavigationState, + action: RegistrationRouterNavigationAction, + options: RouterConfigOptions, + ) => { + if (action.type === reconnectEthereumActionType) { + // First, we look to see if ConnectEthereum is already in the stack. + // If it is, we'll pop all later screens and navigate to it. + const routeNames = lastState.routes.map(({ name }) => name); + if (routeNames.includes(ConnectEthereumRouteName)) { + const newState = removeScreensFromStack( + lastState, + (route: Route<>) => + route.name === ConnectEthereumRouteName ? 'break' : 'remove', + ); + const connectEthereumRoute = newState.routes[newState.index]; + const restRoutes = newState.routes.slice(0, -1); + return { + ...newState, + routes: [ + ...restRoutes, + { + ...connectEthereumRoute, + params: action.payload.params, + }, + ], + }; + } + // If it's not in the stack, we'll pop up to ConnectFarcaster + // and then push a new route + const newState = removeScreensFromStack(lastState, (route: Route<>) => + route.name === ConnectFarcasterRouteName ? 'break' : 'remove', + ); + return { + ...newState, + routes: [ + ...newState.routes, + { + name: ConnectEthereumRouteName, + key: 'ReconnectEthereum', + params: action.payload.params, + }, + ], + index: newState.index + 1, + }; + } else { + return baseGetStateForAction(lastState, action, options); + } + }, + actionCreators: { + ...baseActionCreators, + reconnectEthereum: (params: ConnectEthereumParams) => ({ + type: reconnectEthereumActionType, + payload: { params }, + }), + }, + }; +} + +export default RegistrationRouter; diff --git a/native/account/registration/registration-terms.react.js b/native/account/registration/registration-terms.react.js --- a/native/account/registration/registration-terms.react.js +++ b/native/account/registration/registration-terms.react.js @@ -1,10 +1,5 @@ // @flow -import type { - StackNavigationEventMap, - StackNavigationState, - StackOptions, -} from '@react-navigation/core'; import invariant from 'invariant'; import * as React from 'react'; import { Text, View, Image, Linking, Alert } from 'react-native'; @@ -24,11 +19,7 @@ } from './registration-types.js'; import commSwooshSource from '../../img/comm-swoosh.png'; import { logInActionType } from '../../navigation/action-types.js'; -import type { RootNavigationProp } from '../../navigation/root-navigator.react.js'; -import type { - NavigationRoute, - ScreenParamList, -} from '../../navigation/route-names.js'; +import type { NavigationRoute } from '../../navigation/route-names.js'; import { useStyles } from '../../themes/colors.js'; export type RegistrationTermsParams = { @@ -69,14 +60,17 @@ }, [setCachedSelections]); const { navigation } = props; - const goBackToHome = navigation.getParent< - ScreenParamList, - 'Registration', - StackNavigationState, - StackOptions, - StackNavigationEventMap, - RootNavigationProp<'Registration'>, - >()?.goBack; + const { reconnectEthereum } = navigation; + const { coolOrNerdMode, keyserverURL, farcasterID } = userSelections; + const navigateToConnectEthereum = React.useCallback(() => { + reconnectEthereum({ + userSelections: { + coolOrNerdMode, + keyserverURL, + farcasterID, + }, + }); + }, [reconnectEthereum, coolOrNerdMode, keyserverURL, farcasterID]); const onNonceExpired = React.useCallback(() => { setCachedSelections(oldUserSelections => ({ ...oldUserSelections, @@ -85,12 +79,12 @@ Alert.alert( 'Registration attempt timed out', 'Please try to connect your Ethereum wallet again', - [{ text: 'OK', onPress: goBackToHome }], + [{ text: 'OK', onPress: navigateToConnectEthereum }], { cancelable: false, }, ); - }, [goBackToHome, setCachedSelections]); + }, [setCachedSelections, navigateToConnectEthereum]); const onProceed = React.useCallback(async () => { setRegistrationInProgress(true); diff --git a/native/navigation/action-types.js b/native/navigation/action-types.js --- a/native/navigation/action-types.js +++ b/native/navigation/action-types.js @@ -15,3 +15,6 @@ export const replaceWithThreadActionType = 'REPLACE_WITH_THREAD'; export const clearThreadsActionType = 'CLEAR_THREADS'; export const pushNewThreadActionType = 'PUSH_NEW_THREAD'; + +// RegistrationRouter +export const reconnectEthereumActionType = 'RECONNECT_ETHEREUM';