diff --git a/native/account/registration/connect-farcaster.react.js b/native/account/registration/connect-farcaster.react.js index 5746f17c6..12c2a504e 100644 --- a/native/account/registration/connect-farcaster.react.js +++ b/native/account/registration/connect-farcaster.react.js @@ -1,252 +1,254 @@ // @flow import invariant from 'invariant'; import * as React from 'react'; import { Alert } from 'react-native'; import { IdentityClientContext } from 'lib/shared/identity-client-context.js'; import { useIsAppForegrounded } from 'lib/shared/lifecycle-utils.js'; import { siweNonceExpired } from './ethereum-utils.js'; import RegistrationButtonContainer from './registration-button-container.react.js'; import RegistrationButton from './registration-button.react.js'; import RegistrationContainer from './registration-container.react.js'; import RegistrationContentContainer from './registration-content-container.react.js'; import { RegistrationContext } from './registration-context.js'; import type { RegistrationNavigationProp } from './registration-navigator.react.js'; import type { CoolOrNerdMode } from './registration-types.js'; import FarcasterPrompt from '../../components/farcaster-prompt.react.js'; import FarcasterWebView from '../../components/farcaster-web-view.react.js'; import type { FarcasterWebViewState } from '../../components/farcaster-web-view.react.js'; import { type NavigationRoute, ConnectEthereumRouteName, AvatarSelectionRouteName, } from '../../navigation/route-names.js'; +import { + getFarcasterAccountAlreadyLinkedAlertDetails, + type AlertDetails, +} from '../../utils/alert-messages.js'; import { useStaffCanSee } from '../../utils/staff-utils.js'; export type ConnectFarcasterParams = ?{ +userSelections?: { +coolOrNerdMode?: CoolOrNerdMode, +keyserverURL?: string, }, }; type Props = { +navigation: RegistrationNavigationProp<'ConnectFarcaster'>, +route: NavigationRoute<'ConnectFarcaster'>, }; function ConnectFarcaster(prop: Props): React.Node { const { navigation, route } = prop; const { navigate } = navigation; const userSelections = route.params?.userSelections; const registrationContext = React.useContext(RegistrationContext); invariant(registrationContext, 'registrationContext should be set'); const { cachedSelections, setCachedSelections, skipEthereumLoginOnce, setSkipEthereumLoginOnce, } = registrationContext; const [webViewState, setWebViewState] = React.useState('closed'); const { ethereumAccount } = cachedSelections; const goToNextStep = React.useCallback( (fid?: ?string) => { setWebViewState('closed'); const nonceExpired = ethereumAccount && siweNonceExpired(ethereumAccount.nonceTimestamp); if (nonceExpired) { setCachedSelections(oldUserSelections => ({ ...oldUserSelections, ethereumAccount: undefined, })); } if (!skipEthereumLoginOnce || !ethereumAccount || nonceExpired) { navigate<'ConnectEthereum'>({ name: ConnectEthereumRouteName, params: { userSelections: { ...userSelections, farcasterID: fid, }, }, }); return; } const newUserSelections = { ...userSelections, farcasterID: fid, accountSelection: ethereumAccount, }; setSkipEthereumLoginOnce(false); navigate<'AvatarSelection'>({ name: AvatarSelectionRouteName, params: { userSelections: newUserSelections }, }); }, [ navigate, skipEthereumLoginOnce, setSkipEthereumLoginOnce, ethereumAccount, userSelections, setCachedSelections, ], ); const onSkip = React.useCallback(() => goToNextStep(), [goToNextStep]); const identityServiceClient = React.useContext(IdentityClientContext); const getFarcasterUsers = identityServiceClient?.identityClient.getFarcasterUsers; invariant(getFarcasterUsers, 'Could not get getFarcasterUsers'); - const [queuedAlert, setQueuedAlert] = React.useState(); + const [queuedAlert, setQueuedAlert] = React.useState(); const onSuccess = React.useCallback( async (fid: string) => { try { const commFCUsers = await getFarcasterUsers([fid]); if (commFCUsers.length > 0 && commFCUsers[0].farcasterID === fid) { const commUsername = commFCUsers[0].username; - setQueuedAlert({ - title: 'Farcaster account already linked', - body: `That Farcaster account is already linked to ${commUsername}`, - }); + + const alert = + getFarcasterAccountAlreadyLinkedAlertDetails(commUsername); + + setQueuedAlert(alert); setWebViewState('closed'); } else { goToNextStep(fid); setCachedSelections(oldUserSelections => ({ ...oldUserSelections, farcasterID: fid, })); } } catch (e) { setQueuedAlert({ title: 'Failed to query Comm', - body: + message: 'We failed to query Comm to see if that Farcaster account is ' + 'already linked', }); setWebViewState('closed'); } }, [goToNextStep, setCachedSelections, getFarcasterUsers], ); const isAppForegrounded = useIsAppForegrounded(); React.useEffect(() => { if (!queuedAlert || !isAppForegrounded) { return; } - Alert.alert(queuedAlert.title, queuedAlert.body); + Alert.alert(queuedAlert.title, queuedAlert.message); setQueuedAlert(null); }, [queuedAlert, isAppForegrounded]); const { farcasterID } = cachedSelections; const alreadyHasConnected = !!farcasterID; const onPressConnectFarcaster = React.useCallback(() => { setWebViewState('opening'); }, []); const defaultConnectButtonVariant = alreadyHasConnected ? 'outline' : 'enabled'; const connectButtonVariant = webViewState === 'opening' ? 'loading' : defaultConnectButtonVariant; const connectButtonText = alreadyHasConnected ? 'Connect new Farcaster account' : 'Connect Farcaster account'; const onUseAlreadyConnectedAccount = React.useCallback(() => { invariant( farcasterID, 'farcasterID should be set in onUseAlreadyConnectedAccount', ); goToNextStep(farcasterID); }, [farcasterID, goToNextStep]); const alreadyConnectedButton = React.useMemo(() => { if (!alreadyHasConnected) { return null; } return ( ); }, [alreadyHasConnected, onUseAlreadyConnectedAccount]); const staffCanSee = useStaffCanSee(); const skipButton = React.useMemo(() => { if (!staffCanSee) { return undefined; } return ( ); }, [staffCanSee, onSkip]); const farcasterPromptTextType = staffCanSee ? 'optional' : 'required'; const connectFarcaster = React.useMemo( () => ( {alreadyConnectedButton} {skipButton} ), [ alreadyConnectedButton, connectButtonText, connectButtonVariant, onPressConnectFarcaster, onSuccess, webViewState, farcasterPromptTextType, skipButton, ], ); return connectFarcaster; } const styles = { scrollViewContentContainer: { flexGrow: 1, }, }; export default ConnectFarcaster; diff --git a/native/utils/alert-messages.js b/native/utils/alert-messages.js index e3c388774..ef1f60e54 100644 --- a/native/utils/alert-messages.js +++ b/native/utils/alert-messages.js @@ -1,42 +1,60 @@ // @flow import { Platform } from 'react-native'; -type AlertDetails = { +export type AlertDetails = { +title: string, +message: string, }; const platformStore: string = Platform.select({ ios: 'App Store', android: 'Play Store', }); -export const AppOutOfDateAlertDetails: AlertDetails = { +const AppOutOfDateAlertDetails: AlertDetails = { title: 'App out of date', message: 'Your app version is pretty old, and the server doesn’t know how ' + `to speak to it anymore. Please use the ${platformStore} to update!`, }; -export const UsernameReservedAlertDetails: AlertDetails = { +const UsernameReservedAlertDetails: AlertDetails = { title: 'Username reserved', message: 'This username is currently reserved. Please contact support@' + 'comm.app if you would like to claim this account.', }; -export const UsernameTakenAlertDetails: AlertDetails = { +const UsernameTakenAlertDetails: AlertDetails = { title: 'Username taken', message: 'An account with that username already exists', }; -export const UserNotFoundAlertDetails: AlertDetails = { +const UserNotFoundAlertDetails: AlertDetails = { title: 'Incorrect username or password', message: "Either that user doesn't exist, or the password is incorrect", }; -export const UnknownErrorAlertDetails: AlertDetails = { +const UnknownErrorAlertDetails: AlertDetails = { title: 'Unknown error', message: 'Uhh... try again?', }; + +const getFarcasterAccountAlreadyLinkedAlertDetails = ( + commUsername: ?string, +): AlertDetails => ({ + title: 'Farcaster account already linked', + message: `That Farcaster account is already linked to ${ + commUsername ? commUsername : 'another account' + }`, +}); + +export { + AppOutOfDateAlertDetails, + UsernameReservedAlertDetails, + UsernameTakenAlertDetails, + UserNotFoundAlertDetails, + UnknownErrorAlertDetails, + getFarcasterAccountAlreadyLinkedAlertDetails, +};