Changeset View
Changeset View
Standalone View
Standalone View
native/roles/change-roles-screen.react.js
// @flow | // @flow | ||||
import { useActionSheet } from '@expo/react-native-action-sheet'; | import { useActionSheet } from '@expo/react-native-action-sheet'; | ||||
import invariant from 'invariant'; | import invariant from 'invariant'; | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { View, Text, Platform } from 'react-native'; | import { View, Text, Platform, ActivityIndicator } from 'react-native'; | ||||
import { TouchableOpacity } from 'react-native-gesture-handler'; | import { TouchableOpacity } from 'react-native-gesture-handler'; | ||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'; | import { useSafeAreaInsets } from 'react-native-safe-area-context'; | ||||
import { changeThreadMemberRolesActionTypes } from 'lib/actions/thread-actions.js'; | |||||
import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; | |||||
import type { LoadingStatus } from 'lib/types/loading-types.js'; | |||||
import type { RelativeMemberInfo, ThreadInfo } from 'lib/types/thread-types.js'; | import type { RelativeMemberInfo, ThreadInfo } from 'lib/types/thread-types.js'; | ||||
import { values } from 'lib/utils/objects.js'; | import { values } from 'lib/utils/objects.js'; | ||||
import ChangeRolesHeaderRightButton from './change-roles-header-right-button.react.js'; | |||||
import UserAvatar from '../avatars/user-avatar.react.js'; | import UserAvatar from '../avatars/user-avatar.react.js'; | ||||
import type { ChatNavigationProp } from '../chat/chat.react'; | import type { ChatNavigationProp } from '../chat/chat.react'; | ||||
import SWMansionIcon from '../components/swmansion-icon.react.js'; | import SWMansionIcon from '../components/swmansion-icon.react.js'; | ||||
import type { NavigationRoute } from '../navigation/route-names.js'; | import type { NavigationRoute } 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'; | ||||
export type ChangeRolesScreenParams = { | export type ChangeRolesScreenParams = { | ||||
+threadInfo: ThreadInfo, | +threadInfo: ThreadInfo, | ||||
+memberInfo: RelativeMemberInfo, | +memberInfo: RelativeMemberInfo, | ||||
+role: ?string, | +role: ?string, | ||||
}; | }; | ||||
type Props = { | type Props = { | ||||
+navigation: ChatNavigationProp<'ChangeRolesScreen'>, | +navigation: ChatNavigationProp<'ChangeRolesScreen'>, | ||||
+route: NavigationRoute<'ChangeRolesScreen'>, | +route: NavigationRoute<'ChangeRolesScreen'>, | ||||
}; | }; | ||||
const changeRolesLoadingStatusSelector = createLoadingStatusSelector( | |||||
changeThreadMemberRolesActionTypes, | |||||
); | |||||
function ChangeRolesScreen(props: Props): React.Node { | function ChangeRolesScreen(props: Props): React.Node { | ||||
const { navigation } = props; | const { navigation, route } = props; | ||||
const { threadInfo, memberInfo, role } = props.route.params; | const { threadInfo, memberInfo, role } = props.route.params; | ||||
invariant(role, 'Role must be defined'); | invariant(role, 'Role must be defined'); | ||||
const changeRolesLoadingStatus: LoadingStatus = useSelector( | |||||
changeRolesLoadingStatusSelector, | |||||
); | |||||
const activityIndicatorStyle = React.useMemo( | |||||
() => ({ paddingRight: 15 }), | |||||
ashoat: Memos with no dependencies generally don't need to be memos, and should instead be declared one… | |||||
atulUnsubmitted Not Done Inline ActionsOr activityIndicatorStyle should be defined in unboundStyles? atul: Or `activityIndicatorStyle` should be defined in `unboundStyles`? | |||||
ashoatUnsubmitted Not Done Inline ActionsAh yeah, that makes more sense ashoat: Ah yeah, that makes more sense | |||||
[], | |||||
); | |||||
const styles = useStyles(unboundStyles); | const styles = useStyles(unboundStyles); | ||||
const [selectedRole, setSelectedRole] = React.useState<string>(role); | const [selectedRole, setSelectedRole] = React.useState<string>(role); | ||||
const roleOptions = React.useMemo( | const roleOptions = React.useMemo( | ||||
() => | () => | ||||
values(threadInfo.roles).map(threadRole => ({ | values(threadInfo.roles).map(threadRole => ({ | ||||
id: threadRole.id, | id: threadRole.id, | ||||
name: threadRole.name, | name: threadRole.name, | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | function ChangeRolesScreen(props: Props): React.Node { | ||||
}, [ | }, [ | ||||
roleOptions, | roleOptions, | ||||
onRoleChange, | onRoleChange, | ||||
insets.bottom, | insets.bottom, | ||||
activeTheme, | activeTheme, | ||||
showActionSheetWithOptions, | showActionSheetWithOptions, | ||||
]); | ]); | ||||
React.useEffect(() => { | |||||
navigation.setOptions({ | |||||
// eslint-disable-next-line react/display-name | |||||
headerRight: () => { | |||||
if (changeRolesLoadingStatus === 'loading') { | |||||
return ( | |||||
<ActivityIndicator | |||||
size="small" | |||||
color="white" | |||||
style={activityIndicatorStyle} | |||||
/> | |||||
); | |||||
} | |||||
return <ChangeRolesHeaderRightButton route={route} />; | |||||
}, | |||||
}); | |||||
}, [changeRolesLoadingStatus, navigation, activityIndicatorStyle, route]); | |||||
return ( | return ( | ||||
<View> | <View> | ||||
<View style={styles.descriptionBackground}> | <View style={styles.descriptionBackground}> | ||||
<Text style={styles.descriptionText}> | <Text style={styles.descriptionText}> | ||||
Members can only be assigned one role at a time. Changing a | Members can only be assigned one role at a time. Changing a | ||||
member’s role will replace their previously assigned role. | member’s role will replace their previously assigned role. | ||||
</Text> | </Text> | ||||
</View> | </View> | ||||
▲ Show 20 Lines • Show All 63 Lines • Show Last 20 Lines |
Memos with no dependencies generally don't need to be memos, and should instead be declared one time at the top-level scope