diff --git a/web/roles/create-roles-modal.css b/web/roles/create-roles-modal.css --- a/web/roles/create-roles-modal.css +++ b/web/roles/create-roles-modal.css @@ -16,6 +16,17 @@ margin: 8px 0 12px 0; } +.errorMessage { + color: var(--error); + font-size: var(--s-font-14); + align-self: center; + visibility: hidden; +} + +.errorMessageVisible { + visibility: visible; +} + .separator { border: 0; margin: 16px 32px 8px 32px; diff --git a/web/roles/create-roles-modal.react.js b/web/roles/create-roles-modal.react.js --- a/web/roles/create-roles-modal.react.js +++ b/web/roles/create-roles-modal.react.js @@ -23,6 +23,7 @@ useServerCall, useDispatchActionPromise, } from 'lib/utils/action-utils.js'; +import { values } from 'lib/utils/objects.js'; import { useFilterPermissionOptionsByThreadType } from 'lib/utils/role-utils.js'; import css from './create-roles-modal.css'; @@ -46,6 +47,8 @@ +rolePermissions: $ReadOnlySet, }; +type RoleCreationErrorVariant = 'already_exists' | 'unknown_error'; + function CreateRolesModal(props: CreateRolesModalProps): React.Node { const { pushModal, popModal } = useModalContext(); const { threadInfo, action, existingRoleID, roleName, rolePermissions } = @@ -63,8 +66,12 @@ const [pendingRolePermissions, setPendingRolePermissions] = React.useState<$ReadOnlySet>(rolePermissions); + const [roleCreationFailed, setRoleCreationFailed] = + React.useState(); + const onChangeRoleName = React.useCallback( (event: SyntheticEvent) => { + setRoleCreationFailed(null); setPendingRoleName(event.currentTarget.value); }, [], @@ -157,8 +164,21 @@ ], ); + const errorMessageClassNames = classNames({ + [css.errorMessage]: true, + [css.errorMessageVisible]: !!roleCreationFailed, + }); + + const threadRoleNames = React.useMemo( + () => values(threadInfo.roles).map(role => role.name), + [threadInfo], + ); + const onClickCreateRole = React.useCallback(() => { - // TODO: Error handling in a later diff + if (threadRoleNames.includes(pendingRoleName) && action === 'create_role') { + setRoleCreationFailed('already_exists'); + return; + } let callModifyCommunityRoleParams: RoleModificationRequest; if (action === 'create_role') { @@ -182,11 +202,16 @@ dispatchActionPromise( modifyCommunityRoleActionTypes, (async () => { - const response = await callModifyCommunityRole( - callModifyCommunityRoleParams, - ); - popModal(); - return response; + try { + const response = await callModifyCommunityRole( + callModifyCommunityRoleParams, + ); + popModal(); + return response; + } catch (e) { + setRoleCreationFailed('unknown_error'); + throw e; + } })(), ); }, [ @@ -198,8 +223,17 @@ pendingRoleName, pendingRolePermissions, popModal, + threadRoleNames, ]); + const errorMessage = React.useMemo(() => { + if (roleCreationFailed === 'already_exists') { + return 'There is already a role with this name in the community'; + } else { + return 'An unknown error occurred. Please try again'; + } + }, [roleCreationFailed]); + const saveButtonContent = React.useMemo(() => { if (createRolesLoadingStatus === 'loading') { return ( @@ -221,6 +255,7 @@ onChange={onChangeRoleName} /> +
{errorMessage}