diff --git a/web/components/enum-settings-option-info.react.js b/web/components/enum-settings-option-info.react.js --- a/web/components/enum-settings-option-info.react.js +++ b/web/components/enum-settings-option-info.react.js @@ -9,8 +9,8 @@ type Props = { +optionSelected: boolean, - +valid: boolean, - +styleStatementBasedOnValidity: boolean, + +valid?: boolean, + +styleStatementBasedOnValidity?: boolean, +children: React.Node, }; diff --git a/web/components/enum-settings-option.react.js b/web/components/enum-settings-option.react.js --- a/web/components/enum-settings-option.react.js +++ b/web/components/enum-settings-option.react.js @@ -27,8 +27,8 @@ +iconPosition?: IconPosition, +statements: $ReadOnlyArray<{ +statement: string, - +isStatementValid: boolean, - +styleStatementBasedOnValidity: boolean, + +isStatementValid?: boolean, + +styleStatementBasedOnValidity?: boolean, }>, }; 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 @@ -8,6 +8,7 @@ import type { ThreadInfo } from 'lib/types/thread-types.js'; import css from './community-roles-modal.css'; +import CreateRolesModal from './create-roles-modal.react.js'; import RolePanelEntry from './role-panel-entry.react.js'; import Button, { buttonThemes } from '../components/button.react.js'; import Modal from '../modals/modal.react.js'; @@ -18,7 +19,7 @@ }; function CommunityRolesModal(props: CommunityRolesModalProps): React.Node { - const { popModal } = useModalContext(); + const { popModal, pushModal } = useModalContext(); const { community } = props; const [threadInfo, setThreadInfo] = React.useState(community); @@ -47,7 +48,20 @@ [roleNamesToMembers], ); - const onClickCreateRole = React.useCallback(() => {}, []); + const rolePermissionsForNewRole = React.useMemo(() => new Set(), []); + + const onClickCreateRole = React.useCallback( + () => + pushModal( + , + ), + [pushModal, threadInfo, rolePermissionsForNewRole], + ); return ( diff --git a/web/roles/create-roles-modal.css b/web/roles/create-roles-modal.css new file mode 100644 --- /dev/null +++ b/web/roles/create-roles-modal.css @@ -0,0 +1,72 @@ +.formContainer { + display: flex; + flex-direction: column; + padding: 16px 32px 0 32px; +} + +.roleNameLabel { + color: var(--create-roles-text-color); + padding: 4px 0; + margin-top: 20px; +} + +.roleNameInput { + display: flex; + color: var(--fg); + margin: 8px 0 12px 0; +} + +.separator { + border: 0; + margin: 16px 32px 8px 32px; + width: 90%; + align-self: center; + height: 2px; + border: none; + border-top: var(--modal-separator) solid 1px; +} + +.permissionsHeaderContainer { + display: flex; + flex-direction: row; + justify-content: space-between; + padding: 16px 32px 24px 32px; +} + +.permissionsLabel { + color: var(--create-roles-text-color); +} + +.clearPermissions { + font-size: var(--s-font-14); +} + +.clearPermissionsDisabled { + color: var(--color-disabled); + cursor: not-allowed; +} + +.clearPermissionsEnabled { + color: var(--purple-link); + cursor: pointer; +} + +.permissionsContainer { + max-height: 350px; + overflow-y: auto; +} + +.buttonsContainer { + display: flex; + flex-direction: row; + justify-content: flex-end; + padding: 16px 32px; +} + +.backButton { + width: 100px; +} + +.createRoleButton { + margin-left: 8px; +} diff --git a/web/roles/create-roles-modal.react.js b/web/roles/create-roles-modal.react.js new file mode 100644 --- /dev/null +++ b/web/roles/create-roles-modal.react.js @@ -0,0 +1,149 @@ +// @flow + +import classNames from 'classnames'; +import * as React from 'react'; + +import { useModalContext } from 'lib/components/modal-provider.react.js'; +import type { + UserSurfacedPermission, + UserSurfacedPermissionOption, +} from 'lib/types/thread-permission-types.js'; +import type { ThreadInfo } from 'lib/types/thread-types.js'; +import { useFilterPermissionOptionsByThreadType } from 'lib/utils/role-utils.js'; + +import css from './create-roles-modal.css'; +import Button, { buttonThemes } from '../components/button.react.js'; +import EnumSettingsOption from '../components/enum-settings-option.react.js'; +import Input from '../modals/input.react.js'; +import Modal from '../modals/modal.react.js'; + +type CreateRolesModalProps = { + +threadInfo: ThreadInfo, + +action: 'create_role' | 'edit_role', + +roleName: string, + +rolePermissions: $ReadOnlySet, +}; + +function CreateRolesModal(props: CreateRolesModalProps): React.Node { + const { popModal } = useModalContext(); + const { threadInfo, roleName, rolePermissions } = props; + + const [pendingRoleName, setPendingRoleName] = + React.useState(roleName); + const [pendingRolePermissions, setPendingRolePermissions] = + React.useState<$ReadOnlySet>(rolePermissions); + + const onChangeRoleName = React.useCallback( + (event: SyntheticEvent) => { + setPendingRoleName(event.currentTarget.value); + }, + [], + ); + + const onCloseModal = React.useCallback(() => { + popModal(); + }, [popModal]); + + const clearPermissionsClassNames = classNames({ + [css.clearPermissions]: true, + [css.clearPermissionsDisabled]: pendingRolePermissions.size === 0, + [css.clearPermissionsEnabled]: pendingRolePermissions.size > 0, + }); + + const onClearPermissions = React.useCallback( + () => setPendingRolePermissions(new Set()), + [], + ); + + const isUserSurfacedPermissionSelected = React.useCallback( + (option: UserSurfacedPermissionOption) => + pendingRolePermissions.has(option.userSurfacedPermission), + [pendingRolePermissions], + ); + + const onEnumValuePress = React.useCallback( + (option: UserSurfacedPermissionOption) => + setPendingRolePermissions(currentPermissions => { + if (currentPermissions.has(option.userSurfacedPermission)) { + const newPermissions = new Set(currentPermissions); + newPermissions.delete(option.userSurfacedPermission); + return newPermissions; + } else { + return new Set([ + ...currentPermissions, + option.userSurfacedPermission, + ]); + } + }), + [], + ); + + const filteredUserSurfacedPermissionOptions = + useFilterPermissionOptionsByThreadType(threadInfo.type); + + const permissionsList = React.useMemo( + () => + [...filteredUserSurfacedPermissionOptions].map(permission => ( + onEnumValuePress(permission)} + icon={null} + title={permission.title} + type="checkbox" + statements={[{ statement: permission.description }]} + /> + )), + [ + filteredUserSurfacedPermissionOptions, + isUserSurfacedPermissionSelected, + onEnumValuePress, + ], + ); + + return ( + +
+
Role Name
+
+ +
+
+
+
+
Permissions
+
+ Clear Permissions +
+
+
{permissionsList}
+
+ + +
+
+ ); +} + +export default CreateRolesModal; diff --git a/web/theme.css b/web/theme.css --- a/web/theme.css +++ b/web/theme.css @@ -241,4 +241,5 @@ --modal-secondary-label: var(--shades-black-60); --community-roles-text-color: var(--shades-white-100); --modal-separator: var(--shades-black-80); + --create-roles-text-color: var(--shades-white-100); }