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 @@ -19,6 +19,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'; @@ -42,6 +43,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 } = @@ -59,8 +62,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); }, [], @@ -153,21 +160,39 @@ ], ); + 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; + } dispatchActionPromise( modifyCommunityRoleActionTypes, (async () => { - const response = await callModifyCommunityRole({ - community: threadInfo.id, - existingRoleID, - action, - name: pendingRoleName, - permissions: [...pendingRolePermissions], - }); - popModal(); - return response; + try { + const response = await callModifyCommunityRole({ + community: threadInfo.id, + existingRoleID, + action, + name: pendingRoleName, + permissions: [...pendingRolePermissions], + }); + popModal(); + return response; + } catch (e) { + setRoleCreationFailed('unknown_error'); + throw e; + } })(), ); }, [ @@ -179,8 +204,19 @@ 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 if (roleCreationFailed === 'unknown_error') { + return 'An unknown error occurred. Please try again'; + } else { + return 'An unknown error occurred. Please try again'; + } + }, [roleCreationFailed]); + const saveButtonContent = React.useMemo(() => { if (createRolesLoadingStatus === 'loading') { return ( @@ -202,6 +238,7 @@ onChange={onChangeRoleName} /> +
{errorMessage}