kopia lustrzana https://gitlab.com/soapbox-pub/soapbox
Remove account_counters reducer and legacy follow actions
rodzic
ad1718b5f9
commit
75dbeb65b6
|
@ -19,12 +19,10 @@ import {
|
|||
fetchFollowing,
|
||||
fetchFollowRequests,
|
||||
fetchRelationships,
|
||||
followAccount,
|
||||
muteAccount,
|
||||
removeFromFollowers,
|
||||
subscribeAccount,
|
||||
unblockAccount,
|
||||
unfollowAccount,
|
||||
unmuteAccount,
|
||||
unsubscribeAccount,
|
||||
} from '../accounts';
|
||||
|
@ -381,169 +379,6 @@ describe('fetchAccountByUsername()', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('followAccount()', () => {
|
||||
describe('when logged out', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', null);
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
it('should do nothing', async() => {
|
||||
await store.dispatch(followAccount('1'));
|
||||
const actions = store.getActions();
|
||||
|
||||
expect(actions).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when logged in', () => {
|
||||
const id = '1';
|
||||
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', '123');
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
describe('with a successful API request', () => {
|
||||
beforeEach(() => {
|
||||
__stub((mock) => {
|
||||
mock.onPost(`/api/v1/accounts/${id}/follow`).reply(200, { success: true });
|
||||
});
|
||||
});
|
||||
|
||||
it('should dispatch the correct actions', async() => {
|
||||
const expectedActions = [
|
||||
{
|
||||
type: 'ACCOUNT_FOLLOW_REQUEST',
|
||||
id,
|
||||
locked: false,
|
||||
skipLoading: true,
|
||||
},
|
||||
{
|
||||
type: 'ACCOUNT_FOLLOW_SUCCESS',
|
||||
relationship: { success: true },
|
||||
alreadyFollowing: undefined,
|
||||
skipLoading: true,
|
||||
},
|
||||
];
|
||||
await store.dispatch(followAccount(id));
|
||||
const actions = store.getActions();
|
||||
|
||||
expect(actions).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with an unsuccessful API request', () => {
|
||||
beforeEach(() => {
|
||||
__stub((mock) => {
|
||||
mock.onPost(`/api/v1/accounts/${id}/follow`).networkError();
|
||||
});
|
||||
});
|
||||
|
||||
it('should dispatch the correct actions', async() => {
|
||||
const expectedActions = [
|
||||
{
|
||||
type: 'ACCOUNT_FOLLOW_REQUEST',
|
||||
id,
|
||||
locked: false,
|
||||
skipLoading: true,
|
||||
},
|
||||
{
|
||||
type: 'ACCOUNT_FOLLOW_FAIL',
|
||||
error: new Error('Network Error'),
|
||||
locked: false,
|
||||
skipLoading: true,
|
||||
},
|
||||
];
|
||||
|
||||
try {
|
||||
await store.dispatch(followAccount(id));
|
||||
} catch (e) {
|
||||
const actions = store.getActions();
|
||||
expect(actions).toEqual(expectedActions);
|
||||
expect(e).toEqual(new Error('Network Error'));
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('unfollowAccount()', () => {
|
||||
describe('when logged out', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', null);
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
it('should do nothing', async() => {
|
||||
await store.dispatch(unfollowAccount('1'));
|
||||
const actions = store.getActions();
|
||||
|
||||
expect(actions).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when logged in', () => {
|
||||
const id = '1';
|
||||
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', '123');
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
describe('with a successful API request', () => {
|
||||
beforeEach(() => {
|
||||
__stub((mock) => {
|
||||
mock.onPost(`/api/v1/accounts/${id}/unfollow`).reply(200, { success: true });
|
||||
});
|
||||
});
|
||||
|
||||
it('should dispatch the correct actions', async() => {
|
||||
const expectedActions = [
|
||||
{ type: 'ACCOUNT_UNFOLLOW_REQUEST', id: '1', skipLoading: true },
|
||||
{
|
||||
type: 'ACCOUNT_UNFOLLOW_SUCCESS',
|
||||
relationship: { success: true },
|
||||
statuses: ImmutableMap({}),
|
||||
skipLoading: true,
|
||||
},
|
||||
];
|
||||
await store.dispatch(unfollowAccount(id));
|
||||
const actions = store.getActions();
|
||||
|
||||
expect(actions).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with an unsuccessful API request', () => {
|
||||
beforeEach(() => {
|
||||
__stub((mock) => {
|
||||
mock.onPost(`/api/v1/accounts/${id}/unfollow`).networkError();
|
||||
});
|
||||
});
|
||||
|
||||
it('should dispatch the correct actions', async() => {
|
||||
const expectedActions = [
|
||||
{
|
||||
type: 'ACCOUNT_UNFOLLOW_REQUEST',
|
||||
id,
|
||||
skipLoading: true,
|
||||
},
|
||||
{
|
||||
type: 'ACCOUNT_UNFOLLOW_FAIL',
|
||||
error: new Error('Network Error'),
|
||||
skipLoading: true,
|
||||
},
|
||||
];
|
||||
await store.dispatch(unfollowAccount(id));
|
||||
const actions = store.getActions();
|
||||
|
||||
expect(actions).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('blockAccount()', () => {
|
||||
const id = '1';
|
||||
|
||||
|
|
|
@ -23,14 +23,6 @@ const ACCOUNT_FETCH_REQUEST = 'ACCOUNT_FETCH_REQUEST';
|
|||
const ACCOUNT_FETCH_SUCCESS = 'ACCOUNT_FETCH_SUCCESS';
|
||||
const ACCOUNT_FETCH_FAIL = 'ACCOUNT_FETCH_FAIL';
|
||||
|
||||
const ACCOUNT_FOLLOW_REQUEST = 'ACCOUNT_FOLLOW_REQUEST';
|
||||
const ACCOUNT_FOLLOW_SUCCESS = 'ACCOUNT_FOLLOW_SUCCESS';
|
||||
const ACCOUNT_FOLLOW_FAIL = 'ACCOUNT_FOLLOW_FAIL';
|
||||
|
||||
const ACCOUNT_UNFOLLOW_REQUEST = 'ACCOUNT_UNFOLLOW_REQUEST';
|
||||
const ACCOUNT_UNFOLLOW_SUCCESS = 'ACCOUNT_UNFOLLOW_SUCCESS';
|
||||
const ACCOUNT_UNFOLLOW_FAIL = 'ACCOUNT_UNFOLLOW_FAIL';
|
||||
|
||||
const ACCOUNT_BLOCK_REQUEST = 'ACCOUNT_BLOCK_REQUEST';
|
||||
const ACCOUNT_BLOCK_SUCCESS = 'ACCOUNT_BLOCK_SUCCESS';
|
||||
const ACCOUNT_BLOCK_FAIL = 'ACCOUNT_BLOCK_FAIL';
|
||||
|
@ -227,81 +219,6 @@ const fetchAccountFail = (id: string | null, error: AxiosError) => ({
|
|||
skipAlert: true,
|
||||
});
|
||||
|
||||
type FollowAccountOpts = {
|
||||
reblogs?: boolean
|
||||
notify?: boolean
|
||||
};
|
||||
|
||||
const followAccount = (id: string, options?: FollowAccountOpts) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return null;
|
||||
|
||||
const alreadyFollowing = getState().relationships.get(id)?.following || undefined;
|
||||
const locked = getState().accounts.get(id)?.locked || false;
|
||||
|
||||
dispatch(followAccountRequest(id, locked));
|
||||
|
||||
return api(getState)
|
||||
.post(`/api/v1/accounts/${id}/follow`, options)
|
||||
.then(response => dispatch(followAccountSuccess(response.data, alreadyFollowing)))
|
||||
.catch(error => {
|
||||
dispatch(followAccountFail(error, locked));
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
|
||||
const unfollowAccount = (id: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return null;
|
||||
|
||||
dispatch(unfollowAccountRequest(id));
|
||||
|
||||
return api(getState)
|
||||
.post(`/api/v1/accounts/${id}/unfollow`)
|
||||
.then(response => dispatch(unfollowAccountSuccess(response.data, getState().statuses)))
|
||||
.catch(error => dispatch(unfollowAccountFail(error)));
|
||||
};
|
||||
|
||||
const followAccountRequest = (id: string, locked: boolean) => ({
|
||||
type: ACCOUNT_FOLLOW_REQUEST,
|
||||
id,
|
||||
locked,
|
||||
skipLoading: true,
|
||||
});
|
||||
|
||||
const followAccountSuccess = (relationship: APIEntity, alreadyFollowing?: boolean) => ({
|
||||
type: ACCOUNT_FOLLOW_SUCCESS,
|
||||
relationship,
|
||||
alreadyFollowing,
|
||||
skipLoading: true,
|
||||
});
|
||||
|
||||
const followAccountFail = (error: AxiosError, locked: boolean) => ({
|
||||
type: ACCOUNT_FOLLOW_FAIL,
|
||||
error,
|
||||
locked,
|
||||
skipLoading: true,
|
||||
});
|
||||
|
||||
const unfollowAccountRequest = (id: string) => ({
|
||||
type: ACCOUNT_UNFOLLOW_REQUEST,
|
||||
id,
|
||||
skipLoading: true,
|
||||
});
|
||||
|
||||
const unfollowAccountSuccess = (relationship: APIEntity, statuses: ImmutableMap<string, Status>) => ({
|
||||
type: ACCOUNT_UNFOLLOW_SUCCESS,
|
||||
relationship,
|
||||
statuses,
|
||||
skipLoading: true,
|
||||
});
|
||||
|
||||
const unfollowAccountFail = (error: AxiosError) => ({
|
||||
type: ACCOUNT_UNFOLLOW_FAIL,
|
||||
error,
|
||||
skipLoading: true,
|
||||
});
|
||||
|
||||
const blockAccount = (id: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return null;
|
||||
|
@ -988,12 +905,6 @@ export {
|
|||
ACCOUNT_FETCH_REQUEST,
|
||||
ACCOUNT_FETCH_SUCCESS,
|
||||
ACCOUNT_FETCH_FAIL,
|
||||
ACCOUNT_FOLLOW_REQUEST,
|
||||
ACCOUNT_FOLLOW_SUCCESS,
|
||||
ACCOUNT_FOLLOW_FAIL,
|
||||
ACCOUNT_UNFOLLOW_REQUEST,
|
||||
ACCOUNT_UNFOLLOW_SUCCESS,
|
||||
ACCOUNT_UNFOLLOW_FAIL,
|
||||
ACCOUNT_BLOCK_REQUEST,
|
||||
ACCOUNT_BLOCK_SUCCESS,
|
||||
ACCOUNT_BLOCK_FAIL,
|
||||
|
@ -1069,14 +980,6 @@ export {
|
|||
fetchAccountRequest,
|
||||
fetchAccountSuccess,
|
||||
fetchAccountFail,
|
||||
followAccount,
|
||||
unfollowAccount,
|
||||
followAccountRequest,
|
||||
followAccountSuccess,
|
||||
followAccountFail,
|
||||
unfollowAccountRequest,
|
||||
unfollowAccountSuccess,
|
||||
unfollowAccountFail,
|
||||
blockAccount,
|
||||
unblockAccount,
|
||||
blockAccountRequest,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Entities } from 'soapbox/entity-store/entities';
|
||||
import { useChangeEntity } from 'soapbox/entity-store/hooks';
|
||||
import { useLoggedIn } from 'soapbox/hooks';
|
||||
import { useApi } from 'soapbox/hooks/useApi';
|
||||
import { type Account } from 'soapbox/schemas';
|
||||
|
||||
|
@ -8,8 +9,15 @@ function useChangeAccount() {
|
|||
return { changeAccount };
|
||||
}
|
||||
|
||||
interface FollowOpts {
|
||||
reblogs?: boolean
|
||||
notify?: boolean
|
||||
languages?: string[]
|
||||
}
|
||||
|
||||
function useFollow() {
|
||||
const api = useApi();
|
||||
const { isLoggedIn } = useLoggedIn();
|
||||
const { changeAccount } = useChangeAccount();
|
||||
|
||||
function incrementFollowers(accountId: string) {
|
||||
|
@ -26,7 +34,8 @@ function useFollow() {
|
|||
}));
|
||||
}
|
||||
|
||||
async function follow(accountId: string, options = {}) {
|
||||
async function follow(accountId: string, options: FollowOpts = {}) {
|
||||
if (!isLoggedIn) return;
|
||||
incrementFollowers(accountId);
|
||||
|
||||
try {
|
||||
|
@ -36,11 +45,12 @@ function useFollow() {
|
|||
}
|
||||
}
|
||||
|
||||
async function unfollow(accountId: string, options = {}) {
|
||||
async function unfollow(accountId: string) {
|
||||
if (!isLoggedIn) return;
|
||||
decrementFollowers(accountId);
|
||||
|
||||
try {
|
||||
await api.post(`/api/v1/accounts/${accountId}/unfollow`, options);
|
||||
await api.post(`/api/v1/accounts/${accountId}/unfollow`);
|
||||
} catch (e) {
|
||||
incrementFollowers(accountId);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import React from 'react';
|
|||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import { blockAccount, followAccount, pinAccount, removeFromFollowers, unblockAccount, unmuteAccount, unpinAccount } from 'soapbox/actions/accounts';
|
||||
import { blockAccount, pinAccount, removeFromFollowers, unblockAccount, unmuteAccount, unpinAccount } from 'soapbox/actions/accounts';
|
||||
import { mentionCompose, directCompose } from 'soapbox/actions/compose';
|
||||
import { blockDomain, unblockDomain } from 'soapbox/actions/domain-blocks';
|
||||
import { openModal } from 'soapbox/actions/modals';
|
||||
|
@ -15,6 +15,7 @@ import { initMuteModal } from 'soapbox/actions/mutes';
|
|||
import { initReport, ReportableEntities } from 'soapbox/actions/reports';
|
||||
import { setSearchAccount } from 'soapbox/actions/search';
|
||||
import { getSettings } from 'soapbox/actions/settings';
|
||||
import { useFollow } from 'soapbox/api/hooks';
|
||||
import Badge from 'soapbox/components/badge';
|
||||
import DropdownMenu, { Menu } from 'soapbox/components/dropdown-menu';
|
||||
import StillImage from 'soapbox/components/still-image';
|
||||
|
@ -87,6 +88,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
|||
|
||||
const features = useFeatures();
|
||||
const ownAccount = useOwnAccount();
|
||||
const { follow } = useFollow();
|
||||
|
||||
const { software } = useAppSelector((state) => parseVersion(state.instance.version));
|
||||
|
||||
|
@ -154,9 +156,9 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
|||
|
||||
const onReblogToggle = () => {
|
||||
if (account.relationship?.showing_reblogs) {
|
||||
dispatch(followAccount(account.id, { reblogs: false }));
|
||||
follow(account.id, { reblogs: false });
|
||||
} else {
|
||||
dispatch(followAccount(account.id, { reblogs: true }));
|
||||
follow(account.id, { reblogs: true });
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@ import React from 'react';
|
|||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import {
|
||||
followAccount,
|
||||
unfollowAccount,
|
||||
blockAccount,
|
||||
unblockAccount,
|
||||
muteAccount,
|
||||
|
@ -12,8 +10,9 @@ import {
|
|||
rejectFollowRequest,
|
||||
} from 'soapbox/actions/accounts';
|
||||
import { openModal } from 'soapbox/actions/modals';
|
||||
import { useFollow } from 'soapbox/api/hooks';
|
||||
import { Button, HStack } from 'soapbox/components/ui';
|
||||
import { useAppDispatch, useAppSelector, useFeatures } from 'soapbox/hooks';
|
||||
import { useAppDispatch, useFeatures, useLoggedIn } from 'soapbox/hooks';
|
||||
|
||||
import type { Account } from 'soapbox/schemas';
|
||||
import type { Account as AccountEntity } from 'soapbox/types/entities';
|
||||
|
@ -53,13 +52,14 @@ const ActionButton: React.FC<IActionButton> = ({ account, actionType, small }) =
|
|||
const features = useFeatures();
|
||||
const intl = useIntl();
|
||||
|
||||
const me = useAppSelector((state) => state.me);
|
||||
const { isLoggedIn, me } = useLoggedIn();
|
||||
const { follow, unfollow } = useFollow();
|
||||
|
||||
const handleFollow = () => {
|
||||
if (account.relationship?.following || account.relationship?.requested) {
|
||||
dispatch(unfollowAccount(account.id));
|
||||
unfollow(account.id);
|
||||
} else {
|
||||
dispatch(followAccount(account.id));
|
||||
follow(account.id);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -187,7 +187,7 @@ const ActionButton: React.FC<IActionButton> = ({ account, actionType, small }) =
|
|||
return null;
|
||||
};
|
||||
|
||||
if (!me) {
|
||||
if (!isLoggedIn) {
|
||||
return renderLoggedOut();
|
||||
}
|
||||
|
||||
|
|
|
@ -2,10 +2,10 @@ import React from 'react';
|
|||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import {
|
||||
followAccount,
|
||||
subscribeAccount,
|
||||
unsubscribeAccount,
|
||||
} from 'soapbox/actions/accounts';
|
||||
import { useFollow } from 'soapbox/api/hooks';
|
||||
import { IconButton } from 'soapbox/components/ui';
|
||||
import { useAppDispatch, useFeatures } from 'soapbox/hooks';
|
||||
import toast from 'soapbox/toast';
|
||||
|
@ -29,6 +29,7 @@ const SubscriptionButton = ({ account }: ISubscriptionButton) => {
|
|||
const dispatch = useAppDispatch();
|
||||
const features = useFeatures();
|
||||
const intl = useIntl();
|
||||
const { follow } = useFollow();
|
||||
|
||||
const isFollowing = account.relationship?.following;
|
||||
const isRequested = account.relationship?.requested;
|
||||
|
@ -53,11 +54,11 @@ const SubscriptionButton = ({ account }: ISubscriptionButton) => {
|
|||
|
||||
const onNotifyToggle = () => {
|
||||
if (account.relationship?.notifying) {
|
||||
dispatch(followAccount(account.id, { notify: false } as any))
|
||||
follow(account.id, { notify: false })
|
||||
?.then(() => onUnsubscribeSuccess())
|
||||
.catch(() => onUnsubscribeFailure());
|
||||
} else {
|
||||
dispatch(followAccount(account.id, { notify: true } as any))
|
||||
follow(account.id, { notify: true })
|
||||
?.then(() => onSubscribeSuccess())
|
||||
.catch(() => onSubscribeFailure());
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ export { useFeatures } from './useFeatures';
|
|||
export { useInstance } from './useInstance';
|
||||
export { useLoading } from './useLoading';
|
||||
export { useLocale } from './useLocale';
|
||||
export { useLoggedIn } from './useLoggedIn';
|
||||
export { useOnScreen } from './useOnScreen';
|
||||
export { useOwnAccount } from './useOwnAccount';
|
||||
export { usePrevious } from './usePrevious';
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
import { useAppSelector } from './useAppSelector';
|
||||
|
||||
function useLoggedIn() {
|
||||
const me = useAppSelector(state => state.me);
|
||||
return {
|
||||
isLoggedIn: typeof me === 'string',
|
||||
isLoginLoading: me === null,
|
||||
isLoginFailed: me === false,
|
||||
me,
|
||||
};
|
||||
}
|
||||
|
||||
export { useLoggedIn };
|
|
@ -1,37 +0,0 @@
|
|||
import { Map as ImmutableMap } from 'immutable';
|
||||
|
||||
import reducer from '../accounts-counters';
|
||||
// import { ACCOUNT_FOLLOW_SUCCESS, ACCOUNT_UNFOLLOW_SUCCESS } from 'soapbox/actions/accounts';
|
||||
// import relationship from 'soapbox/__fixtures__/relationship.json';
|
||||
// import accounts_counter_initial from 'soapbox/__fixtures__/accounts_counter_initial.json';
|
||||
// import accounts_counter_unfollow from 'soapbox/__fixtures__/accounts_counter_unfollow.json';
|
||||
// import accounts_counter_follow from 'soapbox/__fixtures__/accounts_counter_follow.json';
|
||||
|
||||
describe('accounts_counters reducer', () => {
|
||||
it('should return the initial state', () => {
|
||||
expect(reducer(undefined, {} as any)).toEqual(ImmutableMap());
|
||||
});
|
||||
|
||||
// it('should handle ACCOUNT_FOLLOW_SUCCESS', () => {
|
||||
// const state = ImmutableList([accounts_counter_initial]);
|
||||
// const action = {
|
||||
// type: ACCOUNT_FOLLOW_SUCCESS,
|
||||
// relationship: relationship,
|
||||
// alreadyFollowing: false,
|
||||
// };
|
||||
// expect(reducer(state, action)).toEqual(
|
||||
// ImmutableList([ accounts_counter_follow ]));
|
||||
// });
|
||||
//
|
||||
// it('should handle ACCOUNT_UNFOLLOW_SUCCESS', () => {
|
||||
// const state = ImmutableList([accounts_counter_initial]);
|
||||
// const action = {
|
||||
// type: ACCOUNT_UNFOLLOW_SUCCESS,
|
||||
// relationship: relationship,
|
||||
// alreadyFollowing: true,
|
||||
// };
|
||||
// expect(reducer(state, action)).toEqual(
|
||||
// ImmutableList([accounts_counter_unfollow]));
|
||||
// });
|
||||
|
||||
});
|
|
@ -1,64 +0,0 @@
|
|||
import { List as ImmutableList, Map as ImmutableMap, Record as ImmutableRecord } from 'immutable';
|
||||
|
||||
import {
|
||||
ACCOUNT_FOLLOW_SUCCESS,
|
||||
ACCOUNT_UNFOLLOW_SUCCESS,
|
||||
} from 'soapbox/actions/accounts';
|
||||
import { ACCOUNT_IMPORT, ACCOUNTS_IMPORT } from 'soapbox/actions/importer';
|
||||
import { STREAMING_FOLLOW_RELATIONSHIPS_UPDATE } from 'soapbox/actions/streaming';
|
||||
|
||||
import type { AnyAction } from 'redux';
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
||||
const CounterRecord = ImmutableRecord({
|
||||
followers_count: 0,
|
||||
following_count: 0,
|
||||
statuses_count: 0,
|
||||
});
|
||||
|
||||
type Counter = ReturnType<typeof CounterRecord>;
|
||||
type State = ImmutableMap<string, Counter>;
|
||||
type APIEntities = Array<APIEntity>;
|
||||
|
||||
const normalizeAccount = (state: State, account: APIEntity) => state.set(account.id, CounterRecord({
|
||||
followers_count: account.followers_count,
|
||||
following_count: account.following_count,
|
||||
statuses_count: account.statuses_count,
|
||||
}));
|
||||
|
||||
const normalizeAccounts = (state: State, accounts: ImmutableList<APIEntities>) => {
|
||||
accounts.forEach(account => {
|
||||
state = normalizeAccount(state, account);
|
||||
});
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
const updateFollowCounters = (state: State, counterUpdates: APIEntities) => {
|
||||
return state.withMutations(state => {
|
||||
counterUpdates.forEach((counterUpdate) => {
|
||||
state.update(counterUpdate.id, CounterRecord(), counters => counters.merge({
|
||||
followers_count: counterUpdate.follower_count,
|
||||
following_count: counterUpdate.following_count,
|
||||
}));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export default function accountsCounters(state: State = ImmutableMap<string, Counter>(), action: AnyAction) {
|
||||
switch (action.type) {
|
||||
case ACCOUNT_IMPORT:
|
||||
return normalizeAccount(state, action.account);
|
||||
case ACCOUNTS_IMPORT:
|
||||
return normalizeAccounts(state, action.accounts);
|
||||
case ACCOUNT_FOLLOW_SUCCESS:
|
||||
return action.alreadyFollowing ? state :
|
||||
state.updateIn([action.relationship.id, 'followers_count'], 0, (count) => typeof count === 'number' ? count + 1 : 0);
|
||||
case ACCOUNT_UNFOLLOW_SUCCESS:
|
||||
return state.updateIn([action.relationship.id, 'followers_count'], 0, (count) => typeof count === 'number' ? Math.max(0, count - 1) : 0);
|
||||
case STREAMING_FOLLOW_RELATIONSHIPS_UPDATE:
|
||||
return updateFollowCounters(state, [action.follower, action.following]);
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
|
@ -9,7 +9,6 @@ import entities from 'soapbox/entity-store/reducer';
|
|||
import { immutableizeStore, type LegacyStore } from 'soapbox/utils/legacy';
|
||||
|
||||
import account_notes from './account-notes';
|
||||
import accounts_counters from './accounts-counters';
|
||||
import accounts_meta from './accounts-meta';
|
||||
import admin from './admin';
|
||||
import admin_announcements from './admin-announcements';
|
||||
|
@ -78,7 +77,6 @@ import type { Account } from 'soapbox/schemas';
|
|||
const reducers = {
|
||||
accounts: ((state: any = {}) => state) as (state: any) => EntityStore<Account> & LegacyStore<Account>,
|
||||
account_notes,
|
||||
accounts_counters,
|
||||
accounts_meta,
|
||||
admin,
|
||||
admin_announcements,
|
||||
|
|
|
@ -6,12 +6,6 @@ import { type Relationship, relationshipSchema } from 'soapbox/schemas';
|
|||
|
||||
import { ACCOUNT_NOTE_SUBMIT_SUCCESS } from '../actions/account-notes';
|
||||
import {
|
||||
ACCOUNT_FOLLOW_SUCCESS,
|
||||
ACCOUNT_FOLLOW_REQUEST,
|
||||
ACCOUNT_FOLLOW_FAIL,
|
||||
ACCOUNT_UNFOLLOW_SUCCESS,
|
||||
ACCOUNT_UNFOLLOW_REQUEST,
|
||||
ACCOUNT_UNFOLLOW_FAIL,
|
||||
ACCOUNT_BLOCK_SUCCESS,
|
||||
ACCOUNT_UNBLOCK_SUCCESS,
|
||||
ACCOUNT_MUTE_SUCCESS,
|
||||
|
@ -101,16 +95,16 @@ export default function relationships(state: State = ImmutableMap<string, Relati
|
|||
return importPleromaAccount(state, action.account);
|
||||
case ACCOUNTS_IMPORT:
|
||||
return importPleromaAccounts(state, action.accounts);
|
||||
case ACCOUNT_FOLLOW_REQUEST:
|
||||
return state.setIn([action.id, 'following'], true);
|
||||
case ACCOUNT_FOLLOW_FAIL:
|
||||
return state.setIn([action.id, 'following'], false);
|
||||
case ACCOUNT_UNFOLLOW_REQUEST:
|
||||
return state.setIn([action.id, 'following'], false);
|
||||
case ACCOUNT_UNFOLLOW_FAIL:
|
||||
return state.setIn([action.id, 'following'], true);
|
||||
case ACCOUNT_FOLLOW_SUCCESS:
|
||||
case ACCOUNT_UNFOLLOW_SUCCESS:
|
||||
// case ACCOUNT_FOLLOW_REQUEST:
|
||||
// return state.setIn([action.id, 'following'], true);
|
||||
// case ACCOUNT_FOLLOW_FAIL:
|
||||
// return state.setIn([action.id, 'following'], false);
|
||||
// case ACCOUNT_UNFOLLOW_REQUEST:
|
||||
// return state.setIn([action.id, 'following'], false);
|
||||
// case ACCOUNT_UNFOLLOW_FAIL:
|
||||
// return state.setIn([action.id, 'following'], true);
|
||||
// case ACCOUNT_FOLLOW_SUCCESS:
|
||||
// case ACCOUNT_UNFOLLOW_SUCCESS:
|
||||
case ACCOUNT_BLOCK_SUCCESS:
|
||||
case ACCOUNT_UNBLOCK_SUCCESS:
|
||||
case ACCOUNT_MUTE_SUCCESS:
|
||||
|
|
|
@ -10,7 +10,6 @@ import sample from 'lodash/sample';
|
|||
import {
|
||||
ACCOUNT_BLOCK_SUCCESS,
|
||||
ACCOUNT_MUTE_SUCCESS,
|
||||
ACCOUNT_UNFOLLOW_SUCCESS,
|
||||
} from '../actions/accounts';
|
||||
import {
|
||||
STATUS_CREATE_REQUEST,
|
||||
|
@ -204,11 +203,11 @@ const buildReferencesTo = (statuses: ImmutableMap<string, Status>, status: Statu
|
|||
.map(statusToReference) as ImmutableMap<string, [string, string]>
|
||||
);
|
||||
|
||||
const filterTimeline = (state: State, timelineId: string, relationship: APIEntity, statuses: ImmutableList<ImmutableMap<string, any>>) =>
|
||||
state.updateIn([timelineId, 'items'], ImmutableOrderedSet(), (ids) =>
|
||||
(ids as ImmutableOrderedSet<string>).filterNot(statusId =>
|
||||
statuses.getIn([statusId, 'account']) === relationship.id,
|
||||
));
|
||||
// const filterTimeline = (state: State, timelineId: string, relationship: APIEntity, statuses: ImmutableList<ImmutableMap<string, any>>) =>
|
||||
// state.updateIn([timelineId, 'items'], ImmutableOrderedSet(), (ids) =>
|
||||
// (ids as ImmutableOrderedSet<string>).filterNot(statusId =>
|
||||
// statuses.getIn([statusId, 'account']) === relationship.id,
|
||||
// ));
|
||||
|
||||
const filterTimelines = (state: State, relationship: APIEntity, statuses: ImmutableMap<string, Status>) => {
|
||||
return state.withMutations(state => {
|
||||
|
@ -356,8 +355,8 @@ export default function timelines(state: State = initialState, action: AnyAction
|
|||
case ACCOUNT_BLOCK_SUCCESS:
|
||||
case ACCOUNT_MUTE_SUCCESS:
|
||||
return filterTimelines(state, action.relationship, action.statuses);
|
||||
case ACCOUNT_UNFOLLOW_SUCCESS:
|
||||
return filterTimeline(state, 'home', action.relationship, action.statuses);
|
||||
// case ACCOUNT_UNFOLLOW_SUCCESS:
|
||||
// return filterTimeline(state, 'home', action.relationship, action.statuses);
|
||||
case TIMELINE_SCROLL_TOP:
|
||||
return updateTop(state, action.timeline, action.top);
|
||||
case TIMELINE_CONNECT:
|
||||
|
|
|
@ -22,7 +22,6 @@ import type { Filter as FilterEntity, Notification, Status, Group } from 'soapbo
|
|||
const normalizeId = (id: any): string => typeof id === 'string' ? id : '';
|
||||
|
||||
const getAccountBase = (state: RootState, id: string) => state.accounts.get(id);
|
||||
const getAccountCounters = (state: RootState, id: string) => state.accounts_counters.get(id);
|
||||
const getAccountRelationship = (state: RootState, id: string) => state.relationships.get(id);
|
||||
const getAccountMoved = (state: RootState, id: string) => state.accounts.get(state.accounts.get(id)?.moved || '');
|
||||
const getAccountMeta = (state: RootState, id: string) => state.accounts_meta.get(id);
|
||||
|
@ -35,13 +34,12 @@ const getAccountPatron = (state: RootState, id: string) => {
|
|||
export const makeGetAccount = () => {
|
||||
return createSelector([
|
||||
getAccountBase,
|
||||
getAccountCounters,
|
||||
getAccountRelationship,
|
||||
getAccountMoved,
|
||||
getAccountMeta,
|
||||
getAccountAdminData,
|
||||
getAccountPatron,
|
||||
], (base, counters, relationship, moved, meta, admin, patron) => {
|
||||
], (base, relationship, moved, meta, admin, patron) => {
|
||||
if (!base) return null;
|
||||
base.relationship = base.relationship ?? relationship;
|
||||
return base;
|
||||
|
|
Ładowanie…
Reference in New Issue