diff --git a/native/chat/settings/thread-settings-member.react.js b/native/chat/settings/thread-settings-member.react.js index db77327ce..00ccf9e0c 100644 --- a/native/chat/settings/thread-settings-member.react.js +++ b/native/chat/settings/thread-settings-member.react.js @@ -1,313 +1,318 @@ // @flow import invariant from 'invariant'; import * as React from 'react'; import { View, Text, Platform, ActivityIndicator, TouchableOpacity, } from 'react-native'; import { removeUsersFromThreadActionTypes, changeThreadMemberRolesActionTypes, } from 'lib/actions/thread-actions'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors'; import { threadHasPermission, memberIsAdmin, memberHasAdminPowers, + threadHasAdminRole, } from 'lib/shared/thread-utils'; import { stringForUser } from 'lib/shared/user-utils'; import type { LoadingStatus } from 'lib/types/loading-types'; import { type ThreadInfo, type RelativeMemberInfo, threadPermissions, } from 'lib/types/thread-types'; import PencilIcon from '../../components/pencil-icon.react'; import { SingleLine } from '../../components/single-line.react'; import { type KeyboardState, KeyboardContext, } from '../../keyboard/keyboard-state'; import { OverlayContext, type OverlayContextType, } from '../../navigation/overlay-context'; import { ThreadSettingsMemberTooltipModalRouteName } from '../../navigation/route-names'; import { useSelector } from '../../redux/redux-utils'; import { type Colors, useColors, useStyles } from '../../themes/colors'; import type { VerticalBounds } from '../../types/layout-types'; import type { ThreadSettingsNavigate } from './thread-settings.react'; type BaseProps = { +memberInfo: RelativeMemberInfo, +threadInfo: ThreadInfo, +canEdit: boolean, +navigate: ThreadSettingsNavigate, +firstListItem: boolean, +lastListItem: boolean, +verticalBounds: ?VerticalBounds, +threadSettingsRouteKey: string, }; type Props = { ...BaseProps, // Redux state +removeUserLoadingStatus: LoadingStatus, +changeRoleLoadingStatus: LoadingStatus, +colors: Colors, +styles: typeof unboundStyles, // withKeyboardState +keyboardState: ?KeyboardState, // withOverlayContext +overlayContext: ?OverlayContextType, }; class ThreadSettingsMember extends React.PureComponent { editButton: ?React.ElementRef; visibleEntryIDs() { const role = this.props.memberInfo.role; if (!this.props.canEdit || !role) { return []; } const canRemoveMembers = threadHasPermission( this.props.threadInfo, threadPermissions.REMOVE_MEMBERS, ); const canChangeRoles = threadHasPermission( this.props.threadInfo, threadPermissions.CHANGE_ROLE, ); const result = []; if ( canRemoveMembers && !this.props.memberInfo.isViewer && (canChangeRoles || (this.props.threadInfo.roles[role] && this.props.threadInfo.roles[role].isDefault)) ) { result.push('remove_user'); } - if (canChangeRoles && this.props.memberInfo.username) { + if ( + canChangeRoles && + this.props.memberInfo.username && + threadHasAdminRole(this.props.threadInfo) + ) { result.push( memberIsAdmin(this.props.memberInfo, this.props.threadInfo) ? 'remove_admin' : 'make_admin', ); } return result; } render() { const userText = stringForUser(this.props.memberInfo); let userInfo = null; if (this.props.memberInfo.username) { userInfo = ( {userText} ); } else { userInfo = ( {userText} ); } let editButton = null; if ( this.props.removeUserLoadingStatus === 'loading' || this.props.changeRoleLoadingStatus === 'loading' ) { editButton = ( ); } else if (this.visibleEntryIDs().length !== 0) { editButton = ( ); } let roleInfo = null; if (memberIsAdmin(this.props.memberInfo, this.props.threadInfo)) { roleInfo = ( admin ); } else if (memberHasAdminPowers(this.props.memberInfo)) { roleInfo = ( parent admin ); } const firstItem = this.props.firstListItem ? null : this.props.styles.topBorder; const lastItem = this.props.lastListItem ? this.props.styles.lastInnerContainer : null; return ( {userInfo} {editButton} {roleInfo} ); } editButtonRef = (editButton: ?React.ElementRef) => { this.editButton = editButton; }; onEditButtonLayout = () => {}; onPressEdit = () => { if (this.dismissKeyboardIfShowing()) { return; } const { editButton, props: { verticalBounds }, } = this; if (!editButton || !verticalBounds) { return; } const { overlayContext } = this.props; invariant( overlayContext, 'ThreadSettingsMember should have OverlayContext', ); overlayContext.setScrollBlockingModalStatus('open'); editButton.measure((x, y, width, height, pageX, pageY) => { const coordinates = { x: pageX, y: pageY, width, height }; this.props.navigate({ name: ThreadSettingsMemberTooltipModalRouteName, params: { presentedFrom: this.props.threadSettingsRouteKey, initialCoordinates: coordinates, verticalBounds, visibleEntryIDs: this.visibleEntryIDs(), memberInfo: this.props.memberInfo, threadInfo: this.props.threadInfo, }, }); }); }; dismissKeyboardIfShowing = () => { const { keyboardState } = this.props; return !!(keyboardState && keyboardState.dismissKeyboardIfShowing()); }; } const unboundStyles = { anonymous: { color: 'panelForegroundTertiaryLabel', fontStyle: 'italic', }, container: { backgroundColor: 'panelForeground', flex: 1, paddingHorizontal: 12, }, editButton: { paddingLeft: 10, }, topBorder: { borderColor: 'panelForegroundBorder', borderTopWidth: 1, }, innerContainer: { flex: 1, paddingHorizontal: 12, paddingVertical: 8, }, lastInnerContainer: { paddingBottom: Platform.OS === 'ios' ? 12 : 10, }, role: { color: 'panelForegroundTertiaryLabel', flex: 1, fontSize: 14, paddingTop: 4, }, row: { flex: 1, flexDirection: 'row', }, username: { color: 'panelForegroundSecondaryLabel', flex: 1, fontSize: 16, lineHeight: 20, }, }; const ConnectedThreadSettingsMember: React.ComponentType = React.memo( function ConnectedThreadSettingsMember(props: BaseProps) { const memberID = props.memberInfo.id; const removeUserLoadingStatus = useSelector(state => createLoadingStatusSelector( removeUsersFromThreadActionTypes, `${removeUsersFromThreadActionTypes.started}:${memberID}`, )(state), ); const changeRoleLoadingStatus = useSelector(state => createLoadingStatusSelector( changeThreadMemberRolesActionTypes, `${changeThreadMemberRolesActionTypes.started}:${memberID}`, )(state), ); const colors = useColors(); const styles = useStyles(unboundStyles); const keyboardState = React.useContext(KeyboardContext); const overlayContext = React.useContext(OverlayContext); return ( ); }, ); export default ConnectedThreadSettingsMember;