Changeset View
Changeset View
Standalone View
Standalone View
native/account/registration/avatar-selection.react.js
// @flow | // @flow | ||||
import invariant from 'invariant'; | import invariant from 'invariant'; | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { Text, View } from 'react-native'; | import { Text, View } from 'react-native'; | ||||
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 { RegistrationContext } from './registration-context.js'; | ||||
import type { RegistrationNavigationProp } from './registration-navigator.react.js'; | import type { RegistrationNavigationProp } from './registration-navigator.react.js'; | ||||
import type { | import { | ||||
CoolOrNerdMode, | type CoolOrNerdMode, | ||||
AccountSelection, | type AccountSelection, | ||||
AvatarData, | type AvatarData, | ||||
ensAvatarSelection, | |||||
} from './registration-types.js'; | } from './registration-types.js'; | ||||
import { | import { | ||||
EditUserAvatarContext, | EditUserAvatarContext, | ||||
type UserAvatarSelection, | type UserAvatarSelection, | ||||
} from '../../avatars/edit-user-avatar-provider.react.js'; | } from '../../avatars/edit-user-avatar-provider.react.js'; | ||||
import EditUserAvatar from '../../avatars/edit-user-avatar.react.js'; | import EditUserAvatar from '../../avatars/edit-user-avatar.react.js'; | ||||
import type { NavigationRoute } from '../../navigation/route-names.js'; | import type { NavigationRoute } from '../../navigation/route-names.js'; | ||||
import { useStyles } from '../../themes/colors.js'; | import { useStyles } from '../../themes/colors.js'; | ||||
export type AvatarSelectionParams = { | export type AvatarSelectionParams = { | ||||
+userSelections: { | +userSelections: { | ||||
+coolOrNerdMode: CoolOrNerdMode, | +coolOrNerdMode: CoolOrNerdMode, | ||||
+keyserverUsername: string, | +keyserverUsername: string, | ||||
+accountSelection: AccountSelection, | +accountSelection: AccountSelection, | ||||
}, | }, | ||||
}; | }; | ||||
const ensDefaultSelection = { | |||||
needsUpload: false, | |||||
updateUserAvatarRequest: { type: 'ens' }, | |||||
clientAvatar: { type: 'ens' }, | |||||
}; | |||||
type Props = { | type Props = { | ||||
+navigation: RegistrationNavigationProp<'AvatarSelection'>, | +navigation: RegistrationNavigationProp<'AvatarSelection'>, | ||||
+route: NavigationRoute<'AvatarSelection'>, | +route: NavigationRoute<'AvatarSelection'>, | ||||
}; | }; | ||||
function AvatarSelection(props: Props): React.Node { | function AvatarSelection(props: Props): React.Node { | ||||
const { userSelections } = props.route.params; | const { userSelections } = props.route.params; | ||||
const { accountSelection } = userSelections; | const { accountSelection } = userSelections; | ||||
const username = | const usernameOrETHAddress = | ||||
accountSelection.accountType === 'username' | accountSelection.accountType === 'username' | ||||
? accountSelection.username | ? accountSelection.username | ||||
: accountSelection.address; | : accountSelection.address; | ||||
const registrationContext = React.useContext(RegistrationContext); | |||||
invariant(registrationContext, 'registrationContext should be set'); | |||||
const { cachedSelections, setCachedSelections, register } = | |||||
registrationContext; | |||||
const editUserAvatarContext = React.useContext(EditUserAvatarContext); | const editUserAvatarContext = React.useContext(EditUserAvatarContext); | ||||
invariant(editUserAvatarContext, 'editUserAvatarContext should be set'); | invariant(editUserAvatarContext, 'editUserAvatarContext should be set'); | ||||
const { setRegistrationMode } = editUserAvatarContext; | const { setRegistrationMode } = editUserAvatarContext; | ||||
const prefetchedAvatarURI = | const prefetchedAvatarURI = | ||||
accountSelection.accountType === 'ethereum' | accountSelection.accountType === 'ethereum' | ||||
? accountSelection.avatarURI | ? accountSelection.avatarURI | ||||
: undefined; | : undefined; | ||||
const [avatarData, setAvatarData] = React.useState<?AvatarData>( | let initialAvatarData = cachedSelections.avatarData; | ||||
prefetchedAvatarURI ? ensDefaultSelection : undefined, | if (!initialAvatarData && prefetchedAvatarURI) { | ||||
); | initialAvatarData = ensAvatarSelection; | ||||
} | |||||
const [avatarData, setAvatarData] = | |||||
React.useState<?AvatarData>(initialAvatarData); | |||||
const setClientAvatarFromSelection = React.useCallback( | const setClientAvatarFromSelection = React.useCallback( | ||||
(selection: UserAvatarSelection) => { | (selection: UserAvatarSelection) => { | ||||
if (selection.needsUpload) { | if (selection.needsUpload) { | ||||
setAvatarData({ | const newAvatarData = { | ||||
...selection, | ...selection, | ||||
clientAvatar: { | clientAvatar: { | ||||
type: 'image', | type: 'image', | ||||
uri: selection.mediaSelection.uri, | uri: selection.mediaSelection.uri, | ||||
}, | }, | ||||
}); | }; | ||||
setAvatarData(newAvatarData); | |||||
setCachedSelections(oldUserSelections => ({ | |||||
...oldUserSelections, | |||||
avatarData: newAvatarData, | |||||
})); | |||||
} else if (selection.updateUserAvatarRequest.type !== 'remove') { | } else if (selection.updateUserAvatarRequest.type !== 'remove') { | ||||
const clientRequest = selection.updateUserAvatarRequest; | const clientRequest = selection.updateUserAvatarRequest; | ||||
invariant( | invariant( | ||||
clientRequest.type !== 'image', | clientRequest.type !== 'image', | ||||
'image avatars need to be uploaded', | 'image avatars need to be uploaded', | ||||
); | ); | ||||
setAvatarData({ | const newAvatarData = { | ||||
...selection, | ...selection, | ||||
clientAvatar: clientRequest, | clientAvatar: clientRequest, | ||||
}); | }; | ||||
setAvatarData(newAvatarData); | |||||
setCachedSelections(oldUserSelections => ({ | |||||
...oldUserSelections, | |||||
avatarData: newAvatarData, | |||||
})); | |||||
} else { | } else { | ||||
setAvatarData(undefined); | setAvatarData(undefined); | ||||
setCachedSelections(oldUserSelections => ({ | |||||
...oldUserSelections, | |||||
avatarData: undefined, | |||||
})); | |||||
} | } | ||||
}, | }, | ||||
[], | [setCachedSelections], | ||||
); | ); | ||||
const [registrationInProgress, setRegistrationInProgress] = | const [registrationInProgress, setRegistrationInProgress] = | ||||
React.useState(false); | React.useState(false); | ||||
React.useEffect(() => { | React.useEffect(() => { | ||||
if (registrationInProgress) { | if (registrationInProgress) { | ||||
return undefined; | return undefined; | ||||
} | } | ||||
setRegistrationMode({ | setRegistrationMode({ | ||||
registrationMode: 'on', | registrationMode: 'on', | ||||
successCallback: setClientAvatarFromSelection, | successCallback: setClientAvatarFromSelection, | ||||
}); | }); | ||||
return () => { | return () => { | ||||
setRegistrationMode({ registrationMode: 'off' }); | setRegistrationMode({ registrationMode: 'off' }); | ||||
}; | }; | ||||
}, [ | }, [ | ||||
registrationInProgress, | registrationInProgress, | ||||
setRegistrationMode, | setRegistrationMode, | ||||
setClientAvatarFromSelection, | setClientAvatarFromSelection, | ||||
]); | ]); | ||||
const registrationContext = React.useContext(RegistrationContext); | |||||
invariant(registrationContext, 'registrationContext should be set'); | |||||
const { register } = registrationContext; | |||||
const onProceed = React.useCallback(async () => { | const onProceed = React.useCallback(async () => { | ||||
setRegistrationInProgress(true); | setRegistrationInProgress(true); | ||||
try { | try { | ||||
await register({ | await register({ | ||||
...userSelections, | ...userSelections, | ||||
avatarData, | avatarData, | ||||
}); | }); | ||||
} finally { | } finally { | ||||
setRegistrationInProgress(false); | setRegistrationInProgress(false); | ||||
} | } | ||||
}, [register, userSelections, avatarData]); | }, [register, userSelections, avatarData]); | ||||
const clientAvatar = avatarData?.clientAvatar; | const clientAvatar = avatarData?.clientAvatar; | ||||
const userInfoOverride = React.useMemo( | const userInfoOverride = React.useMemo( | ||||
() => ({ | () => ({ | ||||
username, | username: usernameOrETHAddress, | ||||
avatar: clientAvatar, | avatar: clientAvatar, | ||||
}), | }), | ||||
[username, clientAvatar], | [usernameOrETHAddress, clientAvatar], | ||||
); | ); | ||||
const styles = useStyles(unboundStyles); | const styles = useStyles(unboundStyles); | ||||
return ( | return ( | ||||
<RegistrationContainer> | <RegistrationContainer> | ||||
<RegistrationContentContainer style={styles.scrollViewContentContainer}> | <RegistrationContentContainer style={styles.scrollViewContentContainer}> | ||||
<Text style={styles.header}>Pick an avatar</Text> | <Text style={styles.header}>Pick an avatar</Text> | ||||
<View style={styles.stagedAvatarSection}> | <View style={styles.stagedAvatarSection}> | ||||
▲ Show 20 Lines • Show All 43 Lines • Show Last 20 Lines |