Changeset View
Changeset View
Standalone View
Standalone View
native/account/registration/username-selection.react.js
// @flow | // @flow | ||||
import invariant from 'invariant'; | |||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { View, Text } from 'react-native'; | import { View, Text } from 'react-native'; | ||||
import { | import { | ||||
exactSearchUser, | exactSearchUser, | ||||
exactSearchUserActionTypes, | exactSearchUserActionTypes, | ||||
} from 'lib/actions/user-actions.js'; | } from 'lib/actions/user-actions.js'; | ||||
import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; | import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; | ||||
import { validUsernameRegex } from 'lib/shared/account-utils.js'; | import { validUsernameRegex } from 'lib/shared/account-utils.js'; | ||||
import { | import { | ||||
useServerCall, | useServerCall, | ||||
useDispatchActionPromise, | useDispatchActionPromise, | ||||
} from 'lib/utils/action-utils.js'; | } from 'lib/utils/action-utils.js'; | ||||
import RegistrationButtonContainer from './registration-button-container.react.js'; | import RegistrationButtonContainer from './registration-button-container.react.js'; | ||||
import RegistrationButton from './registration-button.react.js'; | import RegistrationButton from './registration-button.react.js'; | ||||
import RegistrationContainer from './registration-container.react.js'; | import RegistrationContainer from './registration-container.react.js'; | ||||
import RegistrationContentContainer from './registration-content-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 { RegistrationNavigationProp } from './registration-navigator.react.js'; | ||||
import RegistrationTextInput from './registration-text-input.react.js'; | import RegistrationTextInput from './registration-text-input.react.js'; | ||||
import type { CoolOrNerdMode } from './registration-types.js'; | import type { CoolOrNerdMode } from './registration-types.js'; | ||||
import { | import { | ||||
type NavigationRoute, | type NavigationRoute, | ||||
PasswordSelectionRouteName, | PasswordSelectionRouteName, | ||||
} from '../../navigation/route-names.js'; | } from '../../navigation/route-names.js'; | ||||
import { useSelector } from '../../redux/redux-utils.js'; | import { useSelector } from '../../redux/redux-utils.js'; | ||||
Show All 12 Lines | |||||
type UsernameError = 'username_invalid' | 'username_taken'; | type UsernameError = 'username_invalid' | 'username_taken'; | ||||
type Props = { | type Props = { | ||||
+navigation: RegistrationNavigationProp<'UsernameSelection'>, | +navigation: RegistrationNavigationProp<'UsernameSelection'>, | ||||
+route: NavigationRoute<'UsernameSelection'>, | +route: NavigationRoute<'UsernameSelection'>, | ||||
}; | }; | ||||
function UsernameSelection(props: Props): React.Node { | function UsernameSelection(props: Props): React.Node { | ||||
const [username, setUsername] = React.useState(''); | 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; | const validUsername = username.search(validUsernameRegex) > -1; | ||||
const [usernameError, setUsernameError] = React.useState<?UsernameError>(); | const [usernameError, setUsernameError] = React.useState<?UsernameError>(); | ||||
const checkUsernameValidity = React.useCallback(() => { | const checkUsernameValidity = React.useCallback(() => { | ||||
if (!validUsername) { | if (!validUsername) { | ||||
setUsernameError('username_invalid'); | setUsernameError('username_invalid'); | ||||
return false; | return false; | ||||
} | } | ||||
Show All 15 Lines | const onProceed = React.useCallback(async () => { | ||||
const { userInfo } = await searchPromise; | const { userInfo } = await searchPromise; | ||||
if (userInfo) { | if (userInfo) { | ||||
setUsernameError('username_taken'); | setUsernameError('username_taken'); | ||||
return; | return; | ||||
} | } | ||||
setUsernameError(undefined); | setUsernameError(undefined); | ||||
setCachedSelections(oldUserSelections => ({ | |||||
...oldUserSelections, | |||||
username, | |||||
})); | |||||
navigate<'PasswordSelection'>({ | navigate<'PasswordSelection'>({ | ||||
name: PasswordSelectionRouteName, | name: PasswordSelectionRouteName, | ||||
params: { | params: { | ||||
userSelections: { | userSelections: { | ||||
...userSelections, | ...userSelections, | ||||
username, | username, | ||||
}, | }, | ||||
}, | }, | ||||
}); | }); | ||||
}, [ | }, [ | ||||
checkUsernameValidity, | checkUsernameValidity, | ||||
username, | username, | ||||
exactSearchUserCall, | exactSearchUserCall, | ||||
dispatchActionPromise, | dispatchActionPromise, | ||||
setCachedSelections, | |||||
navigate, | navigate, | ||||
userSelections, | userSelections, | ||||
]); | ]); | ||||
const exactSearchUserCallLoading = useSelector( | const exactSearchUserCallLoading = useSelector( | ||||
state => exactSearchUserLoadingStatusSelector(state) === 'loading', | state => exactSearchUserLoadingStatusSelector(state) === 'loading', | ||||
); | ); | ||||
let buttonVariant = 'disabled'; | let buttonVariant = 'disabled'; | ||||
Show All 32 Lines | function UsernameSelection(props: Props): React.Node { | ||||
} else if (usernameError === 'username_taken') { | } else if (usernameError === 'username_taken') { | ||||
errorText = ( | errorText = ( | ||||
<Text style={styles.errorText}> | <Text style={styles.errorText}> | ||||
Username taken. Please try another one | Username taken. Please try another one | ||||
</Text> | </Text> | ||||
); | ); | ||||
} | } | ||||
const shouldAutoFocus = React.useRef(!cachedSelections.username); | |||||
return ( | return ( | ||||
<RegistrationContainer> | <RegistrationContainer> | ||||
<RegistrationContentContainer> | <RegistrationContentContainer> | ||||
<Text style={styles.header}>Pick a username</Text> | <Text style={styles.header}>Pick a username</Text> | ||||
<RegistrationTextInput | <RegistrationTextInput | ||||
value={username} | value={username} | ||||
onChangeText={setUsername} | onChangeText={setUsername} | ||||
placeholder="Username" | placeholder="Username" | ||||
autoFocus={true} | autoFocus={shouldAutoFocus.current} | ||||
autoCorrect={false} | autoCorrect={false} | ||||
autoCapitalize="none" | autoCapitalize="none" | ||||
keyboardType="ascii-capable" | keyboardType="ascii-capable" | ||||
textContentType="username" | textContentType="username" | ||||
autoComplete="username-new" | autoComplete="username-new" | ||||
returnKeyType="go" | returnKeyType="go" | ||||
onSubmitEditing={onProceed} | onSubmitEditing={onProceed} | ||||
editable={!exactSearchUserCallLoading} | editable={!exactSearchUserCallLoading} | ||||
▲ Show 20 Lines • Show All 42 Lines • Show Last 20 Lines |