diff --git a/lib/shared/thread-utils.js b/lib/shared/thread-utils.js --- a/lib/shared/thread-utils.js +++ b/lib/shared/thread-utils.js @@ -54,8 +54,10 @@ import { threadPermissionPropagationPrefixes, threadPermissions, + configurableCommunityPermissions, type ThreadPermission, type ThreadPermissionsInfo, + type UserSurfacedPermission, } from '../types/thread-permission-types.js'; import { type ThreadType, @@ -1568,6 +1570,41 @@ }, [threadInfo]); } +type RoleUserSurfacedPermissions = { + +[roleName: string]: $ReadOnlyArray, +}; +// Iterates through the existing roles in the community and 'reverse maps' +// the set of permission literals for each role to user-facing permission enums +// to help pre-populate the permission checkboxes when editing roles. +function useRoleUserSurfacedPermissions( + threadInfo: ThreadInfo, +): RoleUserSurfacedPermissions { + return React.useMemo(() => { + const roleNamesToPermissions = {}; + + Object.keys(threadInfo.roles).forEach(roleID => { + const roleName = threadInfo.roles[roleID].name; + const rolePermissions = Object.keys(threadInfo.roles[roleID].permissions); + const setOfUserSurfacedPermissions = new Set(); + + rolePermissions.forEach(rolePermission => { + const userSurfacedPermission = Object.keys( + configurableCommunityPermissions, + ).find(key => + configurableCommunityPermissions[key].has(rolePermission), + ); + + if (userSurfacedPermission) { + setOfUserSurfacedPermissions.add(userSurfacedPermission); + } + }); + roleNamesToPermissions[roleName] = [...setOfUserSurfacedPermissions]; + }); + + return roleNamesToPermissions; + }, [threadInfo]); +} + export { threadHasPermission, viewerIsMember, @@ -1634,4 +1671,5 @@ patchThreadInfoToIncludeMentionedMembersOfParent, threadInfoInsideCommunity, useRoleMemberCountsForCommunity, + useRoleUserSurfacedPermissions, }; diff --git a/native/roles/community-roles-screen.react.js b/native/roles/community-roles-screen.react.js --- a/native/roles/community-roles-screen.react.js +++ b/native/roles/community-roles-screen.react.js @@ -5,7 +5,10 @@ import { ScrollView } from 'react-native-gesture-handler'; import { threadInfoSelector } from 'lib/selectors/thread-selectors.js'; -import { useRoleMemberCountsForCommunity } from 'lib/shared/thread-utils.js'; +import { + useRoleMemberCountsForCommunity, + useRoleUserSurfacedPermissions, +} from 'lib/shared/thread-utils.js'; import type { ThreadInfo } from 'lib/types/thread-types.js'; import RolePanelEntry from './role-panel-entry.react.js'; @@ -49,6 +52,9 @@ const roleNamesToMembers = useRoleMemberCountsForCommunity(threadInfo); + const roleNamesToUserSurfacedPermissions = + useRoleUserSurfacedPermissions(threadInfo); + const rolePanelList = React.useMemo(() => { const rolePanelEntries = []; @@ -56,14 +62,22 @@ rolePanelEntries.push( , ); }); return rolePanelEntries; - }, [roleNamesToMembers]); + }, [ + roleNamesToMembers, + props.navigation, + threadInfo, + roleNamesToUserSurfacedPermissions, + ]); const navigateToCreateRole = React.useCallback( () => 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 @@ -5,18 +5,27 @@ import { View, Text, TouchableOpacity, Platform } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; +import type { UserSurfacedPermission } from 'lib/types/thread-permission-types.js'; +import type { ThreadInfo } from 'lib/types/thread-types.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'; +import { CreateRolesScreenRouteName } from '../navigation/route-names.js'; import { useSelector } from '../redux/redux-utils.js'; import { useStyles } from '../themes/colors.js'; type RolePanelEntryProps = { + +navigation: RolesNavigationProp<'CommunityRolesScreen'>, + +threadInfo: ThreadInfo, +roleName: string, + +rolePermissions: $ReadOnlyArray, +memberCount: number, }; function RolePanelEntry(props: RolePanelEntryProps): React.Node { - const { roleName, memberCount } = props; + const { navigation, threadInfo, roleName, rolePermissions, memberCount } = + props; const styles = useStyles(unboundStyles); const options = React.useMemo(() => { @@ -34,8 +43,19 @@ if (index === undefined || index === null || index === options.length) { return; } + + const selectedOption = options[index]; + + if (selectedOption === 'Edit role') { + navigation.navigate(CreateRolesScreenRouteName, { + threadInfo, + action: 'edit_role', + roleName, + rolePermissions, + }); + } }, - [options.length], + [navigation, options, roleName, rolePermissions, threadInfo], ); const activeTheme = useSelector(state => state.globalThemeInfo.activeTheme);