diff --git a/native/roles/change-roles-header-right-button.react.js b/native/roles/change-roles-header-right-button.react.js
--- a/native/roles/change-roles-header-right-button.react.js
+++ b/native/roles/change-roles-header-right-button.react.js
@@ -10,12 +10,15 @@
changeThreadMemberRoles,
changeThreadMemberRolesActionTypes,
} from 'lib/actions/thread-actions.js';
+import { otherUsersButNoOtherAdmins } from 'lib/selectors/thread-selectors.js';
+import { roleIsAdminRole } from 'lib/shared/thread-utils.js';
import {
useDispatchActionPromise,
useServerCall,
} from 'lib/utils/action-utils.js';
import type { NavigationRoute } from '../navigation/route-names';
+import { useSelector } from '../redux/redux-utils.js';
import { useColors } from '../themes/colors.js';
type Props = {
@@ -25,12 +28,17 @@
function ChangeRolesHeaderRightButton(props: Props): React.Node {
const { threadInfo, memberInfo, role: selectedRole } = props.route.params;
const { role: initialRole } = memberInfo;
+ invariant(initialRole, 'Expected initial role to be defined');
invariant(selectedRole, 'Expected selected role to be defined');
const navigation = useNavigation();
const callChangeThreadMemberRoles = useServerCall(changeThreadMemberRoles);
const dispatchActionPromise = useDispatchActionPromise();
+ const otherUsersButNoOtherAdminsValue = useSelector(
+ otherUsersButNoOtherAdmins(threadInfo.id),
+ );
+
const { purpleLink } = useColors();
const textStyle = React.useMemo(
() => ({
@@ -46,6 +54,16 @@
return;
}
+ const memberIsAdmin = roleIsAdminRole(threadInfo.roles[initialRole]);
+
+ if (otherUsersButNoOtherAdminsValue && memberIsAdmin) {
+ navigation.setParams({
+ ...props.route.params,
+ shouldShowError: true,
+ });
+ return;
+ }
+
dispatchActionPromise(
changeThreadMemberRolesActionTypes,
callChangeThreadMemberRoles(threadInfo.id, [memberInfo.id], selectedRole),
@@ -58,8 +76,11 @@
initialRole,
memberInfo.id,
navigation,
+ otherUsersButNoOtherAdminsValue,
+ props.route.params,
selectedRole,
threadInfo.id,
+ threadInfo.roles,
]);
return (
diff --git a/native/roles/change-roles-screen.react.js b/native/roles/change-roles-screen.react.js
--- a/native/roles/change-roles-screen.react.js
+++ b/native/roles/change-roles-screen.react.js
@@ -24,6 +24,7 @@
+threadInfo: ThreadInfo,
+memberInfo: RelativeMemberInfo,
+role: ?string,
+ +shouldShowError?: boolean,
};
type Props = {
@@ -37,7 +38,7 @@
function ChangeRolesScreen(props: Props): React.Node {
const { navigation, route } = props;
- const { threadInfo, memberInfo, role } = props.route.params;
+ const { threadInfo, memberInfo, role, shouldShowError } = props.route.params;
invariant(role, 'Role must be defined');
const changeRolesLoadingStatus: LoadingStatus = useSelector(
@@ -99,6 +100,7 @@
threadInfo,
memberInfo,
role: newRole,
+ shouldShowError: false,
});
},
[navigation, setSelectedRole, roleOptions, memberInfo, threadInfo],
@@ -122,7 +124,22 @@
},
onRoleChange,
);
- }, [roleOptions, onRoleChange, activeTheme, showActionSheetWithOptions]);
+ }, [showActionSheetWithOptions, roleOptions, onRoleChange, activeTheme]);
+
+ const errorMessage = React.useMemo(() => {
+ if (!shouldShowError) {
+ return null;
+ }
+
+ return (
+
+ Cannot change role.
+
+ There must be at least one admin at any given time.
+
+
+ );
+ }, [shouldShowError, styles.errorMessage, styles.errorMessageContainer]);
return (
@@ -143,6 +160,7 @@
+ {errorMessage}
);
}
@@ -192,6 +210,16 @@
pencilIcon: {
color: 'panelInputSecondaryForeground',
},
+ errorMessageContainer: {
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'center',
+ marginTop: 20,
+ },
+ errorMessage: {
+ color: 'redText',
+ fontSize: 16,
+ },
};
export default ChangeRolesScreen;