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
@@ -54,7 +54,28 @@
return message;
}
+type RoleDeletableAndEditableStatus = {
+ +isDeletable: boolean,
+ +isEditable: boolean,
+};
+function useRoleDeletableAndEditableStatus(
+ roleName: string,
+ defaultRoleID: string,
+ existingRoleID: string,
+): RoleDeletableAndEditableStatus {
+ return React.useMemo(() => {
+ const canDelete = roleName !== 'Admins' && defaultRoleID !== existingRoleID;
+ const canEdit = roleName !== 'Admins';
+
+ return {
+ isDeletable: canDelete,
+ isEditable: canEdit,
+ };
+ }, [roleName, defaultRoleID, existingRoleID]);
+}
+
export {
useFilterPermissionOptionsByThreadType,
constructRoleDeletionMessagePrompt,
+ useRoleDeletableAndEditableStatus,
};
diff --git a/web/components/menu.css b/web/components/menu.css
--- a/web/components/menu.css
+++ b/web/components/menu.css
@@ -42,6 +42,14 @@
top: 24px;
}
+div.menuActionListRoleActions {
+ font-size: var(--s-font-14);
+ background-color: var(--menu-bg-light);
+ color: var(--menu-color);
+ stroke: var(--menu-color);
+ margin-top: 20px;
+}
+
button.menuAction {
color: inherit;
z-index: 1;
diff --git a/web/components/menu.react.js b/web/components/menu.react.js
--- a/web/components/menu.react.js
+++ b/web/components/menu.react.js
@@ -6,7 +6,11 @@
import css from './menu.css';
import { useRenderMenu } from '../menu-provider.react.js';
-type MenuVariant = 'thread-actions' | 'member-actions' | 'community-actions';
+type MenuVariant =
+ | 'thread-actions'
+ | 'member-actions'
+ | 'community-actions'
+ | 'role-actions';
type MenuProps = {
+icon: React.Node,
@@ -30,6 +34,7 @@
[css.menuActionListThreadActions]: variant === 'thread-actions',
[css.menuActionListMemberActions]: variant === 'member-actions',
[css.menuActionListCommunityActions]: variant === 'community-actions',
+ [css.menuActionListRoleActions]: variant === 'role-actions',
});
const menuActionList = React.useMemo(
diff --git a/web/roles/community-roles-modal.css b/web/roles/community-roles-modal.css
--- a/web/roles/community-roles-modal.css
+++ b/web/roles/community-roles-modal.css
@@ -17,7 +17,7 @@
}
.rolePanelTitle:last-of-type {
- margin-right: 32px;
+ margin-right: 90px;
}
.separator {
diff --git a/web/roles/community-roles-modal.react.js b/web/roles/community-roles-modal.react.js
--- a/web/roles/community-roles-modal.react.js
+++ b/web/roles/community-roles-modal.react.js
@@ -41,11 +41,12 @@
Object.keys(roleNamesToMembers).map(roleName => (
)),
- [roleNamesToMembers],
+ [roleNamesToMembers, threadInfo],
);
const rolePermissionsForNewRole = React.useMemo(() => new Set(), []);
diff --git a/web/roles/role-actions-menu.css b/web/roles/role-actions-menu.css
new file mode 100644
--- /dev/null
+++ b/web/roles/role-actions-menu.css
@@ -0,0 +1,4 @@
+.menuContainer {
+ color: var(--menu-color-light);
+ width: 10px;
+}
diff --git a/web/roles/role-actions-menu.react.js b/web/roles/role-actions-menu.react.js
new file mode 100644
--- /dev/null
+++ b/web/roles/role-actions-menu.react.js
@@ -0,0 +1,84 @@
+// @flow
+
+import invariant from 'invariant';
+import * as React from 'react';
+
+import SWMansionIcon from 'lib/components/SWMansionIcon.react.js';
+import type { ThreadInfo } from 'lib/types/thread-types.js';
+import { useRoleDeletableAndEditableStatus } from 'lib/utils/role-utils.js';
+
+import css from './role-actions-menu.css';
+import MenuItem from '../components/menu-item.react.js';
+import Menu from '../components/menu.react.js';
+
+const menuIcon = ;
+
+type RoleActionsMenuProps = {
+ +threadInfo: ThreadInfo,
+ +roleName: string,
+};
+
+function RoleActionsMenu(props: RoleActionsMenuProps): React.Node {
+ const { threadInfo, roleName } = props;
+
+ const defaultRoleID = Object.keys(threadInfo.roles).find(
+ roleID => threadInfo.roles[roleID].isDefault,
+ );
+ invariant(defaultRoleID, 'default role should exist');
+
+ const existingRoleID = Object.keys(threadInfo.roles).find(
+ roleID => threadInfo.roles[roleID].name === roleName,
+ );
+ invariant(existingRoleID, 'existing role should exist');
+
+ const roleOptions = useRoleDeletableAndEditableStatus(
+ roleName,
+ defaultRoleID,
+ existingRoleID,
+ );
+
+ // TODO: Implement in following diffs
+ const openEditRoleModal = React.useCallback(() => {}, []);
+ const openDeleteRoleModal = React.useCallback(() => {}, []);
+
+ const menuItems = React.useMemo(() => {
+ const availableOptions = [];
+ const { isDeletable, isEditable } = roleOptions;
+
+ if (isEditable) {
+ availableOptions.push(
+ ,
+ );
+ }
+
+ if (isDeletable) {
+ availableOptions.push(
+ ,
+ );
+ }
+
+ return availableOptions;
+ }, [roleOptions, openDeleteRoleModal, openEditRoleModal]);
+
+ return (
+
+
+
+ );
+}
+
+export default RoleActionsMenu;
diff --git a/web/roles/role-panel-entry.css b/web/roles/role-panel-entry.css
--- a/web/roles/role-panel-entry.css
+++ b/web/roles/role-panel-entry.css
@@ -1,7 +1,5 @@
.rolePanelEntry {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
+ display: grid;
align-items: center;
padding: 12px;
color: var(--community-roles-text-color);
@@ -13,9 +11,16 @@
}
.rolePanelCountEntryContainer {
- margin-right: 40px;
display: flex;
- align-items: flex-end;
+ align-items: center;
+ justify-content: flex-end;
+ grid-column: 3;
+}
+
+.rolePanelCountAndIcon {
+ display: flex;
+ align-items: center;
+ margin-right: 90px;
}
.rolePanelCountEntry {
diff --git a/web/roles/role-panel-entry.react.js b/web/roles/role-panel-entry.react.js
--- a/web/roles/role-panel-entry.react.js
+++ b/web/roles/role-panel-entry.react.js
@@ -2,22 +2,29 @@
import * as React from 'react';
+import type { ThreadInfo } from 'lib/types/thread-types.js';
+
+import RoleActionsMenu from './role-actions-menu.react.js';
import css from './role-panel-entry.css';
import CommIcon from '../CommIcon.react.js';
type RolePanelEntryProps = {
+ +threadInfo: ThreadInfo,
+roleName: string,
+memberCount: number,
};
function RolePanelEntry(props: RolePanelEntryProps): React.Node {
- const { roleName, memberCount } = props;
+ const { threadInfo, roleName, memberCount } = props;
return (
);