pl-fe: migrate list editing modals to tanstack query
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@ -1,5 +1,4 @@
|
||||
import { queryClient } from 'pl-fe/queries/client';
|
||||
import { selectAccount } from 'pl-fe/selectors';
|
||||
import toast from 'pl-fe/toast';
|
||||
import { isLoggedIn } from 'pl-fe/utils/auth';
|
||||
|
||||
@ -7,7 +6,7 @@ import { getClient } from '../api';
|
||||
|
||||
import { importEntities } from './importer';
|
||||
|
||||
import type { Account, List, PaginatedResponse } from 'pl-api';
|
||||
import type { Account, List } from 'pl-api';
|
||||
import type { AppDispatch, RootState } from 'pl-fe/store';
|
||||
|
||||
const LIST_EDITOR_TITLE_CHANGE = 'LIST_EDITOR_TITLE_CHANGE' as const;
|
||||
@ -16,25 +15,10 @@ const LIST_EDITOR_EXCLUSIVE_CHANGE = 'LIST_EDITOR_EXCLUSIVE_CHANGE' as const;
|
||||
const LIST_EDITOR_RESET = 'LIST_EDITOR_RESET' as const;
|
||||
const LIST_EDITOR_SETUP = 'LIST_EDITOR_SETUP' as const;
|
||||
|
||||
const LIST_ACCOUNTS_FETCH_REQUEST = 'LIST_ACCOUNTS_FETCH_REQUEST' as const;
|
||||
const LIST_ACCOUNTS_FETCH_SUCCESS = 'LIST_ACCOUNTS_FETCH_SUCCESS' as const;
|
||||
const LIST_ACCOUNTS_FETCH_FAIL = 'LIST_ACCOUNTS_FETCH_FAIL' as const;
|
||||
|
||||
const LIST_EDITOR_SUGGESTIONS_CHANGE = 'LIST_EDITOR_SUGGESTIONS_CHANGE' as const;
|
||||
const LIST_EDITOR_SUGGESTIONS_READY = 'LIST_EDITOR_SUGGESTIONS_READY' as const;
|
||||
const LIST_EDITOR_SUGGESTIONS_CLEAR = 'LIST_EDITOR_SUGGESTIONS_CLEAR' as const;
|
||||
|
||||
const LIST_EDITOR_ADD_SUCCESS = 'LIST_EDITOR_ADD_SUCCESS' as const;
|
||||
|
||||
const LIST_EDITOR_REMOVE_SUCCESS = 'LIST_EDITOR_REMOVE_SUCCESS' as const;
|
||||
|
||||
const LIST_ADDER_RESET = 'LIST_ADDER_RESET' as const;
|
||||
const LIST_ADDER_SETUP = 'LIST_ADDER_SETUP' as const;
|
||||
|
||||
const LIST_ADDER_LISTS_FETCH_REQUEST = 'LIST_ADDER_LISTS_FETCH_REQUEST' as const;
|
||||
const LIST_ADDER_LISTS_FETCH_SUCCESS = 'LIST_ADDER_LISTS_FETCH_SUCCESS' as const;
|
||||
const LIST_ADDER_LISTS_FETCH_FAIL = 'LIST_ADDER_LISTS_FETCH_FAIL' as const;
|
||||
|
||||
interface ListEditorSetupAction {
|
||||
type: typeof LIST_EDITOR_SETUP;
|
||||
list: List;
|
||||
@ -48,8 +32,6 @@ const setupListEditor = (listId: string) => (dispatch: AppDispatch) => {
|
||||
type: LIST_EDITOR_SETUP,
|
||||
list,
|
||||
});
|
||||
|
||||
dispatch(fetchListAccounts(listId));
|
||||
};
|
||||
|
||||
const changeListEditorTitle = (value: string) => ({
|
||||
@ -71,35 +53,6 @@ const resetListEditor = () => ({
|
||||
type: LIST_EDITOR_RESET,
|
||||
});
|
||||
|
||||
const fetchListAccounts = (listId: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
|
||||
dispatch(fetchListAccountsRequest(listId));
|
||||
|
||||
return getClient(getState()).lists.getListAccounts(listId).then(({ items, next }) => {
|
||||
dispatch(importEntities({ accounts: items }));
|
||||
dispatch(fetchListAccountsSuccess(listId, items, next));
|
||||
}).catch(err => dispatch(fetchListAccountsFail(listId, err)));
|
||||
};
|
||||
|
||||
const fetchListAccountsRequest = (listId: string) => ({
|
||||
type: LIST_ACCOUNTS_FETCH_REQUEST,
|
||||
listId,
|
||||
});
|
||||
|
||||
const fetchListAccountsSuccess = (listId: string, accounts: Account[], next: (() => Promise<PaginatedResponse<Account>>) | null) => ({
|
||||
type: LIST_ACCOUNTS_FETCH_SUCCESS,
|
||||
listId,
|
||||
accounts,
|
||||
next,
|
||||
});
|
||||
|
||||
const fetchListAccountsFail = (listId: string, error: unknown) => ({
|
||||
type: LIST_ACCOUNTS_FETCH_FAIL,
|
||||
listId,
|
||||
error,
|
||||
});
|
||||
|
||||
const fetchListSuggestions = (q: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
|
||||
@ -124,114 +77,15 @@ const changeListSuggestions = (value: string) => ({
|
||||
value,
|
||||
});
|
||||
|
||||
const addToListEditor = (accountId: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
dispatch(addToList(getState().listEditor.listId!, accountId));
|
||||
};
|
||||
|
||||
const addToList = (listId: string, accountId: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
|
||||
return getClient(getState()).lists.addListAccounts(listId, [accountId])
|
||||
.then(() => dispatch(addToListSuccess(listId, accountId)));
|
||||
};
|
||||
|
||||
const addToListSuccess = (listId: string, accountId: string) => ({
|
||||
type: LIST_EDITOR_ADD_SUCCESS,
|
||||
listId,
|
||||
accountId,
|
||||
});
|
||||
|
||||
const removeFromListEditor = (accountId: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
dispatch(removeFromList(getState().listEditor.listId!, accountId));
|
||||
};
|
||||
|
||||
const removeFromList = (listId: string, accountId: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
|
||||
return getClient(getState()).lists.deleteListAccounts(listId, [accountId])
|
||||
.then(() => dispatch(removeFromListSuccess(listId, accountId)));
|
||||
};
|
||||
|
||||
const removeFromListSuccess = (listId: string, accountId: string) => ({
|
||||
type: LIST_EDITOR_REMOVE_SUCCESS,
|
||||
listId,
|
||||
accountId,
|
||||
});
|
||||
|
||||
const resetListAdder = () => ({
|
||||
type: LIST_ADDER_RESET,
|
||||
});
|
||||
|
||||
interface ListAdderSetupAction {
|
||||
type: typeof LIST_ADDER_SETUP;
|
||||
account: Account;
|
||||
}
|
||||
|
||||
const setupListAdder = (accountId: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const account = selectAccount(getState(), accountId);
|
||||
if (!account) return;
|
||||
|
||||
dispatch<ListAdderSetupAction>({
|
||||
type: LIST_ADDER_SETUP,
|
||||
account,
|
||||
});
|
||||
dispatch(fetchAccountLists(accountId));
|
||||
};
|
||||
|
||||
const fetchAccountLists = (accountId: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
|
||||
dispatch(fetchAccountListsRequest(accountId));
|
||||
|
||||
return getClient(getState()).accounts.getAccountLists(accountId)
|
||||
.then((data) => dispatch(fetchAccountListsSuccess(accountId, data)))
|
||||
.catch(err => dispatch(fetchAccountListsFail(accountId, err)));
|
||||
};
|
||||
|
||||
const fetchAccountListsRequest = (listId: string) => ({
|
||||
type: LIST_ADDER_LISTS_FETCH_REQUEST,
|
||||
listId,
|
||||
});
|
||||
|
||||
const fetchAccountListsSuccess = (listId: string, lists: Array<List>) => ({
|
||||
type: LIST_ADDER_LISTS_FETCH_SUCCESS,
|
||||
listId,
|
||||
lists,
|
||||
});
|
||||
|
||||
const fetchAccountListsFail = (listId: string, err: unknown) => ({
|
||||
type: LIST_ADDER_LISTS_FETCH_FAIL,
|
||||
listId,
|
||||
err,
|
||||
});
|
||||
|
||||
const addToListAdder = (listId: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
dispatch(addToList(listId, getState().listAdder.accountId!));
|
||||
};
|
||||
|
||||
const removeFromListAdder = (listId: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
dispatch(removeFromList(listId, getState().listAdder.accountId!));
|
||||
};
|
||||
|
||||
type ListsAction =
|
||||
| ListEditorSetupAction
|
||||
| ReturnType<typeof changeListEditorTitle>
|
||||
| ReturnType<typeof changeListEditorRepliesPolicy>
|
||||
| ReturnType<typeof changeListEditorExclusive>
|
||||
| ReturnType<typeof resetListEditor>
|
||||
| ReturnType<typeof fetchListAccountsRequest>
|
||||
| ReturnType<typeof fetchListAccountsSuccess>
|
||||
| ReturnType<typeof fetchListAccountsFail>
|
||||
| ReturnType<typeof fetchListSuggestionsReady>
|
||||
| ReturnType<typeof clearListSuggestions>
|
||||
| ReturnType<typeof changeListSuggestions>
|
||||
| ReturnType<typeof addToListSuccess>
|
||||
| ReturnType<typeof removeFromListSuccess>
|
||||
| ReturnType<typeof resetListAdder>
|
||||
| ListAdderSetupAction
|
||||
| ReturnType<typeof fetchAccountListsRequest>
|
||||
| ReturnType<typeof fetchAccountListsSuccess>
|
||||
| ReturnType<typeof fetchAccountListsFail>;
|
||||
| ReturnType<typeof changeListSuggestions>;
|
||||
|
||||
export {
|
||||
LIST_EDITOR_TITLE_CHANGE,
|
||||
@ -239,19 +93,9 @@ export {
|
||||
LIST_EDITOR_EXCLUSIVE_CHANGE,
|
||||
LIST_EDITOR_RESET,
|
||||
LIST_EDITOR_SETUP,
|
||||
LIST_ACCOUNTS_FETCH_REQUEST,
|
||||
LIST_ACCOUNTS_FETCH_SUCCESS,
|
||||
LIST_ACCOUNTS_FETCH_FAIL,
|
||||
LIST_EDITOR_SUGGESTIONS_CHANGE,
|
||||
LIST_EDITOR_SUGGESTIONS_READY,
|
||||
LIST_EDITOR_SUGGESTIONS_CLEAR,
|
||||
LIST_EDITOR_ADD_SUCCESS,
|
||||
LIST_EDITOR_REMOVE_SUCCESS,
|
||||
LIST_ADDER_RESET,
|
||||
LIST_ADDER_SETUP,
|
||||
LIST_ADDER_LISTS_FETCH_REQUEST,
|
||||
LIST_ADDER_LISTS_FETCH_SUCCESS,
|
||||
LIST_ADDER_LISTS_FETCH_FAIL,
|
||||
setupListEditor,
|
||||
changeListEditorTitle,
|
||||
changeListEditorRepliesPolicy,
|
||||
@ -260,11 +104,5 @@ export {
|
||||
fetchListSuggestions,
|
||||
clearListSuggestions,
|
||||
changeListSuggestions,
|
||||
addToListEditor,
|
||||
removeFromListEditor,
|
||||
resetListAdder,
|
||||
setupListAdder,
|
||||
addToListAdder,
|
||||
removeFromListAdder,
|
||||
type ListsAction,
|
||||
};
|
||||
|
||||
@ -71,7 +71,7 @@ const messages = defineMessages({
|
||||
bite: { id: 'account.bite', defaultMessage: 'Bite @{name}' },
|
||||
removeFromFollowers: { id: 'account.remove_from_followers', defaultMessage: 'Remove this follower' },
|
||||
adminAccount: { id: 'status.admin_account', defaultMessage: 'Moderate @{name}' },
|
||||
add_or_remove_from_list: { id: 'account.add_or_remove_from_list', defaultMessage: 'Add or Remove from lists' },
|
||||
add_or_remove_from_list: { id: 'account.add_or_remove_from_list', defaultMessage: 'Add or remove from lists' },
|
||||
search: { id: 'account.search', defaultMessage: 'Search from @{name}' },
|
||||
searchSelf: { id: 'account.search_self', defaultMessage: 'Search your posts' },
|
||||
unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
|
||||
|
||||
@ -1,12 +1,9 @@
|
||||
import React from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { removeFromListAdder, addToListAdder } from 'pl-fe/actions/lists';
|
||||
import Icon from 'pl-fe/components/icon';
|
||||
import IconButton from 'pl-fe/components/icon-button';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
|
||||
import { useList } from 'pl-fe/queries/accounts/use-lists';
|
||||
import { useAddAccountsToList, useList, useRemoveAccountsFromList } from 'pl-fe/queries/accounts/use-lists';
|
||||
|
||||
const messages = defineMessages({
|
||||
remove: { id: 'lists.account.remove', defaultMessage: 'Remove from list' },
|
||||
@ -14,18 +11,21 @@ const messages = defineMessages({
|
||||
});
|
||||
|
||||
interface IList {
|
||||
accountId: string;
|
||||
listId: string;
|
||||
added?: boolean;
|
||||
}
|
||||
|
||||
const List: React.FC<IList> = ({ listId }) => {
|
||||
const List: React.FC<IList> = ({ listId, accountId, added }) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const { data: list } = useList(listId);
|
||||
const added = useAppSelector((state) => state.listAdder.lists.items.includes(listId));
|
||||
|
||||
const onRemove = () => dispatch(removeFromListAdder(listId));
|
||||
const onAdd = () => dispatch(addToListAdder(listId));
|
||||
const { mutate: addToList } = useAddAccountsToList(listId);
|
||||
const { mutate: removeFromList } = useRemoveAccountsFromList(listId);
|
||||
|
||||
const onAdd = () => addToList([accountId]);
|
||||
const onRemove = () => removeFromList([accountId]);
|
||||
|
||||
if (!list) return null;
|
||||
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import React from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import { setupListAdder, resetListAdder } from 'pl-fe/actions/lists';
|
||||
import { CardHeader, CardTitle } from 'pl-fe/components/ui/card';
|
||||
import Modal from 'pl-fe/components/ui/modal';
|
||||
import AccountContainer from 'pl-fe/containers/account-container';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { NewListForm, getOrderedLists } from 'pl-fe/pages/account-lists/lists';
|
||||
import { useLists } from 'pl-fe/queries/accounts/use-lists';
|
||||
import { useLists, useListsForAccount } from 'pl-fe/queries/accounts/use-lists';
|
||||
|
||||
import List from './components/list';
|
||||
|
||||
@ -24,25 +22,18 @@ interface ListAdderModalProps {
|
||||
|
||||
const ListAdderModal: React.FC<BaseModalProps & ListAdderModalProps> = ({ accountId, onClose }) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const { data: accountListIds = [] } = useListsForAccount(accountId);
|
||||
|
||||
const { data: listIds = [] } = useLists((lists) => getOrderedLists(lists).map(list => list.id));
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(setupListAdder(accountId));
|
||||
|
||||
return () => {
|
||||
dispatch(resetListAdder());
|
||||
};
|
||||
}, []);
|
||||
|
||||
const onClickClose = () => {
|
||||
onClose('LIST_ADDER');
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={<FormattedMessage id='list_adder.header_title' defaultMessage='Add or Remove from Lists' />}
|
||||
title={<FormattedMessage id='list_adder.header_title' defaultMessage='Add or remove from lists' />}
|
||||
onClose={onClickClose}
|
||||
>
|
||||
<AccountContainer id={accountId} withRelationship={false} />
|
||||
@ -60,7 +51,7 @@ const ListAdderModal: React.FC<BaseModalProps & ListAdderModalProps> = ({ accoun
|
||||
<CardTitle title={intl.formatMessage(messages.subheading)} />
|
||||
</CardHeader>
|
||||
<div>
|
||||
{listIds.map(listId => <List key={listId} listId={listId} />)}
|
||||
{listIds.map(listId => <List key={listId} accountId={accountId} listId={listId} added={accountListIds.includes(listId)} />)}
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
import React from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { removeFromListEditor, addToListEditor } from 'pl-fe/actions/lists';
|
||||
import IconButton from 'pl-fe/components/icon-button';
|
||||
import HStack from 'pl-fe/components/ui/hstack';
|
||||
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 { useAddAccountsToList, useRemoveAccountsFromList } from 'pl-fe/queries/accounts/use-lists';
|
||||
|
||||
const messages = defineMessages({
|
||||
remove: { id: 'lists.account.remove', defaultMessage: 'Remove from list' },
|
||||
@ -14,21 +12,23 @@ const messages = defineMessages({
|
||||
});
|
||||
|
||||
interface IAccount {
|
||||
listId: string;
|
||||
accountId: string;
|
||||
added?: boolean;
|
||||
}
|
||||
|
||||
const Account: React.FC<IAccount> = ({ accountId }) => {
|
||||
const Account: React.FC<IAccount> = ({ listId, accountId, added }) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const isAdded = useAppSelector((state) => state.listEditor.accounts.items.includes(accountId));
|
||||
const { mutate: addToList } = useAddAccountsToList(listId);
|
||||
const { mutate: removeFromList } = useRemoveAccountsFromList(listId);
|
||||
|
||||
const onRemove = () => dispatch(removeFromListEditor(accountId));
|
||||
const onAdd = () => dispatch(addToListEditor(accountId));
|
||||
const onAdd = () => addToList([accountId]);
|
||||
const onRemove = () => removeFromList([accountId]);
|
||||
|
||||
let button;
|
||||
|
||||
if (isAdded) {
|
||||
if (added) {
|
||||
button = <IconButton src={require('@tabler/icons/outline/x.svg')} iconClassName='h-5 w-5' title={intl.formatMessage(messages.remove)} onClick={onRemove} />;
|
||||
} else {
|
||||
button = <IconButton src={require('@tabler/icons/outline/plus.svg')} iconClassName='h-5 w-5' title={intl.formatMessage(messages.add)} onClick={onAdd} />;
|
||||
|
||||
@ -6,6 +6,7 @@ import { CardHeader, CardTitle } from 'pl-fe/components/ui/card';
|
||||
import Modal from 'pl-fe/components/ui/modal';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
|
||||
import { useListAccounts } from 'pl-fe/queries/accounts/use-lists';
|
||||
|
||||
import Account from './components/account';
|
||||
import EditListForm from './components/edit-list-form';
|
||||
@ -29,7 +30,7 @@ const ListEditorModal: React.FC<BaseModalProps & ListEditorModalProps> = ({ list
|
||||
|
||||
const [tab, setTab] = useState<'info' | 'members'>('info');
|
||||
|
||||
const accountIds = useAppSelector((state) => state.listEditor.accounts.items);
|
||||
const { data: accountIds = [] } = useListAccounts(listId);
|
||||
const searchAccountIds = useAppSelector((state) => state.listEditor.suggestions.items);
|
||||
|
||||
useEffect(() => {
|
||||
@ -61,7 +62,7 @@ const ListEditorModal: React.FC<BaseModalProps & ListEditorModalProps> = ({ list
|
||||
<CardTitle title={intl.formatMessage(messages.removeFromList)} />
|
||||
</CardHeader>
|
||||
<div className='max-h-48 overflow-y-auto'>
|
||||
{accountIds.map(accountId => <Account key={accountId} accountId={accountId} />)}
|
||||
{accountIds.map(accountId => <Account key={accountId} listId={listId} accountId={accountId} added={accountIds.includes(accountId)} />)}
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
@ -73,7 +74,7 @@ const ListEditorModal: React.FC<BaseModalProps & ListEditorModalProps> = ({ list
|
||||
</CardHeader>
|
||||
<Search />
|
||||
<div className='max-h-48 overflow-y-auto'>
|
||||
{searchAccountIds.map(accountId => <Account key={accountId} accountId={accountId} />)}
|
||||
{searchAccountIds.map(accountId => <Account key={accountId} listId={listId} accountId={accountId} added={accountIds.includes(accountId)} />)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
@ -1,11 +1,14 @@
|
||||
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||
import { type InfiniteData, useMutation, useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { useClient } from 'pl-fe/hooks/use-client';
|
||||
import { useFeatures } from 'pl-fe/hooks/use-features';
|
||||
|
||||
import { queryClient } from '../client';
|
||||
import { filterById } from '../utils/filter-id';
|
||||
import { makePaginatedResponseQuery } from '../utils/make-paginated-response-query';
|
||||
import { minifyAccountList } from '../utils/minify-list';
|
||||
|
||||
import type { CreateListParams, List, UpdateListParams } from 'pl-api';
|
||||
import type { CreateListParams, List, PaginatedResponse, UpdateListParams } from 'pl-api';
|
||||
|
||||
const useLists = <T>(
|
||||
select?: ((data: Array<List>) => T),
|
||||
@ -58,4 +61,48 @@ const useUpdateList = (listId: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
export { useLists, useList, useCreateList, useDeleteList, useUpdateList };
|
||||
const useListAccounts = makePaginatedResponseQuery(
|
||||
(listId: string) => ['accountsLists', 'lists', listId],
|
||||
(client, [listId]) => client.lists.getListAccounts(listId).then(minifyAccountList),
|
||||
);
|
||||
|
||||
const useAddAccountsToList = (listId: string) => {
|
||||
const client = useClient();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['accountsLists', 'lists', listId, 'add'],
|
||||
mutationFn: (accountIds: Array<string>) => client.lists.addListAccounts(listId, accountIds),
|
||||
onSettled: (_, __, accountIds) => {
|
||||
queryClient.invalidateQueries({ queryKey: ['accountsLists', 'lists', listId] });
|
||||
accountIds.forEach((accountId) =>
|
||||
queryClient.setQueryData<Array<string>>(['lists', 'forAccount', accountId], (listIds) => listIds ? [...listIds, listId] : undefined),
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const useRemoveAccountsFromList = (listId: string) => {
|
||||
const client = useClient();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['accountsLists', 'lists', listId, 'remove'],
|
||||
mutationFn: (accountIds: Array<string>) => client.lists.deleteListAccounts(listId, accountIds),
|
||||
onSettled: (_, __, accountIds) => {
|
||||
queryClient.setQueryData<InfiniteData<PaginatedResponse<string>>>(['accountsLists', 'lists', listId], filterById(accountIds));
|
||||
accountIds.forEach((accountId) =>
|
||||
queryClient.setQueryData<Array<string>>(['lists', 'forAccount', accountId], listIds => listIds?.filter(id => id !== listId)),
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const useListsForAccount = (accountId: string) => {
|
||||
const client = useClient();
|
||||
|
||||
return useQuery({
|
||||
queryKey: ['lists', 'forAccount', accountId],
|
||||
queryFn: () => client.accounts.getAccountLists(accountId).then((lists) => lists.map((list) => list.id)),
|
||||
});
|
||||
};
|
||||
|
||||
export { useLists, useList, useCreateList, useDeleteList, useUpdateList, useListAccounts, useAddAccountsToList, useRemoveAccountsFromList, useListsForAccount };
|
||||
|
||||
@ -3,19 +3,24 @@ import { create } from 'mutative';
|
||||
import type { InfiniteData } from '@tanstack/react-query';
|
||||
import type { PaginatedResponse } from 'pl-api';
|
||||
|
||||
const filterById = (filteredId: string) => (data: InfiniteData<PaginatedResponse<string, true>, unknown> | undefined) => {
|
||||
const filterById = (filteredId: string | Array<string>) => (data: InfiniteData<PaginatedResponse<string, true>, unknown> | undefined) => {
|
||||
if (data) {
|
||||
return create((data), data => {
|
||||
let found = false;
|
||||
let found = 0;
|
||||
data.pages.forEach((page) => {
|
||||
page.items = page.items.filter((id) => {
|
||||
if (id === filteredId) found = true;
|
||||
if (Array.isArray(filteredId)) {
|
||||
const includes = filteredId.includes(id);
|
||||
if (includes) found += 1;
|
||||
return !includes;
|
||||
}
|
||||
if (id === filteredId) found = 1;
|
||||
return id !== filteredId;
|
||||
});
|
||||
});
|
||||
|
||||
if (found) data.pages.forEach((page) => {
|
||||
if (page.total) page.total -= 1;
|
||||
if (page.total) page.total -= found;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -13,7 +13,6 @@ import conversations from './conversations';
|
||||
import draft_statuses from './draft-statuses';
|
||||
import filters from './filters';
|
||||
import instance from './instance';
|
||||
import listAdder from './list-adder';
|
||||
import listEditor from './list-editor';
|
||||
import me from './me';
|
||||
import meta from './meta';
|
||||
@ -39,7 +38,6 @@ const reducers = {
|
||||
entities,
|
||||
filters,
|
||||
instance,
|
||||
listAdder,
|
||||
listEditor,
|
||||
me,
|
||||
meta,
|
||||
|
||||
@ -1,116 +0,0 @@
|
||||
import { List as ImmutableList, Record as ImmutableRecord } from 'immutable';
|
||||
|
||||
import * as actions from 'pl-fe/actions/lists';
|
||||
|
||||
import reducer from './list-adder';
|
||||
|
||||
describe('list_adder reducer', () => {
|
||||
it('should return the initial state', () => {
|
||||
expect(reducer(undefined, {} as any)).toMatchObject({
|
||||
accountId: null,
|
||||
|
||||
lists: {
|
||||
items: ImmutableList(),
|
||||
loaded: false,
|
||||
isLoading: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle LIST_ADDER_RESET', () => {
|
||||
const state = ImmutableRecord({
|
||||
accountId: null,
|
||||
|
||||
lists: ImmutableRecord({
|
||||
items: ImmutableList<string>(),
|
||||
loaded: false,
|
||||
isLoading: false,
|
||||
})(),
|
||||
})();
|
||||
const action = {
|
||||
type: actions.LIST_ADDER_RESET,
|
||||
};
|
||||
expect(reducer(state, action)).toMatchObject({
|
||||
accountId: null,
|
||||
|
||||
lists: {
|
||||
items: ImmutableList(),
|
||||
loaded: false,
|
||||
isLoading: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle LIST_ADDER_LISTS_FETCH_REQUEST', () => {
|
||||
const state = ImmutableRecord({
|
||||
accountId: null,
|
||||
|
||||
lists: ImmutableRecord({
|
||||
items: ImmutableList<string>(),
|
||||
loaded: false,
|
||||
isLoading: false,
|
||||
})(),
|
||||
})();
|
||||
const action = {
|
||||
type: actions.LIST_ADDER_LISTS_FETCH_REQUEST,
|
||||
};
|
||||
expect(reducer(state, action)).toMatchObject({
|
||||
accountId: null,
|
||||
|
||||
lists: {
|
||||
items: ImmutableList(),
|
||||
loaded: false,
|
||||
isLoading: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle LIST_ADDER_LISTS_FETCH_FAIL', () => {
|
||||
const state = ImmutableRecord({
|
||||
accountId: null,
|
||||
|
||||
lists: ImmutableRecord({
|
||||
items: ImmutableList<string>(),
|
||||
loaded: false,
|
||||
isLoading: false,
|
||||
})(),
|
||||
})();
|
||||
const action = {
|
||||
type: actions.LIST_ADDER_LISTS_FETCH_FAIL,
|
||||
};
|
||||
expect(reducer(state, action)).toMatchObject({
|
||||
accountId: null,
|
||||
|
||||
lists: {
|
||||
items: ImmutableList(),
|
||||
loaded: false,
|
||||
isLoading: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// it('should handle LIST_ADDER_LISTS_FETCH_SUCCESS', () => {
|
||||
// const state = ImmutableMap({
|
||||
// accountId: null,
|
||||
//
|
||||
// lists: ImmutableMap({
|
||||
// items: ImmutableList(),
|
||||
// loaded: false,
|
||||
// isLoading: false,
|
||||
// }),
|
||||
// });
|
||||
// const action = {
|
||||
// type: actions.LIST_ADDER_LISTS_FETCH_SUCCESS,
|
||||
// };
|
||||
// expect(reducer(state, action)).toEqual(ImmutableMap({
|
||||
// accountId: null,
|
||||
//
|
||||
// lists: ImmutableMap({
|
||||
// items: ImmutableList(),
|
||||
// loaded: true,
|
||||
// isLoading: false,
|
||||
// }),
|
||||
// }));
|
||||
// });
|
||||
|
||||
});
|
||||
@ -1,67 +0,0 @@
|
||||
import { create } from 'mutative';
|
||||
|
||||
import {
|
||||
LIST_ADDER_RESET,
|
||||
LIST_ADDER_SETUP,
|
||||
LIST_ADDER_LISTS_FETCH_REQUEST,
|
||||
LIST_ADDER_LISTS_FETCH_SUCCESS,
|
||||
LIST_ADDER_LISTS_FETCH_FAIL,
|
||||
LIST_EDITOR_ADD_SUCCESS,
|
||||
LIST_EDITOR_REMOVE_SUCCESS,
|
||||
type ListsAction,
|
||||
} from '../actions/lists';
|
||||
|
||||
interface State {
|
||||
accountId: string | null;
|
||||
lists: {
|
||||
items: Array<string>;
|
||||
loaded: boolean;
|
||||
isLoading: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
const initialState: State = {
|
||||
accountId: null,
|
||||
lists: {
|
||||
items: [],
|
||||
loaded: false,
|
||||
isLoading: false,
|
||||
},
|
||||
};
|
||||
|
||||
const listAdderReducer = (state: State = initialState, action: ListsAction): State => {
|
||||
switch (action.type) {
|
||||
case LIST_ADDER_RESET:
|
||||
return initialState;
|
||||
case LIST_ADDER_SETUP:
|
||||
return create(state, (draft) => {
|
||||
draft.accountId = action.account.id;
|
||||
});
|
||||
case LIST_ADDER_LISTS_FETCH_REQUEST:
|
||||
return create(state, (draft) => {
|
||||
draft.lists.isLoading = true;
|
||||
});
|
||||
case LIST_ADDER_LISTS_FETCH_FAIL:
|
||||
return create(state, (draft) => {
|
||||
draft.lists.isLoading = false;
|
||||
});
|
||||
case LIST_ADDER_LISTS_FETCH_SUCCESS:
|
||||
return create(state, (draft) => {
|
||||
draft.lists.isLoading = false;
|
||||
draft.lists.loaded = true;
|
||||
draft.lists.items = action.lists.map((item: { id: string }) => item.id);
|
||||
});
|
||||
case LIST_EDITOR_ADD_SUCCESS:
|
||||
return create(state, (draft) => {
|
||||
draft.lists.items = [action.listId, ...draft.lists.items];
|
||||
});
|
||||
case LIST_EDITOR_REMOVE_SUCCESS:
|
||||
return create(state, (draft) => {
|
||||
draft.lists.items = draft.lists.items.filter(id => id !== action.listId);
|
||||
});
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export { listAdderReducer as default };
|
||||
@ -4,14 +4,9 @@ import {
|
||||
LIST_EDITOR_RESET,
|
||||
LIST_EDITOR_SETUP,
|
||||
LIST_EDITOR_TITLE_CHANGE,
|
||||
LIST_ACCOUNTS_FETCH_REQUEST,
|
||||
LIST_ACCOUNTS_FETCH_SUCCESS,
|
||||
LIST_ACCOUNTS_FETCH_FAIL,
|
||||
LIST_EDITOR_SUGGESTIONS_READY,
|
||||
LIST_EDITOR_SUGGESTIONS_CLEAR,
|
||||
LIST_EDITOR_SUGGESTIONS_CHANGE,
|
||||
LIST_EDITOR_ADD_SUCCESS,
|
||||
LIST_EDITOR_REMOVE_SUCCESS,
|
||||
type ListsAction,
|
||||
LIST_EDITOR_EXCLUSIVE_CHANGE,
|
||||
LIST_EDITOR_REPLIES_POLICY_CHANGE,
|
||||
@ -27,12 +22,6 @@ interface State {
|
||||
repliesPolicy: List['replies_policy'];
|
||||
exclusive?: boolean;
|
||||
|
||||
accounts: {
|
||||
items: Array<string>;
|
||||
loaded: boolean;
|
||||
isLoading: boolean;
|
||||
};
|
||||
|
||||
suggestions: {
|
||||
value: string;
|
||||
items: Array<string>;
|
||||
@ -46,12 +35,6 @@ const initialState: State = {
|
||||
repliesPolicy: undefined,
|
||||
exclusive: false,
|
||||
|
||||
accounts: {
|
||||
items: [],
|
||||
loaded: false,
|
||||
isLoading: false,
|
||||
},
|
||||
|
||||
suggestions: {
|
||||
value: '',
|
||||
items: [],
|
||||
@ -82,20 +65,6 @@ const listEditorReducer = (state: State = initialState, action: ListsAction): St
|
||||
return create(state, (draft) => {
|
||||
draft.repliesPolicy = action.repliesPolicy;
|
||||
});
|
||||
case LIST_ACCOUNTS_FETCH_REQUEST:
|
||||
return create(state, (draft) => {
|
||||
draft.accounts.isLoading = true;
|
||||
});
|
||||
case LIST_ACCOUNTS_FETCH_FAIL:
|
||||
return create(state, (draft) => {
|
||||
draft.accounts.isLoading = false;
|
||||
});
|
||||
case LIST_ACCOUNTS_FETCH_SUCCESS:
|
||||
return create(state, (draft) => {
|
||||
draft.accounts.isLoading = false;
|
||||
draft.accounts.loaded = true;
|
||||
draft.accounts.items = action.accounts.map((item: { id: string }) => item.id);
|
||||
});
|
||||
case LIST_EDITOR_SUGGESTIONS_CHANGE:
|
||||
return create(state, (draft) => {
|
||||
draft.suggestions.value = action.value;
|
||||
@ -109,14 +78,6 @@ const listEditorReducer = (state: State = initialState, action: ListsAction): St
|
||||
draft.suggestions.items = [];
|
||||
draft.suggestions.value = '';
|
||||
});
|
||||
case LIST_EDITOR_ADD_SUCCESS:
|
||||
return create(state, (draft) => {
|
||||
draft.accounts.items = [action.accountId, ...draft.accounts.items];
|
||||
});
|
||||
case LIST_EDITOR_REMOVE_SUCCESS:
|
||||
return create(state, (draft) => {
|
||||
draft.accounts.items = draft.accounts.items.filter(id => id !== action.accountId);
|
||||
});
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user