diff --git a/app/javascript/flavours/glitch/actions/accounts_typed.ts b/app/javascript/flavours/glitch/actions/accounts_typed.ts index 22aaa48a0d..d9097591e0 100644 --- a/app/javascript/flavours/glitch/actions/accounts_typed.ts +++ b/app/javascript/flavours/glitch/actions/accounts_typed.ts @@ -1,7 +1,9 @@ import { createAction } from '@reduxjs/toolkit'; +import { apiRemoveAccountFromFollowers } from 'flavours/glitch/api/accounts'; import type { ApiAccountJSON } from 'flavours/glitch/api_types/accounts'; import type { ApiRelationshipJSON } from 'flavours/glitch/api_types/relationships'; +import { createDataLoadingThunk } from 'flavours/glitch/store/typed_functions'; export const revealAccount = createAction<{ id: string; @@ -95,3 +97,10 @@ export const fetchRelationshipsSuccess = createAction( 'relationships/fetch/SUCCESS', actionWithSkipLoadingTrue<{ relationships: ApiRelationshipJSON[] }>, ); + +export const removeAccountFromFollowers = createDataLoadingThunk( + 'accounts/remove_from_followers', + ({ accountId }: { accountId: string }) => + apiRemoveAccountFromFollowers(accountId), + (relationship) => ({ relationship }), +); diff --git a/app/javascript/flavours/glitch/api/accounts.ts b/app/javascript/flavours/glitch/api/accounts.ts index 4d68885088..8b02ca06d0 100644 --- a/app/javascript/flavours/glitch/api/accounts.ts +++ b/app/javascript/flavours/glitch/api/accounts.ts @@ -18,3 +18,8 @@ export const apiFollowAccount = ( export const apiUnfollowAccount = (id: string) => apiRequestPost(`v1/accounts/${id}/unfollow`); + +export const apiRemoveAccountFromFollowers = (id: string) => + apiRequestPost( + `v1/accounts/${id}/remove_from_followers`, + ); diff --git a/app/javascript/flavours/glitch/features/account_timeline/components/account_header.tsx b/app/javascript/flavours/glitch/features/account_timeline/components/account_header.tsx index 6b3783bd79..32a942cb54 100644 --- a/app/javascript/flavours/glitch/features/account_timeline/components/account_header.tsx +++ b/app/javascript/flavours/glitch/features/account_timeline/components/account_header.tsx @@ -18,6 +18,7 @@ import { unmuteAccount, pinAccount, unpinAccount, + removeAccountFromFollowers, } from 'flavours/glitch/actions/accounts'; import { initBlockModal } from 'flavours/glitch/actions/blocks'; import { mentionCompose, directCompose } from 'flavours/glitch/actions/compose'; @@ -156,6 +157,23 @@ const messages = defineMessages({ id: 'account.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) => { @@ -498,6 +516,39 @@ export const AccountHeader: React.FC<{ 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: {account.acct} }, + ), + 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) { arr.push({ text: intl.formatMessage(messages.unmute, { @@ -596,6 +647,8 @@ export const AccountHeader: React.FC<{ return arr; }, [ + dispatch, + accountId, account, relationship, permissions, diff --git a/app/javascript/flavours/glitch/reducers/relationships.ts b/app/javascript/flavours/glitch/reducers/relationships.ts index 6ef84b0bb7..9ada09d45e 100644 --- a/app/javascript/flavours/glitch/reducers/relationships.ts +++ b/app/javascript/flavours/glitch/reducers/relationships.ts @@ -24,6 +24,7 @@ import { pinAccountSuccess, unpinAccountSuccess, fetchRelationshipsSuccess, + removeAccountFromFollowers, } from '../actions/accounts_typed'; import { blockDomainSuccess, @@ -109,7 +110,8 @@ export const relationshipsReducer: Reducer = ( unmuteAccountSuccess.match(action) || pinAccountSuccess.match(action) || unpinAccountSuccess.match(action) || - isFulfilled(submitAccountNote)(action) + isFulfilled(submitAccountNote)(action) || + isFulfilled(removeAccountFromFollowers)(action) ) return normalizeRelationship(state, action.payload.relationship); else if (fetchRelationshipsSuccess.match(action))