diff --git a/native/account/registration/username-selection.react.js b/native/account/registration/username-selection.react.js index cdbefeef4..7840937c9 100644 --- a/native/account/registration/username-selection.react.js +++ b/native/account/registration/username-selection.react.js @@ -1,240 +1,240 @@ // @flow import invariant from 'invariant'; import * as React from 'react'; import { View, Text } from 'react-native'; import { exactSearchUser, exactSearchUserActionTypes, } from 'lib/actions/user-actions.js'; import { useLegacyAshoatKeyserverCall } from 'lib/keyserver-conn/legacy-keyserver-call.js'; -import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; import { validUsernameRegex } from 'lib/shared/account-utils.js'; import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js'; import { usingCommServicesAccessToken } from 'lib/utils/services-utils.js'; import { isValidEthereumAddress } from 'lib/utils/siwe-utils.js'; import RegistrationButtonContainer from './registration-button-container.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 RegistrationTextInput from './registration-text-input.react.js'; import type { CoolOrNerdMode } from './registration-types.js'; import PrimaryButton from '../../components/primary-button.react.js'; import { commRustModule } from '../../native-modules.js'; import { type NavigationRoute, PasswordSelectionRouteName, } from '../../navigation/route-names.js'; -import { useSelector } from '../../redux/redux-utils.js'; import { useStyles } from '../../themes/colors.js'; -const exactSearchUserLoadingStatusSelector = createLoadingStatusSelector( - exactSearchUserActionTypes, -); - export type UsernameSelectionParams = { +userSelections: { +coolOrNerdMode?: ?CoolOrNerdMode, +keyserverURL?: ?string, +farcasterID: ?string, }, }; type UsernameError = 'username_invalid' | 'username_taken'; type Props = { +navigation: RegistrationNavigationProp<'UsernameSelection'>, +route: NavigationRoute<'UsernameSelection'>, }; function UsernameSelection(props: Props): React.Node { const registrationContext = React.useContext(RegistrationContext); invariant(registrationContext, 'registrationContext should be set'); const { cachedSelections, setCachedSelections } = registrationContext; const [username, setUsername] = React.useState( cachedSelections.username ?? '', ); const validUsername = username.search(validUsernameRegex) > -1 && !isValidEthereumAddress(username.toLowerCase()); const [usernameError, setUsernameError] = React.useState(); const checkUsernameValidity = React.useCallback(() => { if (!validUsername) { setUsernameError('username_invalid'); return false; } setUsernameError(null); return true; }, [validUsername]); const { userSelections } = props.route.params; const { keyserverURL } = userSelections; const serverCallParamOverride = React.useMemo(() => { if (keyserverURL) { return { urlPrefix: keyserverURL }; } return undefined; }, [keyserverURL]); + const [usernameSearchLoading, setUsernameSearchLoading] = + React.useState(false); + const exactSearchUserCall = useLegacyAshoatKeyserverCall( exactSearchUser, serverCallParamOverride, ); const dispatchActionPromise = useDispatchActionPromise(); const { navigate } = props.navigation; const onProceed = React.useCallback(async () => { if (!checkUsernameValidity()) { return; } + setUsernameSearchLoading(true); + let userAlreadyExists; - if (usingCommServicesAccessToken) { - const findUserIDResponseString = - await commRustModule.findUserIDForUsername(username); - const findUserIDResponse = JSON.parse(findUserIDResponseString); - userAlreadyExists = - !!findUserIDResponse.userID || findUserIDResponse.isReserved; - } else { - const searchPromise = exactSearchUserCall(username); - void dispatchActionPromise(exactSearchUserActionTypes, searchPromise); - const { userInfo } = await searchPromise; - userAlreadyExists = !!userInfo; + try { + if (usingCommServicesAccessToken) { + const findUserIDResponseString = + await commRustModule.findUserIDForUsername(username); + const findUserIDResponse = JSON.parse(findUserIDResponseString); + userAlreadyExists = + !!findUserIDResponse.userID || findUserIDResponse.isReserved; + } else { + const searchPromise = exactSearchUserCall(username); + void dispatchActionPromise(exactSearchUserActionTypes, searchPromise); + const { userInfo } = await searchPromise; + userAlreadyExists = !!userInfo; + } + } finally { + setUsernameSearchLoading(false); } if (userAlreadyExists) { setUsernameError('username_taken'); return; } setUsernameError(undefined); setCachedSelections(oldUserSelections => ({ ...oldUserSelections, username, })); navigate<'PasswordSelection'>({ name: PasswordSelectionRouteName, params: { userSelections: { ...userSelections, username, }, }, }); }, [ checkUsernameValidity, username, exactSearchUserCall, dispatchActionPromise, setCachedSelections, navigate, userSelections, ]); - const exactSearchUserCallLoading = useSelector( - state => exactSearchUserLoadingStatusSelector(state) === 'loading', - ); let buttonVariant = 'disabled'; - if (exactSearchUserCallLoading) { + if (usernameSearchLoading) { buttonVariant = 'loading'; } else if (validUsername) { buttonVariant = 'enabled'; } const styles = useStyles(unboundStyles); let errorText; if (usernameError === 'username_invalid') { errorText = ( <> Usernames must: {'1. '} Be at least one character long. {'2. '} Start with either a letter or a number. {'3. '} Contain only letters, numbers, or the characters “-” and “_”. ); } else if (usernameError === 'username_taken') { errorText = ( Username taken. Please try another one ); } const shouldAutoFocus = React.useRef(!cachedSelections.username); return ( Pick a username {errorText} ); } const unboundStyles = { header: { fontSize: 24, color: 'panelForegroundLabel', paddingBottom: 16, }, error: { marginTop: 16, }, errorText: { fontFamily: 'Arial', fontSize: 15, lineHeight: 20, color: 'redText', }, listItem: { flexDirection: 'row', }, listItemNumber: { fontWeight: 'bold', }, listItemContent: { flexShrink: 1, }, }; export default UsernameSelection;