Add option to remove account from followers in web UI (#34488)

This commit is contained in:
Eugen Rochko 2025-04-18 09:23:34 +02:00 committed by GitHub
parent 64d94f9e57
commit bed614d44e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 74 additions and 1 deletions

View file

@ -1,7 +1,9 @@
import { createAction } from '@reduxjs/toolkit'; import { createAction } from '@reduxjs/toolkit';
import { apiRemoveAccountFromFollowers } from 'mastodon/api/accounts';
import type { ApiAccountJSON } from 'mastodon/api_types/accounts'; import type { ApiAccountJSON } from 'mastodon/api_types/accounts';
import type { ApiRelationshipJSON } from 'mastodon/api_types/relationships'; import type { ApiRelationshipJSON } from 'mastodon/api_types/relationships';
import { createDataLoadingThunk } from 'mastodon/store/typed_functions';
export const revealAccount = createAction<{ export const revealAccount = createAction<{
id: string; id: string;
@ -95,3 +97,10 @@ export const fetchRelationshipsSuccess = createAction(
'relationships/fetch/SUCCESS', 'relationships/fetch/SUCCESS',
actionWithSkipLoadingTrue<{ relationships: ApiRelationshipJSON[] }>, actionWithSkipLoadingTrue<{ relationships: ApiRelationshipJSON[] }>,
); );
export const removeAccountFromFollowers = createDataLoadingThunk(
'accounts/remove_from_followers',
({ accountId }: { accountId: string }) =>
apiRemoveAccountFromFollowers(accountId),
(relationship) => ({ relationship }),
);

View file

@ -18,3 +18,8 @@ export const apiFollowAccount = (
export const apiUnfollowAccount = (id: string) => export const apiUnfollowAccount = (id: string) =>
apiRequestPost<ApiRelationshipJSON>(`v1/accounts/${id}/unfollow`); apiRequestPost<ApiRelationshipJSON>(`v1/accounts/${id}/unfollow`);
export const apiRemoveAccountFromFollowers = (id: string) =>
apiRequestPost<ApiRelationshipJSON>(
`v1/accounts/${id}/remove_from_followers`,
);

View file

@ -18,6 +18,7 @@ import {
unmuteAccount, unmuteAccount,
pinAccount, pinAccount,
unpinAccount, unpinAccount,
removeAccountFromFollowers,
} from 'mastodon/actions/accounts'; } from 'mastodon/actions/accounts';
import { initBlockModal } from 'mastodon/actions/blocks'; import { initBlockModal } from 'mastodon/actions/blocks';
import { mentionCompose, directCompose } from 'mastodon/actions/compose'; import { mentionCompose, directCompose } from 'mastodon/actions/compose';
@ -152,6 +153,23 @@ const messages = defineMessages({
id: 'account.open_original_page', id: 'account.open_original_page',
defaultMessage: 'Open original page', defaultMessage: 'Open original page',
}, },
removeFromFollowers: {
id: 'account.remove_from_followers',
defaultMessage: 'Remove {name} from followers',
},
confirmRemoveFromFollowersTitle: {
id: 'confirmations.remove_from_followers.title',
defaultMessage: 'Remove follower?',
},
confirmRemoveFromFollowersMessage: {
id: 'confirmations.remove_from_followers.message',
defaultMessage:
'{name} will stop following you. Are you sure you want to proceed?',
},
confirmRemoveFromFollowersButton: {
id: 'confirmations.remove_from_followers.confirm',
defaultMessage: 'Remove follower',
},
}); });
const titleFromAccount = (account: Account) => { const titleFromAccount = (account: Account) => {
@ -494,6 +512,39 @@ export const AccountHeader: React.FC<{
arr.push(null); arr.push(null);
} }
if (relationship?.followed_by) {
const handleRemoveFromFollowers = () => {
dispatch(
openModal({
modalType: 'CONFIRM',
modalProps: {
title: intl.formatMessage(
messages.confirmRemoveFromFollowersTitle,
),
message: intl.formatMessage(
messages.confirmRemoveFromFollowersMessage,
{ name: <strong>{account.acct}</strong> },
),
confirm: intl.formatMessage(
messages.confirmRemoveFromFollowersButton,
),
onConfirm: () => {
void dispatch(removeAccountFromFollowers({ accountId }));
},
},
}),
);
};
arr.push({
text: intl.formatMessage(messages.removeFromFollowers, {
name: account.username,
}),
action: handleRemoveFromFollowers,
dangerous: true,
});
}
if (relationship?.muting) { if (relationship?.muting) {
arr.push({ arr.push({
text: intl.formatMessage(messages.unmute, { text: intl.formatMessage(messages.unmute, {
@ -592,6 +643,8 @@ export const AccountHeader: React.FC<{
return arr; return arr;
}, [ }, [
dispatch,
accountId,
account, account,
relationship, relationship,
permissions, permissions,

View file

@ -62,6 +62,7 @@
"account.open_original_page": "Open original page", "account.open_original_page": "Open original page",
"account.posts": "Posts", "account.posts": "Posts",
"account.posts_with_replies": "Posts and replies", "account.posts_with_replies": "Posts and replies",
"account.remove_from_followers": "Remove {name} from followers",
"account.report": "Report @{name}", "account.report": "Report @{name}",
"account.requested": "Awaiting approval. Click to cancel follow request", "account.requested": "Awaiting approval. Click to cancel follow request",
"account.requested_follow": "{name} has requested to follow you", "account.requested_follow": "{name} has requested to follow you",
@ -233,6 +234,9 @@
"confirmations.redraft.confirm": "Delete & redraft", "confirmations.redraft.confirm": "Delete & redraft",
"confirmations.redraft.message": "Are you sure you want to delete this post and re-draft it? Favorites and boosts will be lost, and replies to the original post will be orphaned.", "confirmations.redraft.message": "Are you sure you want to delete this post and re-draft it? Favorites and boosts will be lost, and replies to the original post will be orphaned.",
"confirmations.redraft.title": "Delete & redraft post?", "confirmations.redraft.title": "Delete & redraft post?",
"confirmations.remove_from_followers.confirm": "Remove follower",
"confirmations.remove_from_followers.message": "{name} will stop following you. Are you sure you want to proceed?",
"confirmations.remove_from_followers.title": "Remove follower?",
"confirmations.reply.confirm": "Reply", "confirmations.reply.confirm": "Reply",
"confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?", "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
"confirmations.reply.title": "Overwrite post?", "confirmations.reply.title": "Overwrite post?",

View file

@ -24,6 +24,7 @@ import {
pinAccountSuccess, pinAccountSuccess,
unpinAccountSuccess, unpinAccountSuccess,
fetchRelationshipsSuccess, fetchRelationshipsSuccess,
removeAccountFromFollowers,
} from '../actions/accounts_typed'; } from '../actions/accounts_typed';
import { import {
blockDomainSuccess, blockDomainSuccess,
@ -109,7 +110,8 @@ export const relationshipsReducer: Reducer<State> = (
unmuteAccountSuccess.match(action) || unmuteAccountSuccess.match(action) ||
pinAccountSuccess.match(action) || pinAccountSuccess.match(action) ||
unpinAccountSuccess.match(action) || unpinAccountSuccess.match(action) ||
isFulfilled(submitAccountNote)(action) isFulfilled(submitAccountNote)(action) ||
isFulfilled(removeAccountFromFollowers)(action)
) )
return normalizeRelationship(state, action.payload.relationship); return normalizeRelationship(state, action.payload.relationship);
else if (fetchRelationshipsSuccess.match(action)) else if (fetchRelationshipsSuccess.match(action))