pl-fe: migrate more to tanstack query

Signed-off-by: mkljczk <git@mkljczk.pl>
This commit is contained in:
mkljczk 2024-12-05 01:24:12 +01:00
parent 86e38c391c
commit d286c34ae0
9 changed files with 59 additions and 151 deletions

View file

@ -38,10 +38,6 @@ const ACCOUNT_MUTE_REQUEST = 'ACCOUNT_MUTE_REQUEST' as const;
const ACCOUNT_MUTE_SUCCESS = 'ACCOUNT_MUTE_SUCCESS' as const;
const ACCOUNT_MUTE_FAIL = 'ACCOUNT_MUTE_FAIL' as const;
const PINNED_ACCOUNTS_FETCH_REQUEST = 'PINNED_ACCOUNTS_FETCH_REQUEST' as const;
const PINNED_ACCOUNTS_FETCH_SUCCESS = 'PINNED_ACCOUNTS_FETCH_SUCCESS' as const;
const PINNED_ACCOUNTS_FETCH_FAIL = 'PINNED_ACCOUNTS_FETCH_FAIL' as const;
const ACCOUNT_SEARCH_REQUEST = 'ACCOUNT_SEARCH_REQUEST' as const;
const ACCOUNT_SEARCH_SUCCESS = 'ACCOUNT_SEARCH_SUCCESS' as const;
const ACCOUNT_SEARCH_FAIL = 'ACCOUNT_SEARCH_FAIL' as const;
@ -342,36 +338,6 @@ const updateNotificationSettings = (params: UpdateNotificationSettingsParams) =>
});
};
const fetchPinnedAccounts = (accountId: string) =>
(dispatch: AppDispatch, getState: () => RootState) => {
dispatch(fetchPinnedAccountsRequest(accountId));
return getClient(getState).accounts.getAccountEndorsements(accountId).then(response => {
dispatch(importEntities({ accounts: response }));
dispatch(fetchPinnedAccountsSuccess(accountId, response, null));
}).catch(error => {
dispatch(fetchPinnedAccountsFail(accountId, error));
});
};
const fetchPinnedAccountsRequest = (accountId: string) => ({
type: PINNED_ACCOUNTS_FETCH_REQUEST,
accountId,
});
const fetchPinnedAccountsSuccess = (accountId: string, accounts: Array<Account>, next: null) => ({
type: PINNED_ACCOUNTS_FETCH_SUCCESS,
accountId,
accounts,
next,
});
const fetchPinnedAccountsFail = (accountId: string, error: unknown) => ({
type: PINNED_ACCOUNTS_FETCH_FAIL,
accountId,
error,
});
interface AccountSearchRequestAction {
type: typeof ACCOUNT_SEARCH_REQUEST;
params: {
@ -452,9 +418,6 @@ type AccountsAction =
| NotificationSettingsRequestAction
| NotificationSettingsSuccessAction
| NotificationSettingsFailAction
| ReturnType<typeof fetchPinnedAccountsRequest>
| ReturnType<typeof fetchPinnedAccountsSuccess>
| ReturnType<typeof fetchPinnedAccountsFail>
| AccountSearchRequestAction
| AccountSearchSuccessAction
| AccountSearchFailAction
@ -475,9 +438,6 @@ export {
ACCOUNT_MUTE_REQUEST,
ACCOUNT_MUTE_SUCCESS,
ACCOUNT_MUTE_FAIL,
PINNED_ACCOUNTS_FETCH_REQUEST,
PINNED_ACCOUNTS_FETCH_SUCCESS,
PINNED_ACCOUNTS_FETCH_FAIL,
ACCOUNT_SEARCH_REQUEST,
ACCOUNT_SEARCH_SUCCESS,
ACCOUNT_SEARCH_FAIL,
@ -499,7 +459,6 @@ export {
pinAccount,
unpinAccount,
updateNotificationSettings,
fetchPinnedAccounts,
accountSearch,
accountLookup,
biteAccount,

View file

@ -1,63 +0,0 @@
import { AppDispatch, RootState } from 'pl-fe/store';
import { getClient } from '../api';
import { fetchRelationships } from './accounts';
import { importEntities } from './importer';
import type { Account } from 'pl-api';
const FAMILIAR_FOLLOWERS_FETCH_REQUEST = 'FAMILIAR_FOLLOWERS_FETCH_REQUEST' as const;
const FAMILIAR_FOLLOWERS_FETCH_SUCCESS = 'FAMILIAR_FOLLOWERS_FETCH_SUCCESS' as const;
const FAMILIAR_FOLLOWERS_FETCH_FAIL = 'FAMILIAR_FOLLOWERS_FETCH_FAIL' as const;
const fetchAccountFamiliarFollowers = (accountId: string) => (dispatch: AppDispatch, getState: () => RootState) => {
dispatch<FamiliarFollowersAction>({
type: FAMILIAR_FOLLOWERS_FETCH_REQUEST,
accountId,
});
getClient(getState()).accounts.getFamiliarFollowers([accountId])
.then((data) => {
const accounts = data.find(({ id }: { id: string }) => id === accountId)!.accounts;
dispatch(importEntities({ accounts }));
dispatch(fetchRelationships(accounts.map((item) => item.id)));
dispatch<FamiliarFollowersAction>({
type: FAMILIAR_FOLLOWERS_FETCH_SUCCESS,
accountId,
accounts,
});
})
.catch(error => dispatch<FamiliarFollowersAction>({
type: FAMILIAR_FOLLOWERS_FETCH_FAIL,
accountId,
error,
skipAlert: true,
}));
};
type FamiliarFollowersAction =
| {
type: typeof FAMILIAR_FOLLOWERS_FETCH_REQUEST;
accountId: string;
}
| {
type: typeof FAMILIAR_FOLLOWERS_FETCH_SUCCESS;
accountId: string;
accounts: Array<Account>;
}
| {
type: typeof FAMILIAR_FOLLOWERS_FETCH_FAIL;
accountId: string;
error: unknown;
skipAlert: true;
}
export {
FAMILIAR_FOLLOWERS_FETCH_REQUEST,
FAMILIAR_FOLLOWERS_FETCH_SUCCESS,
FAMILIAR_FOLLOWERS_FETCH_FAIL,
fetchAccountFamiliarFollowers,
type FamiliarFollowersAction,
};

View file

@ -0,0 +1,20 @@
import { useQuery } from '@tanstack/react-query';
import { importEntities } from 'pl-fe/actions/importer';
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
import { useClient } from 'pl-fe/hooks/use-client';
const useEndorsedAccounts = (accountId: string) => {
const client = useClient();
const dispatch = useAppDispatch();
return useQuery({
queryKey: ['accountsLists', 'endorsedAccounts', accountId],
queryFn: () => client.accounts.getAccountEndorsements(accountId).then((accounts) => {
dispatch(importEntities({ accounts }));
return accounts.map(({ id }) => id);
}),
});
};
export { useEndorsedAccounts };

View file

@ -0,0 +1,28 @@
import { useQuery } from '@tanstack/react-query';
import { importEntities } from 'pl-fe/actions/importer';
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';
const useFamiliarFollowers = (accountId: string) => {
const client = useClient();
const dispatch = useAppDispatch();
const features = useFeatures();
const { isLoggedIn } = useLoggedIn();
return useQuery({
queryKey: ['accountsLists', 'endorsedAccounts', accountId],
queryFn: () => client.accounts.getFamiliarFollowers([accountId]).then((response) => {
const result = response.find(({ id }) => id === accountId);
if (!result) return [];
dispatch(importEntities({ accounts: result.accounts }));
return result.accounts.map(({ id }) => id);
}),
enabled: isLoggedIn && features.familiarFollowers,
});
};
export { useFamiliarFollowers };

View file

@ -1,6 +1,7 @@
import React, { useRef } from 'react';
import { FormattedMessage } from 'react-intl';
import { useFamiliarFollowers } from 'pl-fe/api/hooks/account-lists/use-familiar-followers';
import ScrollableList from 'pl-fe/components/scrollable-list';
import Modal from 'pl-fe/components/ui/modal';
import Spinner from 'pl-fe/components/ui/spinner';
@ -20,7 +21,7 @@ interface FamiliarFollowersModalProps {
const FamiliarFollowersModal: React.FC<BaseModalProps & FamiliarFollowersModalProps> = ({ accountId, onClose }) => {
const modalRef = useRef<HTMLDivElement>(null);
const account = useAppSelector(state => getAccount(state, accountId));
const familiarFollowerIds = useAppSelector(state => state.user_lists.familiar_followers[accountId]?.items || []);
const { data: familiarFollowerIds } = useFamiliarFollowers(accountId);
const onClickClose = () => {
onClose('FAMILIAR_FOLLOWERS');

View file

@ -1,13 +1,11 @@
import React, { useEffect } from 'react';
import React from 'react';
import { FormattedMessage } from 'react-intl';
import { fetchPinnedAccounts } from 'pl-fe/actions/accounts';
import { useEndorsedAccounts } from 'pl-fe/api/hooks/account-lists/use-endorsed-accounts';
import Widget from 'pl-fe/components/ui/widget';
import AccountContainer from 'pl-fe/containers/account-container';
import Emojify from 'pl-fe/features/emoji/emojify';
import { WhoToFollowPanel } from 'pl-fe/features/ui/util/async-components';
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
import type { Account } from 'pl-fe/normalizers/account';
@ -17,12 +15,7 @@ interface IPinnedAccountsPanel {
}
const PinnedAccountsPanel: React.FC<IPinnedAccountsPanel> = ({ account, limit }) => {
const dispatch = useAppDispatch();
const pinned = useAppSelector((state) => state.user_lists.pinned[account.id]?.items || []).slice(0, limit);
useEffect(() => {
dispatch(fetchPinnedAccounts(account.id));
}, []);
const { data: pinned = [] } = useEndorsedAccounts(accountId);
if (!pinned.length) {
return (

View file

@ -1,17 +1,15 @@
import React, { useEffect } from 'react';
import React from 'react';
import { FormattedList, FormattedMessage } from 'react-intl';
import { Link } from 'react-router-dom';
import { fetchAccountFamiliarFollowers } from 'pl-fe/actions/familiar-followers';
import { useFamiliarFollowers } from 'pl-fe/api/hooks/account-lists/use-familiar-followers';
import AvatarStack from 'pl-fe/components/avatar-stack';
import HoverAccountWrapper from 'pl-fe/components/hover-account-wrapper';
import HStack from 'pl-fe/components/ui/hstack';
import Text from 'pl-fe/components/ui/text';
import VerificationBadge from 'pl-fe/components/verification-badge';
import Emojify from 'pl-fe/features/emoji/emojify';
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
import { useFeatures } from 'pl-fe/hooks/use-features';
import { makeGetAccount } from 'pl-fe/selectors';
import { useModalsStore } from 'pl-fe/stores/modals';
@ -25,18 +23,9 @@ interface IProfileFamiliarFollowers {
const ProfileFamiliarFollowers: React.FC<IProfileFamiliarFollowers> = ({ account }) => {
const { openModal } = useModalsStore();
const dispatch = useAppDispatch();
const me = useAppSelector((state) => state.me);
const features = useFeatures();
const familiarFollowerIds = useAppSelector(state => state.user_lists.familiar_followers[account.id]?.items || []);
const { data: familiarFollowerIds = [] } = useFamiliarFollowers(account.id);
const familiarFollowers = useAppSelector(state => familiarFollowerIds.slice(0, 2).map(accountId => getAccount(state, accountId)));
useEffect(() => {
if (me && features.familiarFollowers) {
dispatch(fetchAccountFamiliarFollowers(account.id));
}
}, [account.id]);
const openFamiliarFollowersModal = () => {
openModal('FAMILIAR_FOLLOWERS', {
accountId: account.id,

View file

@ -1,20 +1,9 @@
import { OrderedSet as ImmutableOrderedSet } from 'immutable';
import reducer from './user-lists';
describe('user_lists reducer', () => {
it('should return the initial state', () => {
expect(reducer(undefined, {} as any)).toMatchObject({
followers: {},
following: {},
reblogged_by: {},
favourited_by: {},
reactions: {},
follow_requests: { next: null, items: ImmutableOrderedSet(), isLoading: false },
blocks: { next: null, items: ImmutableOrderedSet(), isLoading: false },
mutes: { next: null, items: ImmutableOrderedSet(), isLoading: false },
pinned: {},
familiar_followers: {},
group_blocks: {},
});
});
});

View file

@ -1,7 +1,5 @@
import { create } from 'mutative';
import { PINNED_ACCOUNTS_FETCH_SUCCESS, type AccountsAction } from 'pl-fe/actions/accounts';
import { FAMILIAR_FOLLOWERS_FETCH_SUCCESS, type FamiliarFollowersAction } from 'pl-fe/actions/familiar-followers';
import {
GROUP_BLOCKS_FETCH_REQUEST,
GROUP_BLOCKS_FETCH_SUCCESS,
@ -18,13 +16,11 @@ interface List {
isLoading: boolean;
}
type NestedListKey = 'pinned' | 'familiar_followers' | 'group_blocks';
type NestedListKey = 'group_blocks';
type State = Record<NestedListKey, Record<string, List>>;
const initialState: State = {
pinned: {},
familiar_followers: {},
group_blocks: {},
};
@ -37,12 +33,8 @@ const normalizeList = (state: State, path: NestedListPath, accounts: Array<Pick<
draft[path[0]][path[1]] = newList;
});
const userLists = (state = initialState, action: AccountsAction | FamiliarFollowersAction | GroupsAction): State => {
const userLists = (state = initialState, action: GroupsAction): State => {
switch (action.type) {
case PINNED_ACCOUNTS_FETCH_SUCCESS:
return normalizeList(state, ['pinned', action.accountId], action.accounts, action.next);
case FAMILIAR_FOLLOWERS_FETCH_SUCCESS:
return normalizeList(state, ['familiar_followers', action.accountId], action.accounts);
case GROUP_BLOCKS_FETCH_SUCCESS:
return normalizeList(state, ['group_blocks', action.groupId], action.accounts, action.next);
case GROUP_BLOCKS_FETCH_REQUEST: