pl-fe: migrate lists to tanstack query
Signed-off-by: Nicole Mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@ -1,3 +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';
|
||||
@ -9,25 +10,10 @@ import { importEntities } from './importer';
|
||||
import type { Account, List, PaginatedResponse } from 'pl-api';
|
||||
import type { AppDispatch, RootState } from 'pl-fe/store';
|
||||
|
||||
const LIST_FETCH_SUCCESS = 'LIST_FETCH_SUCCESS' as const;
|
||||
const LIST_FETCH_FAIL = 'LIST_FETCH_FAIL' as const;
|
||||
|
||||
const LISTS_FETCH_SUCCESS = 'LISTS_FETCH_SUCCESS' as const;
|
||||
|
||||
const LIST_EDITOR_TITLE_CHANGE = 'LIST_EDITOR_TITLE_CHANGE' as const;
|
||||
const LIST_EDITOR_RESET = 'LIST_EDITOR_RESET' as const;
|
||||
const LIST_EDITOR_SETUP = 'LIST_EDITOR_SETUP' as const;
|
||||
|
||||
const LIST_CREATE_REQUEST = 'LIST_CREATE_REQUEST' as const;
|
||||
const LIST_CREATE_SUCCESS = 'LIST_CREATE_SUCCESS' as const;
|
||||
const LIST_CREATE_FAIL = 'LIST_CREATE_FAIL' as const;
|
||||
|
||||
const LIST_UPDATE_REQUEST = 'LIST_UPDATE_REQUEST' as const;
|
||||
const LIST_UPDATE_SUCCESS = 'LIST_UPDATE_SUCCESS' as const;
|
||||
const LIST_UPDATE_FAIL = 'LIST_UPDATE_FAIL' as const;
|
||||
|
||||
const LIST_DELETE_SUCCESS = 'LIST_DELETE_SUCCESS' 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;
|
||||
@ -47,59 +33,13 @@ 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;
|
||||
|
||||
const fetchList = (listId: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
|
||||
if (getState().lists[listId]) {
|
||||
return;
|
||||
}
|
||||
|
||||
return getClient(getState()).lists.getList(listId)
|
||||
.then((data) => dispatch(fetchListSuccess(data)))
|
||||
.catch(err => dispatch(fetchListFail(listId, err)));
|
||||
};
|
||||
|
||||
const fetchListSuccess = (list: List) => ({
|
||||
type: LIST_FETCH_SUCCESS,
|
||||
list,
|
||||
});
|
||||
|
||||
const fetchListFail = (listId: string, error: unknown) => ({
|
||||
type: LIST_FETCH_FAIL,
|
||||
listId,
|
||||
error,
|
||||
});
|
||||
|
||||
const fetchLists = () => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
|
||||
return getClient(getState()).lists.getLists()
|
||||
.then((data) => dispatch(fetchListsSuccess(data)));
|
||||
};
|
||||
|
||||
const fetchListsSuccess = (lists: Array<List>) => ({
|
||||
type: LISTS_FETCH_SUCCESS,
|
||||
lists,
|
||||
});
|
||||
|
||||
const submitListEditor = (shouldReset?: boolean) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const listId = getState().listEditor.listId!;
|
||||
const title = getState().listEditor.title;
|
||||
|
||||
if (listId === null) {
|
||||
dispatch(createList(title, shouldReset));
|
||||
} else {
|
||||
dispatch(updateList(listId, title, shouldReset));
|
||||
}
|
||||
};
|
||||
|
||||
interface ListEditorSetupAction {
|
||||
type: typeof LIST_EDITOR_SETUP;
|
||||
list: List;
|
||||
}
|
||||
|
||||
const setupListEditor = (listId: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const list = getState().lists[listId];
|
||||
const setupListEditor = (listId: string) => (dispatch: AppDispatch) => {
|
||||
const list = queryClient.getQueryData<Array<List>>(['lists'])?.find((list) => list.id === listId);
|
||||
if (!list) return;
|
||||
|
||||
dispatch<ListEditorSetupAction>({
|
||||
@ -115,80 +55,10 @@ const changeListEditorTitle = (value: string) => ({
|
||||
value,
|
||||
});
|
||||
|
||||
const createList = (title: string, shouldReset?: boolean) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
|
||||
dispatch(createListRequest());
|
||||
|
||||
return getClient(getState()).lists.createList({ title }).then((data) => {
|
||||
dispatch(createListSuccess(data));
|
||||
|
||||
if (shouldReset) {
|
||||
dispatch(resetListEditor());
|
||||
}
|
||||
}).catch(err => dispatch(createListFail(err)));
|
||||
};
|
||||
|
||||
const createListRequest = () => ({
|
||||
type: LIST_CREATE_REQUEST,
|
||||
});
|
||||
|
||||
const createListSuccess = (list: List) => ({
|
||||
type: LIST_CREATE_SUCCESS,
|
||||
list,
|
||||
});
|
||||
|
||||
const createListFail = (error: unknown) => ({
|
||||
type: LIST_CREATE_FAIL,
|
||||
error,
|
||||
});
|
||||
|
||||
const updateList = (listId: string, title: string, shouldReset?: boolean) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
|
||||
dispatch(updateListRequest(listId));
|
||||
|
||||
return getClient(getState()).lists.updateList(listId, { title }).then((data) => {
|
||||
dispatch(updateListSuccess(data));
|
||||
|
||||
if (shouldReset) {
|
||||
dispatch(resetListEditor());
|
||||
}
|
||||
}).catch(err => dispatch(updateListFail(listId, err)));
|
||||
};
|
||||
|
||||
const updateListRequest = (listId: string) => ({
|
||||
type: LIST_UPDATE_REQUEST,
|
||||
listId,
|
||||
});
|
||||
|
||||
const updateListSuccess = (list: List) => ({
|
||||
type: LIST_UPDATE_SUCCESS,
|
||||
list,
|
||||
});
|
||||
|
||||
const updateListFail = (listId: string, error: unknown) => ({
|
||||
type: LIST_UPDATE_FAIL,
|
||||
listId,
|
||||
error,
|
||||
});
|
||||
|
||||
const resetListEditor = () => ({
|
||||
type: LIST_EDITOR_RESET,
|
||||
});
|
||||
|
||||
const deleteList = (listId: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
|
||||
return getClient(getState()).lists.deleteList(listId)
|
||||
.then(() => dispatch(deleteListSuccess(listId)));
|
||||
};
|
||||
|
||||
const deleteListSuccess = (listId: string) => ({
|
||||
type: LIST_DELETE_SUCCESS,
|
||||
listId,
|
||||
});
|
||||
|
||||
const fetchListAccounts = (listId: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
|
||||
@ -293,7 +163,6 @@ const setupListAdder = (accountId: string) => (dispatch: AppDispatch, getState:
|
||||
type: LIST_ADDER_SETUP,
|
||||
account,
|
||||
});
|
||||
dispatch(fetchLists());
|
||||
dispatch(fetchAccountLists(accountId));
|
||||
};
|
||||
|
||||
@ -333,19 +202,9 @@ const removeFromListAdder = (listId: string) => (dispatch: AppDispatch, getState
|
||||
};
|
||||
|
||||
type ListsAction =
|
||||
| ReturnType<typeof fetchListSuccess>
|
||||
| ReturnType<typeof fetchListFail>
|
||||
| ReturnType<typeof fetchListsSuccess>
|
||||
| ListEditorSetupAction
|
||||
| ReturnType<typeof changeListEditorTitle>
|
||||
| ReturnType<typeof createListRequest>
|
||||
| ReturnType<typeof createListSuccess>
|
||||
| ReturnType<typeof createListFail>
|
||||
| ReturnType<typeof updateListRequest>
|
||||
| ReturnType<typeof updateListSuccess>
|
||||
| ReturnType<typeof updateListFail>
|
||||
| ReturnType<typeof resetListEditor>
|
||||
| ReturnType<typeof deleteListSuccess>
|
||||
| ReturnType<typeof fetchListAccountsRequest>
|
||||
| ReturnType<typeof fetchListAccountsSuccess>
|
||||
| ReturnType<typeof fetchListAccountsFail>
|
||||
@ -361,19 +220,9 @@ type ListsAction =
|
||||
| ReturnType<typeof fetchAccountListsFail>;
|
||||
|
||||
export {
|
||||
LIST_FETCH_SUCCESS,
|
||||
LIST_FETCH_FAIL,
|
||||
LISTS_FETCH_SUCCESS,
|
||||
LIST_EDITOR_TITLE_CHANGE,
|
||||
LIST_EDITOR_RESET,
|
||||
LIST_EDITOR_SETUP,
|
||||
LIST_CREATE_REQUEST,
|
||||
LIST_CREATE_SUCCESS,
|
||||
LIST_CREATE_FAIL,
|
||||
LIST_UPDATE_REQUEST,
|
||||
LIST_UPDATE_SUCCESS,
|
||||
LIST_UPDATE_FAIL,
|
||||
LIST_DELETE_SUCCESS,
|
||||
LIST_ACCOUNTS_FETCH_REQUEST,
|
||||
LIST_ACCOUNTS_FETCH_SUCCESS,
|
||||
LIST_ACCOUNTS_FETCH_FAIL,
|
||||
@ -387,13 +236,9 @@ export {
|
||||
LIST_ADDER_LISTS_FETCH_REQUEST,
|
||||
LIST_ADDER_LISTS_FETCH_SUCCESS,
|
||||
LIST_ADDER_LISTS_FETCH_FAIL,
|
||||
fetchList,
|
||||
fetchLists,
|
||||
submitListEditor,
|
||||
setupListEditor,
|
||||
changeListEditorTitle,
|
||||
resetListEditor,
|
||||
deleteList,
|
||||
fetchListSuggestions,
|
||||
clearListSuggestions,
|
||||
changeListSuggestions,
|
||||
|
||||
@ -1,15 +1,14 @@
|
||||
import React, { useEffect, useMemo } from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useIntl, defineMessages, IntlShape } from 'react-intl';
|
||||
|
||||
import { changeComposeFederated, changeComposeVisibility } from 'pl-fe/actions/compose';
|
||||
import { fetchLists } from 'pl-fe/actions/lists';
|
||||
import DropdownMenu, { MenuItem } from 'pl-fe/components/dropdown-menu';
|
||||
import Button from 'pl-fe/components/ui/button';
|
||||
import { getOrderedLists } from 'pl-fe/features/lists';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
|
||||
import { useCompose } from 'pl-fe/hooks/use-compose';
|
||||
import { useFeatures } from 'pl-fe/hooks/use-features';
|
||||
import { useLists } from 'pl-fe/queries/accounts/use-lists';
|
||||
|
||||
import type { Features } from 'pl-api';
|
||||
|
||||
@ -111,7 +110,7 @@ const PrivacyDropdown: React.FC<IPrivacyDropdown> = ({
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const compose = useCompose(composeId);
|
||||
const lists = useAppSelector((state) => getOrderedLists(state));
|
||||
const { data: lists = [] } = useLists(getOrderedLists);
|
||||
|
||||
const value = compose.privacy;
|
||||
const unavailable = compose.id;
|
||||
@ -131,10 +130,6 @@ const PrivacyDropdown: React.FC<IPrivacyDropdown> = ({
|
||||
})),
|
||||
}));
|
||||
|
||||
useEffect(() => {
|
||||
if (features.addressableLists) dispatch(fetchLists());
|
||||
}, []);
|
||||
|
||||
if (features.localOnlyStatuses) items.push({
|
||||
icon: require('@tabler/icons/outline/affiliate.svg'),
|
||||
text: intl.formatMessage(messages.local_short),
|
||||
|
||||
@ -2,7 +2,6 @@ import React, { useEffect } from 'react';
|
||||
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
import { deleteList, fetchList } from 'pl-fe/actions/lists';
|
||||
import { fetchListTimeline } from 'pl-fe/actions/timelines';
|
||||
import { useListStream } from 'pl-fe/api/hooks/streaming/use-list-stream';
|
||||
import DropdownMenu from 'pl-fe/components/dropdown-menu';
|
||||
@ -11,9 +10,9 @@ import Button from 'pl-fe/components/ui/button';
|
||||
import Column from 'pl-fe/components/ui/column';
|
||||
import Spinner from 'pl-fe/components/ui/spinner';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
|
||||
import { useIsMobile } from 'pl-fe/hooks/use-is-mobile';
|
||||
import { useTheme } from 'pl-fe/hooks/use-theme';
|
||||
import { useDeleteList, useList } from 'pl-fe/queries/accounts/use-lists';
|
||||
import { useModalsStore } from 'pl-fe/stores/modals';
|
||||
|
||||
import Timeline from '../ui/components/timeline';
|
||||
@ -34,12 +33,12 @@ const ListTimeline: React.FC = () => {
|
||||
const isMobile = useIsMobile();
|
||||
const { openModal } = useModalsStore();
|
||||
|
||||
const list = useAppSelector((state) => state.lists[id]);
|
||||
const { data: list, isFetching } = useList(id);
|
||||
const { mutate: deleteList } = useDeleteList();
|
||||
|
||||
useListStream(id);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchList(id));
|
||||
dispatch(fetchListTimeline(id));
|
||||
}, [id]);
|
||||
|
||||
@ -59,14 +58,14 @@ const ListTimeline: React.FC = () => {
|
||||
message: intl.formatMessage(messages.deleteMessage),
|
||||
confirm: intl.formatMessage(messages.deleteConfirm),
|
||||
onConfirm: () => {
|
||||
dispatch(deleteList(id));
|
||||
deleteList(id);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const title = list ? list.title : id;
|
||||
|
||||
if (typeof list === 'undefined') {
|
||||
if (!list && isFetching) {
|
||||
return (
|
||||
<Column>
|
||||
<div>
|
||||
@ -74,7 +73,7 @@ const ListTimeline: React.FC = () => {
|
||||
</div>
|
||||
</Column>
|
||||
);
|
||||
} else if (list === false) {
|
||||
} else if (!list) {
|
||||
return (
|
||||
<MissingIndicator />
|
||||
);
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
import React from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { changeListEditorTitle, submitListEditor } from 'pl-fe/actions/lists';
|
||||
import { changeListEditorTitle } from 'pl-fe/actions/lists';
|
||||
import Button from 'pl-fe/components/ui/button';
|
||||
import Form from 'pl-fe/components/ui/form';
|
||||
import HStack from 'pl-fe/components/ui/hstack';
|
||||
import Input from 'pl-fe/components/ui/input';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
|
||||
import { useCreateList } from 'pl-fe/queries/accounts/use-lists';
|
||||
|
||||
const messages = defineMessages({
|
||||
label: { id: 'lists.new.title_placeholder', defaultMessage: 'New list title' },
|
||||
@ -19,8 +20,9 @@ const NewListForm: React.FC = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const intl = useIntl();
|
||||
|
||||
const value = useAppSelector((state) => state.listEditor.title);
|
||||
const disabled = useAppSelector((state) => !!state.listEditor.isSubmitting);
|
||||
const { title: value, isSubmitting: disabled } = useAppSelector((state) => state.listEditor);
|
||||
|
||||
const { mutate: createList } = useCreateList();
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
dispatch(changeListEditorTitle(e.target.value));
|
||||
@ -28,7 +30,7 @@ const NewListForm: React.FC = () => {
|
||||
|
||||
const handleSubmit = (e: React.FormEvent<Element>) => {
|
||||
e.preventDefault();
|
||||
dispatch(submitListEditor(true));
|
||||
createList({ title: value });
|
||||
};
|
||||
|
||||
const label = intl.formatMessage(messages.label);
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import React from 'react';
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import { fetchLists } from 'pl-fe/actions/lists';
|
||||
import List, { ListItem } from 'pl-fe/components/list';
|
||||
import Card from 'pl-fe/components/ui/card';
|
||||
import Column from 'pl-fe/components/ui/column';
|
||||
@ -10,36 +8,29 @@ import HStack from 'pl-fe/components/ui/hstack';
|
||||
import Icon from 'pl-fe/components/ui/icon';
|
||||
import Spinner from 'pl-fe/components/ui/spinner';
|
||||
import Stack from 'pl-fe/components/ui/stack';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
|
||||
import { useLists } from 'pl-fe/queries/accounts/use-lists';
|
||||
|
||||
import NewListForm from './components/new-list-form';
|
||||
|
||||
import type { List as ListEntity } from 'pl-api';
|
||||
import type { RootState } from 'pl-fe/store';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.lists', defaultMessage: 'Lists' },
|
||||
subheading: { id: 'lists.subheading', defaultMessage: 'Your lists' },
|
||||
});
|
||||
|
||||
const getOrderedLists = createSelector([(state: RootState) => state.lists], lists => {
|
||||
const getOrderedLists = (lists: Array<ListEntity>) => {
|
||||
if (!lists) {
|
||||
return lists;
|
||||
}
|
||||
|
||||
return Object.values(lists).filter((item): item is ListEntity => !!item).sort((a, b) => a.title.localeCompare(b.title));
|
||||
});
|
||||
};
|
||||
|
||||
const Lists: React.FC = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const intl = useIntl();
|
||||
|
||||
const lists = useAppSelector((state) => getOrderedLists(state));
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchLists());
|
||||
}, []);
|
||||
const { data: lists } = useLists(getOrderedLists);
|
||||
|
||||
if (!lists) {
|
||||
return (
|
||||
|
||||
@ -6,6 +6,7 @@ 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';
|
||||
|
||||
const messages = defineMessages({
|
||||
remove: { id: 'lists.account.remove', defaultMessage: 'Remove from list' },
|
||||
@ -20,7 +21,7 @@ const List: React.FC<IList> = ({ listId }) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const list = useAppSelector((state) => state.lists[listId]);
|
||||
const { data: list } = useList(listId);
|
||||
const added = useAppSelector((state) => state.listAdder.lists.items.includes(listId));
|
||||
|
||||
const onRemove = () => dispatch(removeFromListAdder(listId));
|
||||
|
||||
@ -8,7 +8,7 @@ import AccountContainer from 'pl-fe/containers/account-container';
|
||||
import { getOrderedLists } from 'pl-fe/features/lists';
|
||||
import NewListForm from 'pl-fe/features/lists/components/new-list-form';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
|
||||
import { useLists } from 'pl-fe/queries/accounts/use-lists';
|
||||
|
||||
import List from './components/list';
|
||||
|
||||
@ -27,7 +27,7 @@ const ListAdderModal: React.FC<BaseModalProps & ListAdderModalProps> = ({ accoun
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const listIds = useAppSelector((state) => getOrderedLists(state).map(list => list.id));
|
||||
const { data: listIds = [] } = useLists((lists) => getOrderedLists(lists).map(list => list.id));
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(setupListAdder(accountId));
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
import React from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { changeListEditorTitle, submitListEditor } from 'pl-fe/actions/lists';
|
||||
import { changeListEditorTitle } from 'pl-fe/actions/lists';
|
||||
import Button from 'pl-fe/components/ui/button';
|
||||
import Form from 'pl-fe/components/ui/form';
|
||||
import HStack from 'pl-fe/components/ui/hstack';
|
||||
import Input from 'pl-fe/components/ui/input';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
|
||||
import { useUpdateList } from 'pl-fe/queries/accounts/use-lists';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'lists.edit.submit', defaultMessage: 'Change title' },
|
||||
@ -18,8 +19,9 @@ const ListForm = () => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const value = useAppSelector((state) => state.listEditor.title);
|
||||
const disabled = useAppSelector((state) => !state.listEditor.isChanged);
|
||||
const { title: value, listId } = useAppSelector((state) => state.listEditor);
|
||||
|
||||
const { mutate: updateList, isPending: disabled } = useUpdateList(listId!);
|
||||
|
||||
const handleChange: React.ChangeEventHandler<HTMLInputElement> = e => {
|
||||
dispatch(changeListEditorTitle(e.target.value));
|
||||
@ -27,11 +29,11 @@ const ListForm = () => {
|
||||
|
||||
const handleSubmit: React.FormEventHandler<Element> = e => {
|
||||
e.preventDefault();
|
||||
dispatch(submitListEditor(false));
|
||||
updateList({ title: value });
|
||||
};
|
||||
|
||||
const handleClick = () => {
|
||||
dispatch(submitListEditor(false));
|
||||
updateList({ title: value });
|
||||
};
|
||||
|
||||
const save = intl.formatMessage(messages.save);
|
||||
|
||||
61
packages/pl-fe/src/queries/accounts/use-lists.ts
Normal file
61
packages/pl-fe/src/queries/accounts/use-lists.ts
Normal file
@ -0,0 +1,61 @@
|
||||
import { 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 type { CreateListParams, List, UpdateListParams } from 'pl-api';
|
||||
|
||||
const useLists = <T>(
|
||||
select?: ((data: Array<List>) => T),
|
||||
) => {
|
||||
const client = useClient();
|
||||
const features = useFeatures();
|
||||
|
||||
return useQuery({
|
||||
queryKey: ['lists'],
|
||||
queryFn: () => client.lists.getLists(),
|
||||
enabled: features.lists,
|
||||
select,
|
||||
});
|
||||
};
|
||||
|
||||
const useList = (listId?: string) => useLists((data) => listId ? data.find(list => list.id === listId) : undefined);
|
||||
|
||||
const useCreateList = () => {
|
||||
const client = useClient();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['lists', 'create'],
|
||||
mutationFn: (params: CreateListParams) => client.lists.createList(params),
|
||||
onSettled: () => queryClient.invalidateQueries({ queryKey: ['lists'] }),
|
||||
});
|
||||
};
|
||||
|
||||
const useDeleteList = () => {
|
||||
const client = useClient();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['lists', 'delete'],
|
||||
mutationFn: (listId: string) => client.lists.deleteList(listId),
|
||||
onSuccess: (_, deletedListId) => {
|
||||
queryClient.setQueryData<Array<List>>(
|
||||
['lists'],
|
||||
(prevData) => prevData?.filter(({ id }) => id !== deletedListId),
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const useUpdateList = (listId: string) => {
|
||||
const client = useClient();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['lists', 'update', listId],
|
||||
mutationFn: (params: UpdateListParams) => client.lists.updateList(listId, params),
|
||||
onSettled: () => queryClient.invalidateQueries({ queryKey: ['lists'] }),
|
||||
});
|
||||
};
|
||||
|
||||
export { useLists, useList, useCreateList, useDeleteList, useUpdateList };
|
||||
@ -17,7 +17,6 @@ import filters from './filters';
|
||||
import instance from './instance';
|
||||
import listAdder from './list-adder';
|
||||
import listEditor from './list-editor';
|
||||
import lists from './lists';
|
||||
import me from './me';
|
||||
import meta from './meta';
|
||||
import notifications from './notifications';
|
||||
@ -47,7 +46,6 @@ const reducers = {
|
||||
instance,
|
||||
listAdder,
|
||||
listEditor,
|
||||
lists,
|
||||
me,
|
||||
meta,
|
||||
notifications,
|
||||
|
||||
@ -1,12 +1,6 @@
|
||||
import { create } from 'mutative';
|
||||
|
||||
import {
|
||||
LIST_CREATE_REQUEST,
|
||||
LIST_CREATE_FAIL,
|
||||
LIST_CREATE_SUCCESS,
|
||||
LIST_UPDATE_REQUEST,
|
||||
LIST_UPDATE_FAIL,
|
||||
LIST_UPDATE_SUCCESS,
|
||||
LIST_EDITOR_RESET,
|
||||
LIST_EDITOR_SETUP,
|
||||
LIST_EDITOR_TITLE_CHANGE,
|
||||
@ -24,7 +18,6 @@ import {
|
||||
interface State {
|
||||
listId: string | null;
|
||||
isSubmitting: boolean;
|
||||
isChanged: boolean;
|
||||
title: string;
|
||||
|
||||
accounts: {
|
||||
@ -42,7 +35,6 @@ interface State {
|
||||
const initialState: State = {
|
||||
listId: null,
|
||||
isSubmitting: false,
|
||||
isChanged: false,
|
||||
title: '',
|
||||
|
||||
accounts: {
|
||||
@ -70,24 +62,6 @@ const listEditorReducer = (state: State = initialState, action: ListsAction): St
|
||||
case LIST_EDITOR_TITLE_CHANGE:
|
||||
return create(state, (draft) => {
|
||||
draft.title = action.value;
|
||||
draft.isChanged = true;
|
||||
});
|
||||
case LIST_CREATE_REQUEST:
|
||||
case LIST_UPDATE_REQUEST:
|
||||
return create(state, (draft) => {
|
||||
draft.isSubmitting = true;
|
||||
draft.isChanged = false;
|
||||
});
|
||||
case LIST_CREATE_FAIL:
|
||||
case LIST_UPDATE_FAIL:
|
||||
return create(state, (draft) => {
|
||||
draft.isSubmitting = false;
|
||||
});
|
||||
case LIST_CREATE_SUCCESS:
|
||||
case LIST_UPDATE_SUCCESS:
|
||||
return create(state, (draft) => {
|
||||
draft.isSubmitting = false;
|
||||
draft.listId = action.list.id;
|
||||
});
|
||||
case LIST_ACCOUNTS_FETCH_REQUEST:
|
||||
return create(state, (draft) => {
|
||||
|
||||
@ -1,46 +1,11 @@
|
||||
import { create } from 'mutative';
|
||||
|
||||
import {
|
||||
LIST_FETCH_SUCCESS,
|
||||
LIST_FETCH_FAIL,
|
||||
LISTS_FETCH_SUCCESS,
|
||||
LIST_CREATE_SUCCESS,
|
||||
LIST_UPDATE_SUCCESS,
|
||||
LIST_DELETE_SUCCESS,
|
||||
type ListsAction,
|
||||
} from 'pl-fe/actions/lists';
|
||||
|
||||
import type { List } from 'pl-api';
|
||||
|
||||
type State = Record<string, List | false>;
|
||||
|
||||
const initialState: State = {};
|
||||
|
||||
const importList = (state: State, list: List) => {
|
||||
state[list.id] = list;
|
||||
};
|
||||
|
||||
const importLists = (state: State, lists: Array<List>) => {
|
||||
lists.forEach(list => importList(state, list));
|
||||
};
|
||||
|
||||
const lists = (state: State = initialState, action: ListsAction) => {
|
||||
const lists = (state: State = initialState, action: any) => {
|
||||
switch (action.type) {
|
||||
case LIST_FETCH_SUCCESS:
|
||||
case LIST_CREATE_SUCCESS:
|
||||
case LIST_UPDATE_SUCCESS:
|
||||
return create(state, (draft) => {
|
||||
importList(draft, action.list);
|
||||
});
|
||||
case LISTS_FETCH_SUCCESS:
|
||||
return create(state, (draft) => {
|
||||
importLists(draft, action.lists);
|
||||
});
|
||||
case LIST_DELETE_SUCCESS:
|
||||
case LIST_FETCH_FAIL:
|
||||
return create(state, (draft) => {
|
||||
draft[action.listId] = false;
|
||||
});
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user