From cfdace94544ca284df59abae13baaa58c736d45e Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sun, 11 Sep 2022 13:19:08 -0500 Subject: [PATCH] AccountModerationModal: add staff role picker --- app/soapbox/actions/admin.ts | 13 +++ .../modals/account-moderation-modal.tsx | 81 ++++++++++++++++++- 2 files changed, 91 insertions(+), 3 deletions(-) diff --git a/app/soapbox/actions/admin.ts b/app/soapbox/actions/admin.ts index 660b52dce..e486ca873 100644 --- a/app/soapbox/actions/admin.ts +++ b/app/soapbox/actions/admin.ts @@ -476,6 +476,18 @@ const demoteToUser = (accountId: string) => dispatch(removePermission([accountId], 'moderator')), ]); +const setRole = (accountId: string, role: 'user' | 'moderator' | 'admin') => + (dispatch: AppDispatch) => { + switch (role) { + case 'user': + return dispatch(demoteToUser(accountId)); + case 'moderator': + return dispatch(promoteToModerator(accountId)); + case 'admin': + return dispatch(promoteToAdmin(accountId)); + } + }; + const suggestUsers = (accountIds: string[]) => (dispatch: AppDispatch, getState: () => RootState) => { const nicknames = nicknamesFromIds(getState, accountIds); @@ -576,6 +588,7 @@ export { promoteToAdmin, promoteToModerator, demoteToUser, + setRole, suggestUsers, unsuggestUsers, }; diff --git a/app/soapbox/features/ui/components/modals/account-moderation-modal.tsx b/app/soapbox/features/ui/components/modals/account-moderation-modal.tsx index 84c7c824d..00bcdc7f8 100644 --- a/app/soapbox/features/ui/components/modals/account-moderation-modal.tsx +++ b/app/soapbox/features/ui/components/modals/account-moderation-modal.tsx @@ -1,14 +1,30 @@ -import React from 'react'; -import { FormattedMessage } from 'react-intl'; +import React, { useMemo } from 'react'; +import { defineMessages, FormattedMessage, useIntl, MessageDescriptor } from 'react-intl'; +import { setRole } from 'soapbox/actions/admin'; +import snackbar from 'soapbox/actions/snackbar'; import Account from 'soapbox/components/account'; +import List, { ListItem } from 'soapbox/components/list'; import MissingIndicator from 'soapbox/components/missing_indicator'; import { Button, HStack, Modal, Stack } from 'soapbox/components/ui'; -import { useAppSelector, useFeatures } from 'soapbox/hooks'; +import { SelectDropdown } from 'soapbox/features/forms'; +import { useAppDispatch, useAppSelector, useFeatures } from 'soapbox/hooks'; import { makeGetAccount } from 'soapbox/selectors'; +import type { Account as AccountEntity } from 'soapbox/types/entities'; + const getAccount = makeGetAccount(); +const messages = defineMessages({ + roleUser: { id: 'account_moderation_modal.roles.user', defaultMessage: 'User' }, + roleModerator: { id: 'account_moderation_modal.roles.moderator', defaultMessage: 'Moderator' }, + roleAdmin: { id: 'account_moderation_modal.roles.admin', defaultMessage: 'Admin' }, + promotedToAdmin: { id: 'admin.users.actions.promote_to_admin_message', defaultMessage: '@{acct} was promoted to an admin' }, + promotedToModerator: { id: 'admin.users.actions.promote_to_moderator_message', defaultMessage: '@{acct} was promoted to a moderator' }, + demotedToModerator: { id: 'admin.users.actions.demote_to_moderator_message', defaultMessage: '@{acct} was demoted to a moderator' }, + demotedToUser: { id: 'admin.users.actions.demote_to_user_message', defaultMessage: '@{acct} was demoted to a regular user' }, +}); + interface IAccountModerationModal { /** Action to close the modal. */ onClose: (type: string) => void, @@ -16,11 +32,34 @@ interface IAccountModerationModal { accountId: string, } +/** Staff role. */ +type AccountRole = 'user' | 'moderator' | 'admin'; + +/** Get the highest staff role associated with the account. */ +const getRole = (account: AccountEntity): AccountRole => { + if (account.admin) { + return 'admin'; + } else if (account.moderator) { + return 'moderator'; + } else { + return 'user'; + } +}; + /** Moderator actions against accounts. */ const AccountModerationModal: React.FC = ({ onClose, accountId }) => { + const intl = useIntl(); + const dispatch = useAppDispatch(); + const features = useFeatures(); const account = useAppSelector(state => getAccount(state, accountId)); + const roles: Record = useMemo(() => ({ + user: intl.formatMessage(messages.roleUser), + moderator: intl.formatMessage(messages.roleModerator), + admin: intl.formatMessage(messages.roleAdmin), + }), []); + const handleClose = () => onClose('ACCOUNT_MODERATION'); if (!account) { @@ -35,6 +74,32 @@ const AccountModerationModal: React.FC = ({ onClose, ac window.open(`/pleroma/admin/#/users/${account.id}/`, '_blank'); }; + const handleRoleChange: React.ChangeEventHandler = (e) => { + const role = e.target.value as AccountRole; + + dispatch(setRole(account.id, role)) + .then(() => { + let message: MessageDescriptor | undefined; + + if (role === 'admin') { + message = messages.promotedToAdmin; + } else if (role === 'moderator' && account.admin) { + message = messages.demotedToModerator; + } else if (role === 'moderator') { + message = messages.promotedToModerator; + } else if (role === 'user') { + message = messages.demotedToUser; + } + + if (message) { + dispatch(snackbar.success(intl.formatMessage(message, { acct: account.acct }))); + } + }) + .catch(() => {}); + }; + + const accountRole = getRole(account); + return ( } @@ -50,6 +115,16 @@ const AccountModerationModal: React.FC = ({ onClose, ac /> + + }> + + + + {features.adminFE && (