diff --git a/lib/utils/farcaster-utils.js b/lib/utils/farcaster-utils.js --- a/lib/utils/farcaster-utils.js +++ b/lib/utils/farcaster-utils.js @@ -1,7 +1,12 @@ // @flow +import invariant from 'invariant'; +import * as React from 'react'; + +import { setSyncedMetadataEntryActionType } from '../actions/synced-metadata-actions.js'; +import { IdentityClientContext } from '../shared/identity-client-context.js'; import { syncedMetadataNames } from '../types/synced-metadata-types.js'; -import { useSelector } from '../utils/redux-utils.js'; +import { useSelector, useDispatch } from '../utils/redux-utils.js'; function useCurrentUserFID(): ?string { return useSelector( @@ -12,4 +17,29 @@ ); } -export { useCurrentUserFID }; +function useLinkFID(): (fid: string) => Promise { + const identityClientContext = React.useContext(IdentityClientContext); + invariant(identityClientContext, 'identityClientContext should be set'); + + const { identityClient } = identityClientContext; + const { linkFarcasterAccount } = identityClient; + + const dispatch = useDispatch(); + + return React.useCallback( + async (fid: string) => { + await linkFarcasterAccount(fid); + + dispatch({ + type: setSyncedMetadataEntryActionType, + payload: { + name: syncedMetadataNames.CURRENT_USER_FID, + data: fid, + }, + }); + }, + [dispatch, linkFarcasterAccount], + ); +} + +export { useCurrentUserFID, useLinkFID }; diff --git a/native/account/registration/registration-server-call.js b/native/account/registration/registration-server-call.js --- a/native/account/registration/registration-server-call.js +++ b/native/account/registration/registration-server-call.js @@ -202,6 +202,7 @@ const legacySiweServerCall = useLegacySIWEServerCall(); const identityWalletRegisterCall = useIdentityWalletRegisterCall(); const dispatch = useDispatch(); + const returnedFunc = React.useCallback( (input: RegistrationServerCallInput) => new Promise( @@ -297,11 +298,11 @@ }, ), [ - currentStep, + currentStep.step, + dispatch, legacyKeyserverRegisterUsernameAccount, identityRegisterUsernameAccount, legacySiweServerCall, - dispatch, identityWalletRegisterCall, ], ); diff --git a/native/components/connect-farcaster-bottom-sheet.react.js b/native/components/connect-farcaster-bottom-sheet.react.js --- a/native/components/connect-farcaster-bottom-sheet.react.js +++ b/native/components/connect-farcaster-bottom-sheet.react.js @@ -5,11 +5,8 @@ import { View, StyleSheet } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; -import { setSyncedMetadataEntryActionType } from 'lib/actions/synced-metadata-actions.js'; import { useIsAppForegrounded } from 'lib/shared/lifecycle-utils.js'; -import { syncedMetadataNames } from 'lib/types/synced-metadata-types.js'; import { useCurrentUserFID } from 'lib/utils/farcaster-utils.js'; -import { useDispatch } from 'lib/utils/redux-utils.js'; import FarcasterPrompt from './farcaster-prompt.react.js'; import FarcasterWebView, { @@ -20,6 +17,7 @@ import BottomSheet from '../bottom-sheet/bottom-sheet.react.js'; import type { RootNavigationProp } from '../navigation/root-navigator.react.js'; import type { NavigationRoute } from '../navigation/route-names.js'; +import { useOnSuccessConnectToFarcaster } from '../utils/farcaster-utils.js'; const bottomSheetPaddingTop = 32; const farcasterPromptHeight = 350; @@ -34,24 +32,15 @@ function ConnectFarcasterBottomSheet(props: Props): React.Node { const { navigation } = props; - const dispatch = useDispatch(); + const { goBack } = navigation; - const fid = useCurrentUserFID(); + const [webViewState, setWebViewState] = + React.useState('closed'); - const onSuccess = React.useCallback( - (newFID: string) => { - dispatch({ - type: setSyncedMetadataEntryActionType, - payload: { - name: syncedMetadataNames.CURRENT_USER_FID, - data: newFID, - }, - }); - }, - [dispatch], - ); + const fid = useCurrentUserFID(); - const { goBack } = navigation; + const onSuccessConnectToFarcaster = + useOnSuccessConnectToFarcaster(setWebViewState); const bottomSheetRef = React.useRef(null); @@ -71,9 +60,6 @@ ); }, [insets.bottom, setContentHeight]); - const [webViewState, setWebViewState] = - React.useState('closed'); - const isAppForegrounded = useIsAppForegrounded(); React.useEffect(() => { @@ -102,10 +88,19 @@ variant={connectButtonVariant} /> - + ), - [connectButtonVariant, goBack, onPressConnect, onSuccess, webViewState], + [ + connectButtonVariant, + goBack, + onPressConnect, + onSuccessConnectToFarcaster, + webViewState, + ], ); return connectFarcasterBottomSheet; diff --git a/native/profile/farcaster-account-settings.react.js b/native/profile/farcaster-account-settings.react.js --- a/native/profile/farcaster-account-settings.react.js +++ b/native/profile/farcaster-account-settings.react.js @@ -3,10 +3,7 @@ import * as React from 'react'; import { View } from 'react-native'; -import { - setSyncedMetadataEntryActionType, - clearSyncedMetadataEntryActionType, -} from 'lib/actions/synced-metadata-actions.js'; +import { clearSyncedMetadataEntryActionType } from 'lib/actions/synced-metadata-actions.js'; import { syncedMetadataNames } from 'lib/types/synced-metadata-types.js'; import { useCurrentUserFID } from 'lib/utils/farcaster-utils.js'; import { useDispatch } from 'lib/utils/redux-utils.js'; @@ -18,6 +15,7 @@ import type { FarcasterWebViewState } from '../components/farcaster-web-view.react.js'; import type { NavigationRoute } from '../navigation/route-names.js'; import { useStyles } from '../themes/colors.js'; +import { useOnSuccessConnectToFarcaster } from '../utils/farcaster-utils.js'; type Props = { +navigation: ProfileNavigationProp<'FarcasterAccountSettings'>, @@ -44,19 +42,8 @@ const [webViewState, setWebViewState] = React.useState('closed'); - const onSuccess = React.useCallback( - (newFID: string) => { - setWebViewState('closed'); - dispatch({ - type: setSyncedMetadataEntryActionType, - payload: { - name: syncedMetadataNames.CURRENT_USER_FID, - data: newFID, - }, - }); - }, - [dispatch], - ); + const onSuccessConnectToFarcaster = + useOnSuccessConnectToFarcaster(setWebViewState); const onPressConnectFarcaster = React.useCallback(() => { setWebViewState('opening'); @@ -91,14 +78,17 @@ - + {button} ), [ button, fid, - onSuccess, + onSuccessConnectToFarcaster, styles.buttonContainer, styles.connectContainer, styles.promptContainer, diff --git a/native/utils/farcaster-utils.js b/native/utils/farcaster-utils.js new file mode 100644 --- /dev/null +++ b/native/utils/farcaster-utils.js @@ -0,0 +1,47 @@ +// @flow + +import * as React from 'react'; +import { Alert } from 'react-native'; + +import type { SetState } from 'lib/types/hook-types.js'; +import { useLinkFID } from 'lib/utils/farcaster-utils.js'; + +import { + getFarcasterAccountAlreadyLinkedAlertDetails, + UnknownErrorAlertDetails, +} from './alert-messages.js'; +import type { FarcasterWebViewState } from '../components/farcaster-web-view.react.js'; + +function useOnSuccessConnectToFarcaster( + setWebViewState: SetState, +): (newFid: string) => Promise { + const linkFID = useLinkFID(); + + return React.useCallback( + async (newFID: string) => { + setWebViewState('closed'); + + try { + await linkFID(newFID); + } catch (error) { + if ( + error.message === + 'farcaster ID already associated with different user' + ) { + const { title, message } = + getFarcasterAccountAlreadyLinkedAlertDetails(); + + Alert.alert(title, message); + } else { + Alert.alert( + UnknownErrorAlertDetails.title, + UnknownErrorAlertDetails.message, + ); + } + } + }, + [linkFID, setWebViewState], + ); +} + +export { useOnSuccessConnectToFarcaster };