pl-fe: migrate account actions to tanstack query
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@@ -12,7 +12,6 @@ import {
|
||||
fetchAccountByUsername,
|
||||
fetchRelationships,
|
||||
muteAccount,
|
||||
removeFromFollowers,
|
||||
unblockAccount,
|
||||
unmuteAccount,
|
||||
} from './accounts';
|
||||
@@ -775,72 +774,6 @@ describe('unsubscribeAccount()', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeFromFollowers()', () => {
|
||||
const id = '1';
|
||||
|
||||
describe('when logged out', () => {
|
||||
beforeEach(() => {
|
||||
const state = { ...rootState, me: null };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
it('should do nothing', async() => {
|
||||
await store.dispatch(removeFromFollowers(id));
|
||||
const actions = store.getActions();
|
||||
|
||||
expect(actions).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when logged in', () => {
|
||||
beforeEach(() => {
|
||||
const state = { ...rootState, me: '123' };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
describe('with a successful API request', () => {
|
||||
beforeEach(() => {
|
||||
__stub((mock) => {
|
||||
mock.onPost(`/api/v1/accounts/${id}/remove_from_followers`).reply(200, {});
|
||||
});
|
||||
});
|
||||
|
||||
it('should dispatch the correct actions', async() => {
|
||||
const expectedActions = [
|
||||
{ type: 'ACCOUNT_REMOVE_FROM_FOLLOWERS_REQUEST', id },
|
||||
{
|
||||
type: 'ACCOUNT_REMOVE_FROM_FOLLOWERS_SUCCESS',
|
||||
relationship: {},
|
||||
},
|
||||
];
|
||||
await store.dispatch(removeFromFollowers(id));
|
||||
const actions = store.getActions();
|
||||
|
||||
expect(actions).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with an unsuccessful API request', () => {
|
||||
beforeEach(() => {
|
||||
__stub((mock) => {
|
||||
mock.onPost(`/api/v1/accounts/${id}/remove_from_followers`).networkError();
|
||||
});
|
||||
});
|
||||
|
||||
it('should dispatch the correct actions', async() => {
|
||||
const expectedActions = [
|
||||
{ type: 'ACCOUNT_REMOVE_FROM_FOLLOWERS_REQUEST', id },
|
||||
{ type: 'ACCOUNT_REMOVE_FROM_FOLLOWERS_FAIL', id, error: new Error('Network Error') },
|
||||
];
|
||||
await store.dispatch(removeFromFollowers(id));
|
||||
const actions = store.getActions();
|
||||
|
||||
expect(actions).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('fetchRelationships()', () => {
|
||||
const id = '1';
|
||||
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
type UpdateNotificationSettingsParams,
|
||||
type CreateAccountParams,
|
||||
type Relationship,
|
||||
type MuteAccountParams,
|
||||
} from 'pl-api';
|
||||
import { type CreateAccountParams, type Relationship } from 'pl-api';
|
||||
|
||||
import { queryClient } from 'pl-fe/queries/client';
|
||||
import { selectAccount } from 'pl-fe/selectors';
|
||||
@@ -13,13 +8,11 @@ import { getClient, type PlfeResponse } from '../api';
|
||||
|
||||
import { importEntities } from './importer';
|
||||
|
||||
import type { MinifiedSuggestion } from 'pl-fe/queries/trends/use-suggested-accounts';
|
||||
import type { MinifiedStatus } from 'pl-fe/reducers/statuses';
|
||||
import type { AppDispatch, RootState } from 'pl-fe/store';
|
||||
import type { History } from 'pl-fe/types/history';
|
||||
|
||||
const ACCOUNT_BLOCK_SUCCESS = 'ACCOUNT_BLOCK_SUCCESS' as const;
|
||||
|
||||
const ACCOUNT_MUTE_SUCCESS = 'ACCOUNT_MUTE_SUCCESS' as const;
|
||||
|
||||
const maybeRedirectLogin = (error: { response: PlfeResponse }, history?: History) => {
|
||||
@@ -29,8 +22,6 @@ const maybeRedirectLogin = (error: { response: PlfeResponse }, history?: History
|
||||
}
|
||||
};
|
||||
|
||||
const noOp = () => new Promise(f => f(undefined));
|
||||
|
||||
const createAccount = (params: CreateAccountParams) =>
|
||||
async (dispatch: AppDispatch, getState: () => RootState) =>
|
||||
getClient(getState()).settings.createAccount(params).then((response) =>
|
||||
@@ -84,88 +75,6 @@ const fetchAccountByUsername = (username: string, history?: History) =>
|
||||
}
|
||||
};
|
||||
|
||||
const blockAccount = (accountId: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return null;
|
||||
|
||||
return getClient(getState).filtering.blockAccount(accountId)
|
||||
.then(response => {
|
||||
dispatch(importEntities({ relationships: [response] }));
|
||||
|
||||
queryClient.setQueryData<Array<MinifiedSuggestion>>(['suggestions'], suggestions => suggestions
|
||||
? suggestions.filter((suggestion) => suggestion.account_id !== accountId)
|
||||
: undefined);
|
||||
|
||||
// Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers
|
||||
return dispatch(blockAccountSuccess(response, getState().statuses));
|
||||
});
|
||||
};
|
||||
|
||||
const unblockAccount = (accountId: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return null;
|
||||
|
||||
return getClient(getState).filtering.unblockAccount(accountId)
|
||||
.then(response => {
|
||||
dispatch(importEntities({ relationships: [response] }));
|
||||
});
|
||||
};
|
||||
|
||||
const blockAccountSuccess = (relationship: Relationship, statuses: Record<string, MinifiedStatus>) => ({
|
||||
type: ACCOUNT_BLOCK_SUCCESS,
|
||||
relationship,
|
||||
statuses,
|
||||
});
|
||||
|
||||
const muteAccount = (accountId: string, notifications?: boolean, duration = 0) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return null;
|
||||
|
||||
const client = getClient(getState);
|
||||
|
||||
const params: MuteAccountParams = {
|
||||
notifications,
|
||||
};
|
||||
|
||||
if (duration) {
|
||||
params.duration = duration;
|
||||
}
|
||||
|
||||
return client.filtering.muteAccount(accountId, params)
|
||||
.then(response => {
|
||||
dispatch(importEntities({ relationships: [response] }));
|
||||
|
||||
queryClient.setQueryData<Array<MinifiedSuggestion>>(['suggestions'], suggestions => suggestions
|
||||
? suggestions.filter((suggestion) => suggestion.account_id !== accountId)
|
||||
: undefined);
|
||||
|
||||
// Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers
|
||||
return dispatch(muteAccountSuccess(response, getState().statuses));
|
||||
});
|
||||
};
|
||||
|
||||
const unmuteAccount = (accountId: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return null;
|
||||
|
||||
return getClient(getState()).filtering.unmuteAccount(accountId)
|
||||
.then(response => dispatch(importEntities({ relationships: [response] })));
|
||||
};
|
||||
|
||||
const muteAccountSuccess = (relationship: Relationship, statuses: Record<string, MinifiedStatus>) => ({
|
||||
type: ACCOUNT_MUTE_SUCCESS,
|
||||
relationship,
|
||||
statuses,
|
||||
});
|
||||
|
||||
const removeFromFollowers = (accountId: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return null;
|
||||
|
||||
return getClient(getState()).accounts.removeAccountFromFollowers(accountId)
|
||||
.then(response => dispatch(importEntities({ relationships: [response] })));
|
||||
};
|
||||
|
||||
const fetchRelationships = (accountIds: string[]) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return null;
|
||||
@@ -180,28 +89,6 @@ const fetchRelationships = (accountIds: string[]) =>
|
||||
.then(response => dispatch(importEntities({ relationships: response })));
|
||||
};
|
||||
|
||||
const pinAccount = (accountId: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return dispatch(noOp);
|
||||
|
||||
return getClient(getState).accounts.pinAccount(accountId).then(response =>
|
||||
dispatch(importEntities({ relationships: [response] })),
|
||||
);
|
||||
};
|
||||
|
||||
const unpinAccount = (accountId: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return dispatch(noOp);
|
||||
|
||||
return getClient(getState).accounts.unpinAccount(accountId).then(response =>
|
||||
dispatch(importEntities({ relationships: [response] })),
|
||||
);
|
||||
};
|
||||
|
||||
const updateNotificationSettings = (params: UpdateNotificationSettingsParams) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) =>
|
||||
getClient(getState).settings.updateNotificationSettings(params).then((data) => ({ params, data }));
|
||||
|
||||
const accountLookup = (acct: string, signal?: AbortSignal) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) =>
|
||||
getClient(getState()).accounts.lookupAccount(acct, { signal }).then((account) => {
|
||||
@@ -209,13 +96,11 @@ const accountLookup = (acct: string, signal?: AbortSignal) =>
|
||||
return account;
|
||||
});
|
||||
|
||||
const biteAccount = (accountId: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) =>
|
||||
getClient(getState).accounts.biteAccount(accountId);
|
||||
|
||||
type AccountsAction =
|
||||
| ReturnType<typeof blockAccountSuccess>
|
||||
| ReturnType<typeof muteAccountSuccess>;
|
||||
type AccountsAction = {
|
||||
type: typeof ACCOUNT_BLOCK_SUCCESS | typeof ACCOUNT_MUTE_SUCCESS;
|
||||
relationship: Relationship;
|
||||
statuses: Record<string, MinifiedStatus>;
|
||||
};
|
||||
|
||||
export {
|
||||
ACCOUNT_BLOCK_SUCCESS,
|
||||
@@ -223,16 +108,7 @@ export {
|
||||
createAccount,
|
||||
fetchAccount,
|
||||
fetchAccountByUsername,
|
||||
blockAccount,
|
||||
unblockAccount,
|
||||
muteAccount,
|
||||
unmuteAccount,
|
||||
removeFromFollowers,
|
||||
fetchRelationships,
|
||||
pinAccount,
|
||||
unpinAccount,
|
||||
updateNotificationSettings,
|
||||
accountLookup,
|
||||
biteAccount,
|
||||
type AccountsAction,
|
||||
};
|
||||
|
||||
@@ -158,7 +158,7 @@ const DropdownMenuContent: React.FC<IDropdownMenuContent> = ({ handleClose, item
|
||||
{Component && <Component handleClose={handleClose} />}
|
||||
{(items?.length || touchscreen) && renderItems(items)}
|
||||
</div>
|
||||
<div className={clsx({ 'w-full': touchscreen, 'fit-content mr-auto': !touchscreen })} style={{ width }}>
|
||||
<div className={clsx({ 'w-full': touchscreen, 'fit-content mr-auto': !touchscreen })} style={{ width }}>
|
||||
{tab !== undefined && (
|
||||
<>
|
||||
<HStack className='mx-2 my-1 text-gray-700 dark:text-gray-300' space={3} alignItems='center'>
|
||||
|
||||
@@ -3,7 +3,6 @@ import React, { useCallback, useMemo } from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
import { useHistory, useRouteMatch } from 'react-router-dom';
|
||||
|
||||
import { blockAccount } from 'pl-fe/actions/accounts';
|
||||
import { redactStatus } from 'pl-fe/actions/admin';
|
||||
import { directCompose, mentionCompose, quoteCompose, replyCompose } from 'pl-fe/actions/compose';
|
||||
import { emojiReact, unEmojiReact } from 'pl-fe/actions/emoji-reacts';
|
||||
@@ -24,6 +23,7 @@ import { useClient } from 'pl-fe/hooks/use-client';
|
||||
import { useFeatures } from 'pl-fe/hooks/use-features';
|
||||
import { useInstance } from 'pl-fe/hooks/use-instance';
|
||||
import { useOwnAccount } from 'pl-fe/hooks/use-own-account';
|
||||
import { useBlockAccountMutation, useUnblockAccountMutation } from 'pl-fe/queries/accounts/use-relationship';
|
||||
import { useChats } from 'pl-fe/queries/chats';
|
||||
import { useBlockGroupUserMutation } from 'pl-fe/queries/groups/use-group-blocks';
|
||||
import { useCustomEmojis } from 'pl-fe/queries/instance/use-custom-emojis';
|
||||
@@ -50,6 +50,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}' },
|
||||
unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },
|
||||
blocked: { id: 'group.group_mod_block.success', defaultMessage: '@{name} is banned' },
|
||||
blockAndReport: { id: 'confirmations.block.block_and_report', defaultMessage: 'Block and report' },
|
||||
blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },
|
||||
@@ -579,6 +580,8 @@ const MenuButton: React.FC<IMenuButton> = ({
|
||||
const { mutate: unbookmarkStatus } = useUnbookmarkStatus(status.id);
|
||||
const { mutate: pinStatus } = usePinStatus(status?.id!);
|
||||
const { mutate: unpinStatus } = useUnpinStatus(status?.id!);
|
||||
const { mutate: blockAccount } = useBlockAccountMutation(status.account_id);
|
||||
const { mutate: unblockAccount } = useUnblockAccountMutation(status.account_id);
|
||||
|
||||
const { groupRelationship } = useGroupRelationship(status.group_id || undefined);
|
||||
const features = useFeatures();
|
||||
@@ -691,15 +694,19 @@ const MenuButton: React.FC<IMenuButton> = ({
|
||||
heading: <FormattedMessage id='confirmations.block.heading' defaultMessage='Block @{name}' values={{ name: account.acct }} />,
|
||||
message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong className='break-words'>@{account.acct}</strong> }} />,
|
||||
confirm: intl.formatMessage(messages.blockConfirm),
|
||||
onConfirm: () => dispatch(blockAccount(account.id)),
|
||||
onConfirm: () => blockAccount(),
|
||||
secondary: intl.formatMessage(messages.blockAndReport),
|
||||
onSecondary: () => {
|
||||
dispatch(blockAccount(account.id));
|
||||
blockAccount();
|
||||
dispatch(initReport(ReportableEntities.STATUS, account, { status }));
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const handleUnblockClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
unblockAccount();
|
||||
};
|
||||
|
||||
const handleEmbed = () => {
|
||||
openModal('EMBED', {
|
||||
url: status.url,
|
||||
@@ -973,11 +980,19 @@ const MenuButton: React.FC<IMenuButton> = ({
|
||||
action: handleMuteClick,
|
||||
icon: require('@phosphor-icons/core/regular/speaker-x.svg'),
|
||||
});
|
||||
menu.push({
|
||||
text: intl.formatMessage(messages.block, { name: username }),
|
||||
action: handleBlockClick,
|
||||
icon: require('@phosphor-icons/core/regular/prohibit.svg'),
|
||||
});
|
||||
if (status.account.relationship?.blocking) {
|
||||
menu.push({
|
||||
text: intl.formatMessage(messages.unblock, { name: username }),
|
||||
action: handleUnblockClick,
|
||||
icon: require('@phosphor-icons/core/regular/prohibit.svg'),
|
||||
});
|
||||
} else {
|
||||
menu.push({
|
||||
text: intl.formatMessage(messages.block, { name: username }),
|
||||
action: handleBlockClick,
|
||||
icon: require('@phosphor-icons/core/regular/prohibit.svg'),
|
||||
});
|
||||
}
|
||||
menu.push({
|
||||
text: intl.formatMessage(messages.report, { name: username }),
|
||||
action: handleReport,
|
||||
|
||||
@@ -6,7 +6,6 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import * as v from 'valibot';
|
||||
|
||||
import { biteAccount, blockAccount, pinAccount, removeFromFollowers, unblockAccount, unmuteAccount, unpinAccount } from 'pl-fe/actions/accounts';
|
||||
import { mentionCompose, directCompose } from 'pl-fe/actions/compose';
|
||||
import { initReport, ReportableEntities } from 'pl-fe/actions/reports';
|
||||
import Account from 'pl-fe/components/account';
|
||||
@@ -29,7 +28,15 @@ import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useClient } from 'pl-fe/hooks/use-client';
|
||||
import { useFeatures } from 'pl-fe/hooks/use-features';
|
||||
import { useOwnAccount } from 'pl-fe/hooks/use-own-account';
|
||||
import { useFollowMutation } from 'pl-fe/queries/accounts/use-relationship';
|
||||
import {
|
||||
useBlockAccountMutation,
|
||||
useFollowAccountMutation,
|
||||
usePinAccountMutation,
|
||||
useRemoveAccountFromFollowersMutation,
|
||||
useUnblockAccountMutation,
|
||||
useUnmuteAccountMutation,
|
||||
useUnpinAccountMutation,
|
||||
} from 'pl-fe/queries/accounts/use-relationship';
|
||||
import { useChats } from 'pl-fe/queries/chats';
|
||||
import { queryClient } from 'pl-fe/queries/client';
|
||||
import { blockDomainMutationOptions, unblockDomainMutationOptions } from 'pl-fe/queries/settings/domain-blocks';
|
||||
@@ -134,7 +141,13 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
||||
|
||||
const features = useFeatures();
|
||||
const { account: ownAccount } = useOwnAccount();
|
||||
const { mutate: follow } = useFollowMutation(account?.id!);
|
||||
const { mutate: followAccount } = useFollowAccountMutation(account?.id!);
|
||||
const { mutate: blockAccount } = useBlockAccountMutation(account?.id!);
|
||||
const { mutate: unblockAccount } = useUnblockAccountMutation(account?.id!);
|
||||
const { mutate: unmuteAccount } = useUnmuteAccountMutation(account?.id!);
|
||||
const { mutate: pinAccount } = usePinAccountMutation(account?.id!);
|
||||
const { mutate: unpinAccount } = useUnpinAccountMutation(account?.id!);
|
||||
const { mutate: removeFromFollowers } = useRemoveAccountFromFollowersMutation(account?.id!);
|
||||
const { openModal } = useModalsActions();
|
||||
const settings = useSettings();
|
||||
|
||||
@@ -181,16 +194,16 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
||||
|
||||
const onBlock = () => {
|
||||
if (account.relationship?.blocking) {
|
||||
dispatch(unblockAccount(account.id));
|
||||
unblockAccount();
|
||||
} else {
|
||||
openModal('CONFIRM', {
|
||||
heading: <FormattedMessage id='confirmations.block.heading' defaultMessage='Block @{name}' values={{ name: account.acct }} />,
|
||||
message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong className='break-words'>@{account.acct}</strong> }} />,
|
||||
confirm: intl.formatMessage(messages.blockConfirm),
|
||||
onConfirm: () => dispatch(blockAccount(account.id)),
|
||||
onConfirm: () => blockAccount(),
|
||||
secondary: intl.formatMessage(messages.blockAndReport),
|
||||
onSecondary: () => {
|
||||
dispatch(blockAccount(account.id));
|
||||
blockAccount();
|
||||
dispatch(initReport(ReportableEntities.ACCOUNT, account));
|
||||
},
|
||||
});
|
||||
@@ -207,26 +220,26 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
||||
|
||||
const onReblogToggle = () => {
|
||||
if (account.relationship?.showing_reblogs) {
|
||||
follow({ reblogs: false });
|
||||
followAccount({ reblogs: false });
|
||||
} else {
|
||||
follow({ reblogs: true });
|
||||
followAccount({ reblogs: true });
|
||||
}
|
||||
};
|
||||
|
||||
const onEndorseToggle = () => {
|
||||
if (account.relationship?.endorsed) {
|
||||
dispatch(unpinAccount(account.id))
|
||||
.then(() => toast.success(intl.formatMessage(messages.userUnendorsed, { acct: account.acct })))
|
||||
.catch(() => { });
|
||||
unpinAccount(undefined, {
|
||||
onSuccess: () => toast.success(intl.formatMessage(messages.userUnendorsed, { acct: account.acct })),
|
||||
});
|
||||
} else {
|
||||
dispatch(pinAccount(account.id))
|
||||
.then(() => toast.success(intl.formatMessage(messages.userEndorsed, { acct: account.acct })))
|
||||
.catch(() => { });
|
||||
pinAccount(undefined, {
|
||||
onSuccess: () => toast.success(intl.formatMessage(messages.userEndorsed, { acct: account.acct })),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const onBite = () => {
|
||||
dispatch(biteAccount(account.id))
|
||||
client.accounts.biteAccount(account.id)
|
||||
.then(() => toast.success(intl.formatMessage(messages.userBit, { acct: account.acct })))
|
||||
.catch(() => toast.error(intl.formatMessage(messages.userBiteFail, { acct: account.acct })));
|
||||
};
|
||||
@@ -243,7 +256,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
||||
|
||||
const onMute = () => {
|
||||
if (account.relationship?.muting) {
|
||||
dispatch(unmuteAccount(account.id));
|
||||
unmuteAccount();
|
||||
} else {
|
||||
openModal('MUTE', { accountId: account.id });
|
||||
}
|
||||
@@ -279,10 +292,10 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
||||
heading: <FormattedMessage id='confirmations.remove_from_followers.heading' defaultMessage='Remove {name} from followers' values={{ name: <strong className='break-words'>@{account.acct}</strong> }} />,
|
||||
message: <FormattedMessage id='confirmations.remove_from_followers.message' defaultMessage='Are you sure you want to remove {name} from your followers?' values={{ name: <strong className='break-words'>@{account.acct}</strong> }} />,
|
||||
confirm: intl.formatMessage(messages.removeFromFollowersConfirm),
|
||||
onConfirm: () => dispatch(removeFromFollowers(account.id)),
|
||||
onConfirm: () => removeFromFollowers(),
|
||||
});
|
||||
} else {
|
||||
dispatch(removeFromFollowers(account.id));
|
||||
removeFromFollowers();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
import { defineMessages, IntlShape, useIntl } from 'react-intl';
|
||||
|
||||
import { unblockAccount } from 'pl-fe/actions/accounts';
|
||||
import Button from 'pl-fe/components/ui/button';
|
||||
import Combobox, { ComboboxInput, ComboboxList, ComboboxOption, ComboboxPopover } from 'pl-fe/components/ui/combobox';
|
||||
import HStack from 'pl-fe/components/ui/hstack';
|
||||
@@ -11,9 +10,8 @@ import Text from 'pl-fe/components/ui/text';
|
||||
import { useChatContext } from 'pl-fe/contexts/chat-context';
|
||||
import UploadButton from 'pl-fe/features/compose/components/upload-button';
|
||||
import emojiSearch from 'pl-fe/features/emoji/search';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useInstance } from 'pl-fe/hooks/use-instance';
|
||||
import { useRelationshipQuery } from 'pl-fe/queries/accounts/use-relationship';
|
||||
import { useRelationshipQuery, useUnblockAccountMutation } from 'pl-fe/queries/accounts/use-relationship';
|
||||
import { useModalsActions } from 'pl-fe/stores/modals';
|
||||
import { textAtCursorMatchesToken } from 'pl-fe/utils/suggestions';
|
||||
|
||||
@@ -76,11 +74,11 @@ const ChatComposer = React.forwardRef<HTMLTextAreaElement | null, IChatComposer>
|
||||
uploadProgress,
|
||||
}, ref) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const { openModal } = useModalsActions();
|
||||
const { chat } = useChatContext();
|
||||
const { data: relationship } = useRelationshipQuery(chat?.account.id);
|
||||
const { mutate: unblockAccount } = useUnblockAccountMutation(chat?.account.id!);
|
||||
|
||||
const isBlocked = relationship?.blocked_by && false;
|
||||
const isBlocking = relationship?.blocking && false;
|
||||
@@ -146,7 +144,7 @@ const ChatComposer = React.forwardRef<HTMLTextAreaElement | null, IChatComposer>
|
||||
message: intl.formatMessage(messages.unblockMessage),
|
||||
confirm: intl.formatMessage(messages.unblockConfirm),
|
||||
confirmationTheme: 'primary',
|
||||
onConfirm: () => dispatch(unblockAccount(chat?.account.id as string)),
|
||||
onConfirm: () => unblockAccount(),
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ import React, { useRef } from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import { Link, useHistory, useParams } from 'react-router-dom';
|
||||
|
||||
import { blockAccount, unblockAccount } from 'pl-fe/actions/accounts';
|
||||
import DropdownMenu, { type Menu } from 'pl-fe/components/dropdown-menu';
|
||||
import Avatar from 'pl-fe/components/ui/avatar';
|
||||
import HStack from 'pl-fe/components/ui/hstack';
|
||||
@@ -11,9 +10,8 @@ import Stack from 'pl-fe/components/ui/stack';
|
||||
import Text from 'pl-fe/components/ui/text';
|
||||
import VerificationBadge from 'pl-fe/components/verification-badge';
|
||||
import { useChatContext } from 'pl-fe/contexts/chat-context';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useFeatures } from 'pl-fe/hooks/use-features';
|
||||
import { useRelationshipQuery } from 'pl-fe/queries/accounts/use-relationship';
|
||||
import { useBlockAccountMutation, useUnblockAccountMutation, useRelationshipQuery } from 'pl-fe/queries/accounts/use-relationship';
|
||||
import { useChat, useChatActions, useChats } from 'pl-fe/queries/chats';
|
||||
import { useModalsActions } from 'pl-fe/stores/modals';
|
||||
|
||||
@@ -38,7 +36,6 @@ const messages = defineMessages({
|
||||
});
|
||||
|
||||
const ChatPageMain = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const intl = useIntl();
|
||||
const features = useFeatures();
|
||||
const history = useHistory();
|
||||
@@ -50,6 +47,9 @@ const ChatPageMain = () => {
|
||||
const { currentChatId } = useChatContext();
|
||||
const { chatsQuery: { data: chats, isLoading } } = useChats();
|
||||
|
||||
const { mutate: blockAccount } = useBlockAccountMutation(chat?.account.id!);
|
||||
const { mutate: unblockAccount } = useUnblockAccountMutation(chat?.account.id!);
|
||||
|
||||
const inputRef = useRef<HTMLTextAreaElement | null>(null);
|
||||
|
||||
const { deleteChat } = useChatActions(chat?.id as string);
|
||||
@@ -62,7 +62,7 @@ const ChatPageMain = () => {
|
||||
message: intl.formatMessage(messages.blockMessage),
|
||||
confirm: intl.formatMessage(messages.blockConfirm),
|
||||
confirmationTheme: 'primary',
|
||||
onConfirm: () => dispatch(blockAccount(chat?.account.id as string)),
|
||||
onConfirm: () => blockAccount(),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -72,7 +72,7 @@ const ChatPageMain = () => {
|
||||
message: intl.formatMessage(messages.unblockMessage),
|
||||
confirm: intl.formatMessage(messages.unblockConfirm),
|
||||
confirmationTheme: 'primary',
|
||||
onConfirm: () => dispatch(unblockAccount(chat?.account.id as string)),
|
||||
onConfirm: () => unblockAccount(),
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import React from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { blockAccount, unblockAccount } from 'pl-fe/actions/accounts';
|
||||
import Avatar from 'pl-fe/components/ui/avatar';
|
||||
import HStack from 'pl-fe/components/ui/hstack';
|
||||
import Icon from 'pl-fe/components/ui/icon';
|
||||
import Stack from 'pl-fe/components/ui/stack';
|
||||
import Text from 'pl-fe/components/ui/text';
|
||||
import { ChatWidgetScreens, useChatContext } from 'pl-fe/contexts/chat-context';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useFeatures } from 'pl-fe/hooks/use-features';
|
||||
import { useRelationshipQuery } from 'pl-fe/queries/accounts/use-relationship';
|
||||
import { useBlockAccountMutation, useUnblockAccountMutation, useRelationshipQuery } from 'pl-fe/queries/accounts/use-relationship';
|
||||
import { useChatActions } from 'pl-fe/queries/chats';
|
||||
import { useModalsActions } from 'pl-fe/stores/modals';
|
||||
|
||||
@@ -33,7 +31,6 @@ const messages = defineMessages({
|
||||
});
|
||||
|
||||
const ChatSettings = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const intl = useIntl();
|
||||
const features = useFeatures();
|
||||
|
||||
@@ -41,6 +38,9 @@ const ChatSettings = () => {
|
||||
const { chat, changeScreen, toggleChatPane } = useChatContext();
|
||||
const { deleteChat } = useChatActions(chat?.id as string);
|
||||
|
||||
const { mutate: blockAccount } = useBlockAccountMutation(chat?.account.id!);
|
||||
const { mutate: unblockAccount } = useUnblockAccountMutation(chat?.account.id!);
|
||||
|
||||
const isBlocked = !!useRelationshipQuery(chat?.account.id).data?.blocked_by;
|
||||
|
||||
const closeSettings = () => {
|
||||
@@ -58,7 +58,7 @@ const ChatSettings = () => {
|
||||
message: intl.formatMessage(messages.blockMessage),
|
||||
confirm: intl.formatMessage(messages.blockConfirm),
|
||||
confirmationTheme: 'primary',
|
||||
onConfirm: () => dispatch(blockAccount(chat?.account.id as string)),
|
||||
onConfirm: () => blockAccount(),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -68,7 +68,7 @@ const ChatSettings = () => {
|
||||
message: intl.formatMessage(messages.unblockMessage),
|
||||
confirm: intl.formatMessage(messages.unblockConfirm),
|
||||
confirmationTheme: 'primary',
|
||||
onConfirm: () => dispatch(unblockAccount(chat?.account.id as string)),
|
||||
onConfirm: () => unblockAccount(),
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ import React from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
import { Link, useHistory } from 'react-router-dom';
|
||||
|
||||
import { blockAccount } from 'pl-fe/actions/accounts';
|
||||
import { directCompose, mentionCompose, quoteCompose } from 'pl-fe/actions/compose';
|
||||
import { fetchEventIcs } from 'pl-fe/actions/events';
|
||||
import { deleteStatusModal, toggleStatusSensitivityModal } from 'pl-fe/actions/moderation';
|
||||
@@ -21,6 +20,7 @@ import Emojify from 'pl-fe/features/emoji/emojify';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useFeatures } from 'pl-fe/hooks/use-features';
|
||||
import { useOwnAccount } from 'pl-fe/hooks/use-own-account';
|
||||
import { useBlockAccountMutation } from 'pl-fe/queries/accounts/use-relationship';
|
||||
import { useChats } from 'pl-fe/queries/chats';
|
||||
import { useBookmarkStatus, usePinStatus, useReblogStatus, useUnbookmarkStatus, useUnpinStatus, useUnreblogStatus } from 'pl-fe/queries/statuses/use-status-interactions';
|
||||
import { useModalsActions } from 'pl-fe/stores/modals';
|
||||
@@ -95,6 +95,7 @@ const EventHeader: React.FC<IEventHeader> = ({ status }) => {
|
||||
const { mutate: unbookmarkStatus } = useUnbookmarkStatus(status?.id!);
|
||||
const { mutate: pinStatus } = usePinStatus(status?.id!);
|
||||
const { mutate: unpinStatus } = useUnpinStatus(status?.id!);
|
||||
const { mutate: blockAccount } = useBlockAccountMutation(status?.account.id!);
|
||||
|
||||
if (!status || !status.event) {
|
||||
return (
|
||||
@@ -191,10 +192,10 @@ const EventHeader: React.FC<IEventHeader> = ({ status }) => {
|
||||
heading: <FormattedMessage id='confirmations.block.heading' defaultMessage='Block @{name}' values={{ name: account.acct }} />,
|
||||
message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.acct}</strong> }} />,
|
||||
confirm: intl.formatMessage(messages.blockConfirm),
|
||||
onConfirm: () => dispatch(blockAccount(account.id)),
|
||||
onConfirm: () => blockAccount(),
|
||||
secondary: intl.formatMessage(messages.blockAndReport),
|
||||
onSecondary: () => {
|
||||
dispatch(blockAccount(account.id));
|
||||
blockAccount();
|
||||
dispatch(initReport(ReportableEntities.STATUS, account, { status }));
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
import React from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import {
|
||||
blockAccount,
|
||||
unblockAccount,
|
||||
muteAccount,
|
||||
unmuteAccount,
|
||||
biteAccount,
|
||||
} from 'pl-fe/actions/accounts';
|
||||
import Button from 'pl-fe/components/ui/button';
|
||||
import HStack from 'pl-fe/components/ui/hstack';
|
||||
import Spinner from 'pl-fe/components/ui/spinner';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useClient } from 'pl-fe/hooks/use-client';
|
||||
import { useFeatures } from 'pl-fe/hooks/use-features';
|
||||
import { useLoggedIn } from 'pl-fe/hooks/use-logged-in';
|
||||
import { useAcceptFollowRequestMutation, useRejectFollowRequestMutation } from 'pl-fe/queries/accounts/use-follow-requests';
|
||||
import { useRelationshipQuery, useFollowMutation, useUnfollowMutation } from 'pl-fe/queries/accounts/use-relationship';
|
||||
import {
|
||||
useRelationshipQuery,
|
||||
useBlockAccountMutation,
|
||||
useUnblockAccountMutation,
|
||||
useMuteAccountMutation,
|
||||
useUnmuteAccountMutation,
|
||||
useFollowAccountMutation,
|
||||
useUnfollowAccountMutation,
|
||||
} from 'pl-fe/queries/accounts/use-relationship';
|
||||
import { useModalsActions } from 'pl-fe/stores/modals';
|
||||
import toast from 'pl-fe/toast';
|
||||
|
||||
@@ -55,15 +56,19 @@ interface IActionButton {
|
||||
* `actionType` prop.
|
||||
*/
|
||||
const ActionButton: React.FC<IActionButton> = ({ account, actionType, small = true }) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const features = useFeatures();
|
||||
const intl = useIntl();
|
||||
const client = useClient();
|
||||
|
||||
const { openModal } = useModalsActions();
|
||||
const { isLoggedIn, me } = useLoggedIn();
|
||||
|
||||
const { mutate: follow, isPending: isPendingFollow } = useFollowMutation(account.id);
|
||||
const { mutate: unfollow, isPending: isPendingUnfollow } = useUnfollowMutation(account.id);
|
||||
const { mutate: followAccount, isPending: isPendingFollow } = useFollowAccountMutation(account.id);
|
||||
const { mutate: unfollowAccount, isPending: isPendingUnfollow } = useUnfollowAccountMutation(account.id);
|
||||
const { mutate: blockAccount } = useBlockAccountMutation(account.id);
|
||||
const { mutate: unblockAccount } = useUnblockAccountMutation(account.id);
|
||||
const { mutate: muteAccount } = useMuteAccountMutation(account.id);
|
||||
const { mutate: unmuteAccount } = useUnmuteAccountMutation(account.id);
|
||||
|
||||
const { data: relationship, isLoading } = useRelationshipQuery(account.id);
|
||||
|
||||
@@ -72,25 +77,25 @@ const ActionButton: React.FC<IActionButton> = ({ account, actionType, small = tr
|
||||
|
||||
const handleFollow = () => {
|
||||
if (relationship?.following || relationship?.requested) {
|
||||
unfollow();
|
||||
unfollowAccount();
|
||||
} else {
|
||||
follow(undefined);
|
||||
followAccount(undefined);
|
||||
}
|
||||
};
|
||||
|
||||
const handleBlock = () => {
|
||||
if (relationship?.blocking) {
|
||||
dispatch(unblockAccount(account.id));
|
||||
unblockAccount();
|
||||
} else {
|
||||
dispatch(blockAccount(account.id));
|
||||
blockAccount();
|
||||
}
|
||||
};
|
||||
|
||||
const handleMute = () => {
|
||||
if (relationship?.muting) {
|
||||
dispatch(unmuteAccount(account.id));
|
||||
unmuteAccount();
|
||||
} else {
|
||||
dispatch(muteAccount(account.id));
|
||||
muteAccount(undefined);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -103,7 +108,7 @@ const ActionButton: React.FC<IActionButton> = ({ account, actionType, small = tr
|
||||
};
|
||||
|
||||
const handleBite = () => {
|
||||
dispatch(biteAccount(account.id))
|
||||
client.accounts.biteAccount(account.id)
|
||||
.then(() => toast.success(intl.formatMessage(messages.userBit, { acct: account.acct })))
|
||||
.catch(() => toast.error(intl.formatMessage(messages.userBiteFail, { acct: account.acct })));
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@ import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import IconButton from 'pl-fe/components/ui/icon-button';
|
||||
import { useFeatures } from 'pl-fe/hooks/use-features';
|
||||
import { useFollowMutation } from 'pl-fe/queries/accounts/use-relationship';
|
||||
import { useFollowAccountMutation } from 'pl-fe/queries/accounts/use-relationship';
|
||||
import toast from 'pl-fe/toast';
|
||||
|
||||
import type { Account as AccountEntity } from 'pl-fe/normalizers/account';
|
||||
@@ -24,7 +24,7 @@ interface ISubscriptionButton {
|
||||
const SubscriptionButton = ({ account }: ISubscriptionButton) => {
|
||||
const features = useFeatures();
|
||||
const intl = useIntl();
|
||||
const { mutate: follow, isPending } = useFollowMutation(account.id);
|
||||
const { mutate: follow, isPending } = useFollowAccountMutation(account.id);
|
||||
|
||||
const isFollowing = account.relationship?.following;
|
||||
const isRequested = account.relationship?.requested;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { muteAccount } from 'pl-fe/actions/accounts';
|
||||
import { useAccount } from 'pl-fe/api/hooks/accounts/use-account';
|
||||
import HStack from 'pl-fe/components/ui/hstack';
|
||||
import Modal from 'pl-fe/components/ui/modal';
|
||||
@@ -9,8 +8,8 @@ import Stack from 'pl-fe/components/ui/stack';
|
||||
import Text from 'pl-fe/components/ui/text';
|
||||
import Toggle from 'pl-fe/components/ui/toggle';
|
||||
import DurationSelector from 'pl-fe/features/compose/components/polls/duration-selector';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useFeatures } from 'pl-fe/hooks/use-features';
|
||||
import { useMuteAccountMutation } from 'pl-fe/queries/accounts/use-relationship';
|
||||
|
||||
import type { BaseModalProps } from 'pl-fe/features/ui/components/modal-root';
|
||||
|
||||
@@ -19,21 +18,23 @@ interface MuteModalProps {
|
||||
}
|
||||
|
||||
const MuteModal: React.FC<MuteModalProps & BaseModalProps> = ({ accountId, onClose }) => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const { account } = useAccount(accountId || undefined);
|
||||
const [notifications, setNotifications] = useState(true);
|
||||
const [duration, setDuration] = useState(0);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const mutesDuration = useFeatures().mutesDuration;
|
||||
|
||||
const { mutate: muteAccount } = useMuteAccountMutation(accountId);
|
||||
|
||||
if (!account) return null;
|
||||
|
||||
const handleClick = () => {
|
||||
setIsSubmitting(true);
|
||||
dispatch(muteAccount(account.id, notifications, duration))?.then(() => {
|
||||
setIsSubmitting(false);
|
||||
onClose('MUTE');
|
||||
muteAccount({ notifications, duration }, {
|
||||
onSuccess: () => {
|
||||
setIsSubmitting(false);
|
||||
onClose('MUTE');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import { blockAccount } from 'pl-fe/actions/accounts';
|
||||
import { submitReport, ReportableEntities } from 'pl-fe/actions/reports';
|
||||
import { fetchAccountTimeline } from 'pl-fe/actions/timelines';
|
||||
import { useAccount } from 'pl-fe/api/hooks/accounts/use-account';
|
||||
@@ -15,6 +14,7 @@ import AccountContainer from 'pl-fe/containers/account-container';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
|
||||
import { useInstance } from 'pl-fe/hooks/use-instance';
|
||||
import { useBlockAccountMutation } from 'pl-fe/queries/accounts/use-relationship';
|
||||
|
||||
import ConfirmationStep from './steps/confirmation-step';
|
||||
import OtherActionsStep from './steps/other-actions-step';
|
||||
@@ -81,6 +81,8 @@ const ReportModal: React.FC<BaseModalProps & ReportModalProps> = ({ onClose, acc
|
||||
|
||||
const { account } = useAccount(accountId || undefined);
|
||||
|
||||
const { mutate: blockAccount } = useBlockAccountMutation(accountId);
|
||||
|
||||
const [block, setBlock] = useState(false);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const { rules } = useInstance();
|
||||
@@ -109,7 +111,7 @@ const ReportModal: React.FC<BaseModalProps & ReportModalProps> = ({ onClose, acc
|
||||
});
|
||||
|
||||
if (block && account) {
|
||||
dispatch(blockAccount(account.id));
|
||||
blockAccount();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -175,7 +175,7 @@ const ReportPage: React.FC<IReportPage> = (props) => {
|
||||
|
||||
<td className='p-2.5 text-end'>
|
||||
<Text size='sm'>
|
||||
<FormattedDate value={report.created_at} year='2-digit' month='short' day='2-digit' weekday='short' />
|
||||
<FormattedDate value={report.created_at} year='2-digit' month='short' day='2-digit' weekday='short' />
|
||||
</Text>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -3,7 +3,6 @@ import { type CredentialAccount, GOTOSOCIAL } from 'pl-api';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
|
||||
import { updateNotificationSettings } from 'pl-fe/actions/accounts';
|
||||
import { patchMe } from 'pl-fe/actions/me';
|
||||
import BirthdayInput from 'pl-fe/components/birthday-input';
|
||||
import List, { ListItem } from 'pl-fe/components/list';
|
||||
@@ -244,9 +243,9 @@ const EditProfilePage: React.FC = () => {
|
||||
|
||||
if (features.muteStrangers) {
|
||||
promises.push(
|
||||
dispatch(updateNotificationSettings({
|
||||
client.settings.updateNotificationSettings({
|
||||
block_from_strangers: muteStrangers,
|
||||
})).catch(console.error),
|
||||
}).catch(console.error),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,32 @@
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import { ACCOUNT_BLOCK_SUCCESS, ACCOUNT_MUTE_SUCCESS, type AccountsAction } from 'pl-fe/actions/accounts';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useClient } from 'pl-fe/hooks/use-client';
|
||||
import { useLoggedIn } from 'pl-fe/hooks/use-logged-in';
|
||||
|
||||
import type { FollowAccountParams, Relationship } from 'pl-api';
|
||||
import type { MinifiedSuggestion } from '../trends/use-suggested-accounts';
|
||||
import type { FollowAccountParams, MuteAccountParams, Relationship } from 'pl-api';
|
||||
|
||||
const updateRelationship = (accountId: string, changes: Partial<Relationship> | ((relationship: Relationship) => Relationship), queryClient: ReturnType<typeof useQueryClient>) => {
|
||||
const previousRelationship = queryClient.getQueryData<Relationship>(['accountRelationships', accountId]);
|
||||
if (!previousRelationship) return;
|
||||
|
||||
const newRelationship = typeof changes === 'function' ? changes(previousRelationship) : { ...previousRelationship, ...changes };
|
||||
queryClient.setQueryData(['accountRelationships', accountId], newRelationship);
|
||||
|
||||
return { previousRelationship };
|
||||
};
|
||||
|
||||
const restorePreviousRelationship = (
|
||||
accountId: string,
|
||||
context: { previousRelationship?: Relationship } | undefined,
|
||||
queryClient: ReturnType<typeof useQueryClient>,
|
||||
) => {
|
||||
if (context?.previousRelationship) {
|
||||
queryClient.setQueryData(['accountRelationships', accountId], context.previousRelationship);
|
||||
}
|
||||
};
|
||||
|
||||
const useRelationshipQuery = (accountId?: string) => {
|
||||
const client = useClient();
|
||||
@@ -16,7 +39,7 @@ const useRelationshipQuery = (accountId?: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
const useFollowMutation = (accountId: string) => {
|
||||
const useFollowAccountMutation = (accountId: string) => {
|
||||
const client = useClient();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
@@ -24,64 +47,204 @@ const useFollowMutation = (accountId: string) => {
|
||||
mutationKey: ['accountRelationships', accountId],
|
||||
mutationFn: (params?: FollowAccountParams) => client.accounts.followAccount(accountId, params),
|
||||
onMutate: (params) => {
|
||||
const previousRelationship = queryClient.getQueryData<Relationship>(['accountRelationships', accountId])!;
|
||||
|
||||
if (!previousRelationship) return;
|
||||
|
||||
const newRelationship: Relationship = {
|
||||
...previousRelationship,
|
||||
requested: !previousRelationship.following,
|
||||
notifying: params?.notify ?? previousRelationship.notifying,
|
||||
showing_reblogs: params?.reblogs ?? previousRelationship.showing_reblogs,
|
||||
};
|
||||
|
||||
queryClient.setQueryData(['accountRelationships', accountId], newRelationship);
|
||||
|
||||
return { previousRelationship };
|
||||
},
|
||||
onError: (_err, _variables, context) => {
|
||||
if (context?.previousRelationship) {
|
||||
queryClient.setQueryData(['accountRelationships', accountId], context.previousRelationship);
|
||||
}
|
||||
return updateRelationship(accountId, (relationship) => ({
|
||||
...relationship,
|
||||
requested: !relationship.following,
|
||||
notifying: params?.notify ?? relationship.notifying,
|
||||
showing_reblogs: params?.reblogs ?? relationship.showing_reblogs,
|
||||
}), queryClient);
|
||||
},
|
||||
onError: (_err, _variables, context) => restorePreviousRelationship(accountId, context, queryClient),
|
||||
onSuccess: (data) => {
|
||||
queryClient.setQueryData(['accountRelationships', accountId], data);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const useUnfollowMutation = (accountId: string) => {
|
||||
const useUnfollowAccountMutation = (accountId: string) => {
|
||||
const client = useClient();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['accountRelationships', accountId],
|
||||
mutationFn: () => client.accounts.unfollowAccount(accountId),
|
||||
onMutate: () => {
|
||||
const previousRelationship = queryClient.getQueryData<Relationship>(['accountRelationships', accountId])!;
|
||||
|
||||
if (!previousRelationship) return;
|
||||
const newRelationship: Relationship = {
|
||||
...previousRelationship,
|
||||
following: false,
|
||||
requested: false,
|
||||
notifying: false,
|
||||
showing_reblogs: false,
|
||||
};
|
||||
|
||||
queryClient.setQueryData(['accountRelationships', accountId], newRelationship);
|
||||
|
||||
return { previousRelationship };
|
||||
},
|
||||
onError: (_err, _variables, context) => {
|
||||
if (context?.previousRelationship) {
|
||||
queryClient.setQueryData(['accountRelationships', accountId], context.previousRelationship);
|
||||
}
|
||||
},
|
||||
onMutate: () => updateRelationship(accountId, {
|
||||
following: false,
|
||||
requested: false,
|
||||
notifying: false,
|
||||
showing_reblogs: false,
|
||||
}, queryClient),
|
||||
onError: (_err, _variables, context) => restorePreviousRelationship(accountId, context, queryClient),
|
||||
onSuccess: (data) => {
|
||||
queryClient.setQueryData(['accountRelationships', accountId], data);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export { useRelationshipQuery, useFollowMutation, useUnfollowMutation };
|
||||
const useBlockAccountMutation = (accountId: string) => {
|
||||
const client = useClient();
|
||||
const queryClient = useQueryClient();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['accountRelationships', accountId],
|
||||
mutationFn: () => client.filtering.blockAccount(accountId),
|
||||
onMutate: () => updateRelationship(accountId, {
|
||||
blocking: true,
|
||||
followed_by: false,
|
||||
following: false,
|
||||
notifying: false,
|
||||
requested: false,
|
||||
}, queryClient),
|
||||
onError: (_err, _variables, context) => restorePreviousRelationship(accountId, context, queryClient),
|
||||
onSuccess: (data) => {
|
||||
queryClient.setQueryData(['accountRelationships', accountId], data);
|
||||
|
||||
queryClient.setQueryData<Array<MinifiedSuggestion>>(['suggestions'], suggestions => suggestions
|
||||
? suggestions.filter((suggestion) => suggestion.account_id !== accountId)
|
||||
: undefined);
|
||||
|
||||
// Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers
|
||||
return dispatch<AccountsAction>((dispatch, getState) => dispatch({
|
||||
type: ACCOUNT_BLOCK_SUCCESS,
|
||||
relationship: data,
|
||||
statuses: getState().statuses,
|
||||
}));
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const useUnblockAccountMutation = (accountId: string) => {
|
||||
const client = useClient();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['accountRelationships', accountId],
|
||||
mutationFn: () => client.filtering.unblockAccount(accountId),
|
||||
onMutate: () => updateRelationship(accountId, {
|
||||
blocking: true,
|
||||
}, queryClient),
|
||||
onError: (_err, _variables, context) => restorePreviousRelationship(accountId, context, queryClient),
|
||||
onSuccess: (data) => {
|
||||
queryClient.setQueryData(['accountRelationships', accountId], data);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const useMuteAccountMutation = (accountId: string) => {
|
||||
const client = useClient();
|
||||
const queryClient = useQueryClient();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['accountRelationships', accountId],
|
||||
mutationFn: (params?: MuteAccountParams) => client.filtering.muteAccount(accountId, params),
|
||||
onMutate: () => updateRelationship(accountId, {
|
||||
muting: true,
|
||||
}, queryClient),
|
||||
onError: (_err, _variables, context) => restorePreviousRelationship(accountId, context, queryClient),
|
||||
onSuccess: (data) => {
|
||||
queryClient.setQueryData(['accountRelationships', accountId], data);
|
||||
|
||||
queryClient.setQueryData<Array<MinifiedSuggestion>>(['suggestions'], suggestions => suggestions
|
||||
? suggestions.filter((suggestion) => suggestion.account_id !== accountId)
|
||||
: undefined);
|
||||
|
||||
// Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers
|
||||
return dispatch<AccountsAction>((dispatch, getState) => dispatch({
|
||||
type: ACCOUNT_MUTE_SUCCESS,
|
||||
relationship: data,
|
||||
statuses: getState().statuses,
|
||||
}));
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const useUnmuteAccountMutation = (accountId: string) => {
|
||||
const client = useClient();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['accountRelationships', accountId],
|
||||
mutationFn: () => client.filtering.unmuteAccount(accountId),
|
||||
onMutate: () => updateRelationship(accountId, {
|
||||
muting: false,
|
||||
}, queryClient),
|
||||
onError: (_err, _variables, context) => restorePreviousRelationship(accountId, context, queryClient),
|
||||
onSuccess: (data) => {
|
||||
queryClient.setQueryData(['accountRelationships', accountId], data);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const usePinAccountMutation = (accountId: string) => {
|
||||
const client = useClient();
|
||||
const queryClient = useQueryClient();
|
||||
const { me } = useLoggedIn();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['accountRelationships', accountId],
|
||||
mutationFn: () => client.accounts.pinAccount(accountId),
|
||||
onMutate: () => updateRelationship(accountId, {
|
||||
endorsed: true,
|
||||
}, queryClient),
|
||||
onError: (_err, _variables, context) => restorePreviousRelationship(accountId, context, queryClient),
|
||||
onSuccess: (data) => {
|
||||
queryClient.setQueryData(['accountRelationships', accountId], data);
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ['accountsLists', 'endorsedAccounts', me],
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const useUnpinAccountMutation = (accountId: string) => {
|
||||
const client = useClient();
|
||||
const queryClient = useQueryClient();
|
||||
const { me } = useLoggedIn();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['accountRelationships', accountId],
|
||||
mutationFn: () => client.accounts.unpinAccount(accountId),
|
||||
onMutate: () => updateRelationship(accountId, {
|
||||
endorsed: false,
|
||||
}, queryClient),
|
||||
onError: (_err, _variables, context) => restorePreviousRelationship(accountId, context, queryClient),
|
||||
onSuccess: (data) => {
|
||||
queryClient.setQueryData(['accountRelationships', accountId], data);
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ['accountsLists', 'endorsedAccounts', me],
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const useRemoveAccountFromFollowersMutation = (accountId: string) => {
|
||||
const client = useClient();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['accountRelationships', accountId],
|
||||
mutationFn: () => client.accounts.removeAccountFromFollowers(accountId),
|
||||
onMutate: () => updateRelationship(accountId, {
|
||||
followed_by: false,
|
||||
}, queryClient),
|
||||
onError: (_err, _variables, context) => restorePreviousRelationship(accountId, context, queryClient),
|
||||
onSuccess: (data) => {
|
||||
queryClient.setQueryData(['accountRelationships', accountId], data);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export {
|
||||
useRelationshipQuery,
|
||||
useFollowAccountMutation,
|
||||
useUnfollowAccountMutation,
|
||||
useBlockAccountMutation,
|
||||
useUnblockAccountMutation,
|
||||
useMuteAccountMutation,
|
||||
useUnmuteAccountMutation,
|
||||
usePinAccountMutation,
|
||||
useUnpinAccountMutation,
|
||||
useRemoveAccountFromFollowersMutation,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user