Page MenuHomePhabricator

D8640.id29098.diff
No OneTemporary

D8640.id29098.diff

diff --git a/lib/utils/role-utils.js b/lib/utils/role-utils.js
--- a/lib/utils/role-utils.js
+++ b/lib/utils/role-utils.js
@@ -35,4 +35,26 @@
}, [shouldFilterVoicedInAnnouncementChannel]);
}
-export { useFilterPermissionOptionsByThreadType };
+function constructRoleDeletionMessagePrompt(
+ defaultRoleName: string,
+ memberCount: number,
+): string {
+ let message;
+ if (memberCount === 0) {
+ message = 'Are you sure you want to delete this role?';
+ } else {
+ const messageNoun = memberCount === 1 ? 'member' : 'members';
+ const messageVerb = memberCount === 1 ? 'is' : 'are';
+ message =
+ `There ${messageVerb} currently ${memberCount} ${messageNoun} with ` +
+ `this role. Deleting the role will automatically assign the ` +
+ `${messageNoun} affected to the ${defaultRoleName} role.`;
+ }
+
+ return message;
+}
+
+export {
+ useFilterPermissionOptionsByThreadType,
+ constructRoleDeletionMessagePrompt,
+};
diff --git a/lib/utils/role-utils.test.js b/lib/utils/role-utils.test.js
new file mode 100644
--- /dev/null
+++ b/lib/utils/role-utils.test.js
@@ -0,0 +1,34 @@
+// @flow
+
+import { constructRoleDeletionMessagePrompt } from './role-utils.js';
+
+describe('constructRoleDeletionMessagePrompt', () => {
+ it('should return generic deletion message if no members have this role', () => {
+ const result = constructRoleDeletionMessagePrompt('defaultRole', 0);
+ expect(result).toBe('Are you sure you want to delete this role?');
+ });
+
+ it('should correctly format message for single member', () => {
+ const result = constructRoleDeletionMessagePrompt('defaultRole', 1);
+ expect(result).toBe(
+ `There is currently 1 member with this role. Deleting the role will ` +
+ `automatically assign the member affected to the defaultRole role.`,
+ );
+ });
+
+ it('should correctly format message for multiple members', () => {
+ const result = constructRoleDeletionMessagePrompt('defaultRole', 5);
+ expect(result).toBe(
+ `There are currently 5 members with this role. Deleting the role will ` +
+ `automatically assign the members affected to the defaultRole role.`,
+ );
+ });
+
+ it('should correctly incorporate the name of the default role', () => {
+ const result = constructRoleDeletionMessagePrompt('testRole', 5);
+ expect(result).toBe(
+ `There are currently 5 members with this role. Deleting the role will ` +
+ `automatically assign the members affected to the testRole role.`,
+ );
+ });
+});
diff --git a/native/roles/role-panel-entry.react.js b/native/roles/role-panel-entry.react.js
--- a/native/roles/role-panel-entry.react.js
+++ b/native/roles/role-panel-entry.react.js
@@ -9,6 +9,7 @@
import type { UserSurfacedPermission } from 'lib/types/thread-permission-types.js';
import type { ThreadInfo } from 'lib/types/thread-types.js';
+import { useDisplayDeleteRoleAlert } from './role-utils.react.js';
import type { RolesNavigationProp } from './roles-navigator.react.js';
import CommIcon from '../components/comm-icon.react.js';
import SWMansionIcon from '../components/swmansion-icon.react.js';
@@ -38,15 +39,33 @@
);
invariant(existingRoleID, 'Role ID must exist for an existing role');
+ const defaultRoleID = Object.keys(threadInfo.roles).find(
+ roleID => threadInfo.roles[roleID].isDefault,
+ );
+ invariant(defaultRoleID, 'Default role ID must exist');
+
+ const displayDeleteRoleAlert = useDisplayDeleteRoleAlert(
+ threadInfo,
+ existingRoleID,
+ defaultRoleID,
+ memberCount,
+ );
+
const options = React.useMemo(() => {
const availableOptions = ['Edit role'];
+ // Since the `Members` role is able to be renamed, we need to check if the
+ // default role ID is the same as the existing role ID.
+ if (defaultRoleID !== existingRoleID) {
+ availableOptions.push('Delete role');
+ }
+
if (Platform.OS === 'ios') {
availableOptions.push('Cancel');
}
return availableOptions;
- }, []);
+ }, [defaultRoleID, existingRoleID]);
const onOptionSelected = React.useCallback(
(index: ?number) => {
@@ -64,6 +83,8 @@
roleName,
rolePermissions,
});
+ } else if (selectedOption === 'Delete role') {
+ displayDeleteRoleAlert();
}
},
[
@@ -73,6 +94,7 @@
roleName,
rolePermissions,
threadInfo,
+ displayDeleteRoleAlert,
],
);
diff --git a/native/roles/role-utils.react.js b/native/roles/role-utils.react.js
new file mode 100644
--- /dev/null
+++ b/native/roles/role-utils.react.js
@@ -0,0 +1,64 @@
+// @flow
+
+import * as React from 'react';
+import { Alert } from 'react-native';
+
+import {
+ deleteCommunityRole,
+ deleteCommunityRoleActionTypes,
+} from 'lib/actions/thread-actions.js';
+import type { ThreadInfo } from 'lib/types/thread-types.js';
+import {
+ useDispatchActionPromise,
+ useServerCall,
+} from 'lib/utils/action-utils.js';
+import { constructRoleDeletionMessagePrompt } from 'lib/utils/role-utils.js';
+
+function useDisplayDeleteRoleAlert(
+ threadInfo: ThreadInfo,
+ existingRoleID: string,
+ defaultRoleID: string,
+ memberCount: number,
+): () => void {
+ const defaultRoleName = threadInfo.roles[defaultRoleID].name;
+ const callDeleteCommunityRole = useServerCall(deleteCommunityRole);
+ const dispatchActionPromise = useDispatchActionPromise();
+
+ const onDeleteRole = React.useCallback(() => {
+ dispatchActionPromise(
+ deleteCommunityRoleActionTypes,
+ callDeleteCommunityRole({
+ community: threadInfo.id,
+ roleID: existingRoleID,
+ }),
+ );
+ }, [
+ callDeleteCommunityRole,
+ dispatchActionPromise,
+ existingRoleID,
+ threadInfo.id,
+ ]);
+
+ const message = constructRoleDeletionMessagePrompt(
+ defaultRoleName,
+ memberCount,
+ );
+
+ return React.useCallback(
+ () =>
+ Alert.alert('Delete role', message, [
+ {
+ text: 'Yes, delete role',
+ style: 'destructive',
+ onPress: onDeleteRole,
+ },
+ {
+ text: 'Cancel',
+ style: 'cancel',
+ },
+ ]),
+ [message, onDeleteRole],
+ );
+}
+
+export { useDisplayDeleteRoleAlert };

File Metadata

Mime Type
text/plain
Expires
Sun, Dec 1, 11:47 PM (4 h, 7 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2606310
Default Alt Text
D8640.id29098.diff (6 KB)

Event Timeline