Changeset View
Changeset View
Standalone View
Standalone View
native/avatars/edit-user-avatar.react.js
// @flow | // @flow | ||||
import { useNavigation } from '@react-navigation/native'; | import { useNavigation } from '@react-navigation/native'; | ||||
import invariant from 'invariant'; | import invariant from 'invariant'; | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { ActivityIndicator, TouchableOpacity, View } from 'react-native'; | import { ActivityIndicator, TouchableOpacity, View } from 'react-native'; | ||||
import { useENSAvatar } from 'lib/hooks/ens-cache.js'; | import { useENSAvatar } from 'lib/hooks/ens-cache.js'; | ||||
import { getETHAddressForUserInfo } from 'lib/shared/account-utils.js'; | import { getETHAddressForUserInfo } from 'lib/shared/account-utils.js'; | ||||
import type { GenericUserInfoWithAvatar } from 'lib/types/avatar-types.js'; | |||||
import { useShowAvatarActionSheet } from './avatar-hooks.js'; | import { useShowAvatarActionSheet } from './avatar-hooks.js'; | ||||
import EditAvatarBadge from './edit-avatar-badge.react.js'; | import EditAvatarBadge from './edit-avatar-badge.react.js'; | ||||
import { EditUserAvatarContext } from './edit-user-avatar-provider.react.js'; | import { EditUserAvatarContext } from './edit-user-avatar-provider.react.js'; | ||||
import UserAvatar from './user-avatar.react.js'; | import UserAvatar from './user-avatar.react.js'; | ||||
import { | import { | ||||
EmojiUserAvatarCreationRouteName, | EmojiUserAvatarCreationRouteName, | ||||
UserAvatarCameraModalRouteName, | UserAvatarCameraModalRouteName, | ||||
} from '../navigation/route-names.js'; | } from '../navigation/route-names.js'; | ||||
import { useSelector } from '../redux/redux-utils.js'; | import { useSelector } from '../redux/redux-utils.js'; | ||||
import { useStyles } from '../themes/colors.js'; | import { useStyles } from '../themes/colors.js'; | ||||
type Props = { | type Props = | ||||
+userID: ?string, | | { +userID: ?string, +disabled?: boolean } | ||||
+disabled?: boolean, | | { +userInfo: ?GenericUserInfoWithAvatar, +disabled?: boolean }; | ||||
}; | |||||
function EditUserAvatar(props: Props): React.Node { | function EditUserAvatar(props: Props): React.Node { | ||||
const styles = useStyles(unboundStyles); | |||||
const { userID, disabled } = props; | |||||
const editUserAvatarContext = React.useContext(EditUserAvatarContext); | const editUserAvatarContext = React.useContext(EditUserAvatarContext); | ||||
invariant(editUserAvatarContext, 'editUserAvatarContext should be set'); | invariant(editUserAvatarContext, 'editUserAvatarContext should be set'); | ||||
const { | const { | ||||
userAvatarSaveInProgress, | userAvatarSaveInProgress, | ||||
selectFromGalleryAndUpdateUserAvatar, | selectFromGalleryAndUpdateUserAvatar, | ||||
setUserAvatar, | setUserAvatar, | ||||
} = editUserAvatarContext; | } = editUserAvatarContext; | ||||
const currentUserInfo = useSelector(state => state.currentUserInfo); | const currentUserInfo = useSelector(state => state.currentUserInfo); | ||||
const userInfoProp = props.userInfo; | |||||
const userInfo: ?GenericUserInfoWithAvatar = userInfoProp ?? currentUserInfo; | |||||
const ethAddress = React.useMemo( | const ethAddress = React.useMemo( | ||||
() => getETHAddressForUserInfo(currentUserInfo), | () => getETHAddressForUserInfo(userInfo), | ||||
[currentUserInfo], | [userInfo], | ||||
); | ); | ||||
const ensAvatarURI = useENSAvatar(ethAddress); | const ensAvatarURI = useENSAvatar(ethAddress); | ||||
const { navigate } = useNavigation(); | const { navigate } = useNavigation(); | ||||
const navigateToUserEmojiAvatarCreation = React.useCallback(() => { | const navigateToUserEmojiAvatarCreation = React.useCallback(() => { | ||||
navigate(EmojiUserAvatarCreationRouteName); | navigate(EmojiUserAvatarCreationRouteName); | ||||
}, [navigate]); | }, [navigate]); | ||||
const navigateToCamera = React.useCallback(() => { | const navigateToCamera = React.useCallback(() => { | ||||
navigate(UserAvatarCameraModalRouteName); | navigate(UserAvatarCameraModalRouteName); | ||||
}, [navigate]); | }, [navigate]); | ||||
const setENSUserAvatar = React.useCallback(() => { | const setENSUserAvatar = React.useCallback(() => { | ||||
setUserAvatar({ type: 'ens' }); | setUserAvatar({ type: 'ens' }); | ||||
}, [setUserAvatar]); | }, [setUserAvatar]); | ||||
const removeUserAvatar = React.useCallback(() => { | const removeUserAvatar = React.useCallback(() => { | ||||
setUserAvatar({ type: 'remove' }); | setUserAvatar({ type: 'remove' }); | ||||
}, [setUserAvatar]); | }, [setUserAvatar]); | ||||
const hasCurrentAvatar = !!userInfo?.avatar; | |||||
const actionSheetConfig = React.useMemo(() => { | const actionSheetConfig = React.useMemo(() => { | ||||
const configOptions = [ | const configOptions = [ | ||||
{ id: 'emoji', onPress: navigateToUserEmojiAvatarCreation }, | { id: 'emoji', onPress: navigateToUserEmojiAvatarCreation }, | ||||
{ id: 'image', onPress: selectFromGalleryAndUpdateUserAvatar }, | { id: 'image', onPress: selectFromGalleryAndUpdateUserAvatar }, | ||||
{ id: 'camera', onPress: navigateToCamera }, | { id: 'camera', onPress: navigateToCamera }, | ||||
]; | ]; | ||||
if (ensAvatarURI) { | if (ensAvatarURI) { | ||||
configOptions.push({ id: 'ens', onPress: setENSUserAvatar }); | configOptions.push({ id: 'ens', onPress: setENSUserAvatar }); | ||||
} | } | ||||
if (currentUserInfo?.avatar) { | if (hasCurrentAvatar) { | ||||
configOptions.push({ id: 'remove', onPress: removeUserAvatar }); | configOptions.push({ id: 'remove', onPress: removeUserAvatar }); | ||||
} | } | ||||
return configOptions; | return configOptions; | ||||
}, [ | }, [ | ||||
currentUserInfo?.avatar, | hasCurrentAvatar, | ||||
ensAvatarURI, | ensAvatarURI, | ||||
navigateToCamera, | navigateToCamera, | ||||
navigateToUserEmojiAvatarCreation, | navigateToUserEmojiAvatarCreation, | ||||
removeUserAvatar, | removeUserAvatar, | ||||
setENSUserAvatar, | setENSUserAvatar, | ||||
selectFromGalleryAndUpdateUserAvatar, | selectFromGalleryAndUpdateUserAvatar, | ||||
]); | ]); | ||||
const showAvatarActionSheet = useShowAvatarActionSheet(actionSheetConfig); | const showAvatarActionSheet = useShowAvatarActionSheet(actionSheetConfig); | ||||
const styles = useStyles(unboundStyles); | |||||
let spinner; | let spinner; | ||||
if (userAvatarSaveInProgress) { | if (userAvatarSaveInProgress) { | ||||
spinner = ( | spinner = ( | ||||
<View style={styles.spinnerContainer}> | <View style={styles.spinnerContainer}> | ||||
<ActivityIndicator color="white" size="large" /> | <ActivityIndicator color="white" size="large" /> | ||||
</View> | </View> | ||||
); | ); | ||||
} | } | ||||
const { userID } = props; | |||||
const userAvatar = userID ? ( | |||||
<UserAvatar userID={userID} size="profile" /> | |||||
) : ( | |||||
<UserAvatar userInfo={userInfo} size="profile" /> | |||||
); | |||||
const { disabled } = props; | |||||
return ( | return ( | ||||
<TouchableOpacity onPress={showAvatarActionSheet} disabled={disabled}> | <TouchableOpacity onPress={showAvatarActionSheet} disabled={disabled}> | ||||
<UserAvatar userID={userID} size="profile" /> | {userAvatar} | ||||
{spinner} | {spinner} | ||||
{!disabled ? <EditAvatarBadge /> : null} | {!disabled ? <EditAvatarBadge /> : null} | ||||
</TouchableOpacity> | </TouchableOpacity> | ||||
); | ); | ||||
} | } | ||||
const unboundStyles = { | const unboundStyles = { | ||||
spinnerContainer: { | spinnerContainer: { | ||||
Show All 11 Lines |