From 9e27cb06cb42d25aaa87bb2265d4497c13fef808 Mon Sep 17 00:00:00 2001 From: Chewbacca Date: Mon, 5 Jun 2023 08:34:22 -0400 Subject: [PATCH] Ban User from status action bar --- .../api/hooks/groups/useBlockGroupMember.ts | 8 ++-- .../api/hooks/groups/usePromoteGroupMember.ts | 2 +- app/soapbox/components/status-action-bar.tsx | 44 ++++++++++++++++--- .../components/group-member-list-item.tsx | 2 +- 4 files changed, 45 insertions(+), 11 deletions(-) diff --git a/app/soapbox/api/hooks/groups/useBlockGroupMember.ts b/app/soapbox/api/hooks/groups/useBlockGroupMember.ts index 36f722f27..5155d18c6 100644 --- a/app/soapbox/api/hooks/groups/useBlockGroupMember.ts +++ b/app/soapbox/api/hooks/groups/useBlockGroupMember.ts @@ -1,12 +1,12 @@ import { Entities } from 'soapbox/entity-store/entities'; import { useEntityActions } from 'soapbox/entity-store/hooks'; -import type { Group, GroupMember } from 'soapbox/schemas'; +import type { Account, Group, GroupMember } from 'soapbox/schemas'; -function useBlockGroupMember(group: Group, groupMember: GroupMember) { +function useBlockGroupMember(group: Group, account: Account) { const { createEntity } = useEntityActions( - [Entities.GROUP_MEMBERSHIPS, groupMember.id], - { post: `/api/v1/groups/${group.id}/blocks` }, + [Entities.GROUP_MEMBERSHIPS, account.id], + { post: `/api/v1/groups/${group?.id}/blocks` }, ); return createEntity; diff --git a/app/soapbox/api/hooks/groups/usePromoteGroupMember.ts b/app/soapbox/api/hooks/groups/usePromoteGroupMember.ts index 148980f0c..3d23dda62 100644 --- a/app/soapbox/api/hooks/groups/usePromoteGroupMember.ts +++ b/app/soapbox/api/hooks/groups/usePromoteGroupMember.ts @@ -8,7 +8,7 @@ import type { Group, GroupMember } from 'soapbox/schemas'; function usePromoteGroupMember(group: Group, groupMember: GroupMember) { const { createEntity } = useEntityActions( - [Entities.GROUP_MEMBERSHIPS, groupMember.id], + [Entities.GROUP_MEMBERSHIPS, groupMember.account.id], { post: `/api/v1/groups/${group.id}/promote` }, { schema: z.array(groupMemberSchema).transform((arr) => arr[0]) }, ); diff --git a/app/soapbox/components/status-action-bar.tsx b/app/soapbox/components/status-action-bar.tsx index 813b96444..47f769102 100644 --- a/app/soapbox/components/status-action-bar.tsx +++ b/app/soapbox/components/status-action-bar.tsx @@ -1,7 +1,7 @@ import { List as ImmutableList } from 'immutable'; import React from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; -import { useHistory } from 'react-router-dom'; +import { useHistory, useRouteMatch } from 'react-router-dom'; import { blockAccount } from 'soapbox/actions/accounts'; import { launchChat } from 'soapbox/actions/chats'; @@ -14,7 +14,7 @@ import { initMuteModal } from 'soapbox/actions/mutes'; import { initReport, ReportableEntities } from 'soapbox/actions/reports'; import { deleteStatus, editStatus, toggleMuteStatus } from 'soapbox/actions/statuses'; import { deleteFromTimelines } from 'soapbox/actions/timelines'; -import { useGroup, useGroupRelationship, useMuteGroup, useUnmuteGroup } from 'soapbox/api/hooks'; +import { useBlockGroupMember, useGroup, useGroupRelationship, useMuteGroup, useUnmuteGroup } from 'soapbox/api/hooks'; import { useDeleteGroupStatus } from 'soapbox/api/hooks/groups/useDeleteGroupStatus'; import DropdownMenu from 'soapbox/components/dropdown-menu'; import StatusActionButton from 'soapbox/components/status-action-button'; @@ -36,6 +36,7 @@ const messages = defineMessages({ adminAccount: { id: 'status.admin_account', defaultMessage: 'Moderate @{name}' }, admin_status: { id: 'status.admin_status', defaultMessage: 'Open this post in the moderation interface' }, block: { id: 'account.block', defaultMessage: 'Block @{name}' }, + blocked: { id: 'group.group_mod_block.success', defaultMessage: '@{name} is banned' }, blockAndReport: { id: 'confirmations.block.block_and_report', defaultMessage: 'Block & Report' }, blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' }, bookmark: { id: 'status.bookmark', defaultMessage: 'Bookmark' }, @@ -57,6 +58,9 @@ const messages = defineMessages({ embed: { id: 'status.embed', defaultMessage: 'Embed' }, external: { id: 'status.external', defaultMessage: 'View post on {domain}' }, favourite: { id: 'status.favourite', defaultMessage: 'Like' }, + groupBlockConfirm: { id: 'confirmations.block_from_group.confirm', defaultMessage: 'Ban' }, + groupBlockFromGroupHeading: { id: 'confirmations.block_from_group.heading', defaultMessage: 'Ban From Group' }, + groupBlockFromGroupMessage: { id: 'confirmations.block_from_group.message', defaultMessage: 'Are you sure you want to ban @{name} from the group?' }, groupModDelete: { id: 'status.group_mod_delete', defaultMessage: 'Delete post from group' }, group_remove_account: { id: 'status.remove_account_from_group', defaultMessage: 'Remove account from group' }, group_remove_post: { id: 'status.remove_post_from_group', defaultMessage: 'Remove post from group' }, @@ -121,19 +125,20 @@ const StatusActionBar: React.FC = ({ const intl = useIntl(); const history = useHistory(); const dispatch = useAppDispatch(); - + const match = useRouteMatch<{ groupSlug: string }>('/group/:groupSlug'); const { group } = useGroup((status.group as Group)?.id as string); const muteGroup = useMuteGroup(group as Group); const unmuteGroup = useUnmuteGroup(group as Group); const isMutingGroup = !!group?.relationship?.muting; + const deleteGroupStatus = useDeleteGroupStatus(group as Group, status.id); + const blockGroupMember = useBlockGroupMember(group as Group, status?.account as any); const me = useAppSelector(state => state.me); const { groupRelationship } = useGroupRelationship(status.group?.id); const features = useFeatures(); const settings = useSettings(); const soapboxConfig = useSoapboxConfig(); - const deleteGroupStatus = useDeleteGroupStatus(status?.group as Group, status.id); const { allowedEmoji } = soapboxConfig; @@ -371,6 +376,21 @@ const StatusActionBar: React.FC = ({ })); }; + const handleBlockFromGroup = () => { + dispatch(openModal('CONFIRM', { + heading: intl.formatMessage(messages.groupBlockFromGroupHeading), + message: intl.formatMessage(messages.groupBlockFromGroupMessage, { name: (status.account as any).username }), + confirm: intl.formatMessage(messages.groupBlockConfirm), + onConfirm: () => { + blockGroupMember({ account_ids: [(status.account as any).id] }, { + onSuccess() { + toast.success(intl.formatMessage(messages.blocked, { name: account?.acct })); + }, + }); + }, + })); + }; + const _makeMenu = (publicStatus: boolean) => { const mutingConversation = status.muted; const ownAccount = status.account.id === me; @@ -538,10 +558,24 @@ const StatusActionBar: React.FC = ({ const isGroupOwner = groupRelationship?.role === GroupRoles.OWNER; const isGroupAdmin = groupRelationship?.role === GroupRoles.ADMIN; const isStatusFromOwner = group.owner.id === account.id; + + const canBanUser = match?.isExact && (isGroupOwner || isGroupAdmin) && !isStatusFromOwner && !ownAccount; const canDeleteStatus = !ownAccount && (isGroupOwner || (isGroupAdmin && !isStatusFromOwner)); - if (canDeleteStatus) { + if (canBanUser || canDeleteStatus) { menu.push(null); + } + + if (canBanUser) { + menu.push({ + text: 'Ban from Group', + action: handleBlockFromGroup, + icon: require('@tabler/icons/ban.svg'), + destructive: true, + }); + } + + if (canDeleteStatus) { menu.push({ text: intl.formatMessage(messages.groupModDelete), action: handleDeleteFromGroup, diff --git a/app/soapbox/features/group/components/group-member-list-item.tsx b/app/soapbox/features/group/components/group-member-list-item.tsx index a2c2c951c..24c2260ee 100644 --- a/app/soapbox/features/group/components/group-member-list-item.tsx +++ b/app/soapbox/features/group/components/group-member-list-item.tsx @@ -53,7 +53,7 @@ const GroupMemberListItem = (props: IGroupMemberListItem) => { const features = useFeatures(); const intl = useIntl(); - const blockGroupMember = useBlockGroupMember(group, member); + const blockGroupMember = useBlockGroupMember(group, member.account); const promoteGroupMember = usePromoteGroupMember(group, member); const demoteGroupMember = useDemoteGroupMember(group, member);