pl-fe: migrate bookmarks to react query
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@@ -3986,7 +3986,6 @@ class PlApiClient {
|
||||
response = await this.request(`/api/v1/admin/accounts/${accountId}/enable`, { method: 'POST' });
|
||||
} else {
|
||||
const account = await this.admin.accounts.getAccount(accountId)!;
|
||||
console.log(account);
|
||||
response = await this.request('/api/v1/pleroma/admin/users/activate', { method: 'PATCH', body: { nicknames: [account.username] } });
|
||||
response.json = response.json?.users?.[0];
|
||||
}
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
import { defineMessages } from 'react-intl';
|
||||
|
||||
import { useModalsStore } from 'pl-fe/stores/modals';
|
||||
import toast, { type IToastOptions } from 'pl-fe/toast';
|
||||
import { isLoggedIn } from 'pl-fe/utils/auth';
|
||||
|
||||
import { getClient } from '../api';
|
||||
@@ -31,18 +27,6 @@ const PIN_SUCCESS = 'PIN_SUCCESS' as const;
|
||||
|
||||
const UNPIN_SUCCESS = 'UNPIN_SUCCESS' as const;
|
||||
|
||||
const BOOKMARK_SUCCESS = 'BOOKMARKED_SUCCESS' as const;
|
||||
|
||||
const UNBOOKMARK_SUCCESS = 'UNBOOKMARKED_SUCCESS' as const;
|
||||
|
||||
const messages = defineMessages({
|
||||
bookmarkAdded: { id: 'status.bookmarked', defaultMessage: 'Bookmark added.' },
|
||||
bookmarkRemoved: { id: 'status.unbookmarked', defaultMessage: 'Bookmark removed.' },
|
||||
folderChanged: { id: 'status.bookmark_folder_changed', defaultMessage: 'Changed folder' },
|
||||
view: { id: 'toast.view', defaultMessage: 'View' },
|
||||
selectFolder: { id: 'status.bookmark.select_folder', defaultMessage: 'Select folder' },
|
||||
});
|
||||
|
||||
interface ReblogRequest {
|
||||
type: typeof REBLOG_REQUEST;
|
||||
statusId: string;
|
||||
@@ -97,63 +81,6 @@ interface UndislikeRequest {
|
||||
statusId: string;
|
||||
}
|
||||
|
||||
const bookmark = (status: Pick<Status, 'id'>, folderId?: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const state = getState();
|
||||
|
||||
const features = state.auth.client.features;
|
||||
|
||||
return getClient(getState()).statuses.bookmarkStatus(status.id, folderId).then((response) => {
|
||||
dispatch(importEntities({ statuses: [response] }));
|
||||
dispatch(bookmarkSuccess(response));
|
||||
|
||||
let opts: IToastOptions = {
|
||||
actionLabel: messages.view,
|
||||
actionLink: folderId ? `/bookmarks/${folderId}` : '/bookmarks/all',
|
||||
};
|
||||
|
||||
if (features.bookmarkFolders && typeof folderId !== 'string') {
|
||||
opts = {
|
||||
actionLabel: messages.selectFolder,
|
||||
action: () => useModalsStore.getState().openModal('SELECT_BOOKMARK_FOLDER', {
|
||||
statusId: status.id,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
toast.success(typeof folderId === 'string' ? messages.folderChanged : messages.bookmarkAdded, opts);
|
||||
});
|
||||
};
|
||||
|
||||
const unbookmark = (status: Pick<Status, 'id'>) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) =>
|
||||
getClient(getState).statuses.unbookmarkStatus(status.id).then(response => {
|
||||
dispatch(importEntities({ statuses: [response] }));
|
||||
dispatch(unbookmarkSuccess(response));
|
||||
toast.success(messages.bookmarkRemoved);
|
||||
});
|
||||
|
||||
const toggleBookmark = (status: Pick<Status, 'id' | 'bookmarked'>) =>
|
||||
(dispatch: AppDispatch) => {
|
||||
if (status.bookmarked) {
|
||||
dispatch(unbookmark(status));
|
||||
} else {
|
||||
dispatch(bookmark(status));
|
||||
}
|
||||
};
|
||||
|
||||
const bookmarkSuccess = (status: Status) => ({
|
||||
type: BOOKMARK_SUCCESS,
|
||||
status,
|
||||
statusId: status.id,
|
||||
});
|
||||
|
||||
const unbookmarkSuccess = (status: Status) => ({
|
||||
type: UNBOOKMARK_SUCCESS,
|
||||
status,
|
||||
statusId: status.id,
|
||||
});
|
||||
|
||||
const pin = (status: Pick<Status, 'id'>, accountId: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
@@ -202,10 +129,6 @@ const unpinSuccess = (status: Status, accountId: string) => ({
|
||||
accountId,
|
||||
});
|
||||
|
||||
const remoteInteraction = (ap_id: string, profile: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) =>
|
||||
getClient(getState).accounts.remoteInteraction(ap_id, profile).then((data) => data.url);
|
||||
|
||||
type InteractionsAction =
|
||||
| ReblogRequest
|
||||
| ReblogFail
|
||||
@@ -217,8 +140,6 @@ type InteractionsAction =
|
||||
| DislikeRequest
|
||||
| DislikeFail
|
||||
| UndislikeRequest
|
||||
| ReturnType<typeof bookmarkSuccess>
|
||||
| ReturnType<typeof unbookmarkSuccess>
|
||||
| ReturnType<typeof pinSuccess>
|
||||
| ReturnType<typeof unpinSuccess>
|
||||
|
||||
@@ -235,11 +156,6 @@ export {
|
||||
UNDISLIKE_REQUEST,
|
||||
PIN_SUCCESS,
|
||||
UNPIN_SUCCESS,
|
||||
BOOKMARK_SUCCESS,
|
||||
UNBOOKMARK_SUCCESS,
|
||||
bookmark,
|
||||
toggleBookmark,
|
||||
togglePin,
|
||||
remoteInteraction,
|
||||
type InteractionsAction,
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useHistory, useRouteMatch } from 'react-router-dom';
|
||||
import { blockAccount } from 'pl-fe/actions/accounts';
|
||||
import { directCompose, mentionCompose, quoteCompose, replyCompose } from 'pl-fe/actions/compose';
|
||||
import { emojiReact, unEmojiReact } from 'pl-fe/actions/emoji-reacts';
|
||||
import { toggleBookmark, togglePin } from 'pl-fe/actions/interactions';
|
||||
import { togglePin } from 'pl-fe/actions/interactions';
|
||||
import { deleteStatusModal, toggleStatusSensitivityModal } from 'pl-fe/actions/moderation';
|
||||
import { initReport, ReportableEntities } from 'pl-fe/actions/reports';
|
||||
import { changeSetting } from 'pl-fe/actions/settings';
|
||||
@@ -30,7 +30,7 @@ import { useChats } from 'pl-fe/queries/chats';
|
||||
import { useBlockGroupUserMutation } from 'pl-fe/queries/groups/use-group-blocks';
|
||||
import { useCustomEmojis } from 'pl-fe/queries/instance/use-custom-emojis';
|
||||
import { useTranslationLanguages } from 'pl-fe/queries/instance/use-translation-languages';
|
||||
import { useDislikeStatus, useFavouriteStatus, useReblogStatus, useUndislikeStatus, useUnfavouriteStatus, useUnreblogStatus } from 'pl-fe/queries/statuses/use-status-interactions';
|
||||
import { useBookmarkStatus, useDislikeStatus, useFavouriteStatus, useReblogStatus, useUnbookmarkStatus, useUndislikeStatus, useUnfavouriteStatus, useUnreblogStatus } from 'pl-fe/queries/statuses/use-status-interactions';
|
||||
import { useModalsStore } from 'pl-fe/stores/modals';
|
||||
import { useStatusMetaStore } from 'pl-fe/stores/status-meta';
|
||||
import toast from 'pl-fe/toast';
|
||||
@@ -622,6 +622,8 @@ const MenuButton: React.FC<IMenuButton> = ({
|
||||
const { group } = useGroup((status.group as Group)?.id as string);
|
||||
const { mutate: blockGroupMember } = useBlockGroupUserMutation(status.group?.id as string, status.account.id);
|
||||
const { getOrCreateChatByAccountId } = useChats();
|
||||
const { mutate: bookmarkStatus } = useBookmarkStatus(status.id);
|
||||
const { mutate: unbookmarkStatus } = useUnbookmarkStatus(status.id);
|
||||
|
||||
const { groupRelationship } = useGroupRelationship(status.group_id || undefined);
|
||||
const features = useFeatures();
|
||||
@@ -654,7 +656,8 @@ const MenuButton: React.FC<IMenuButton> = ({
|
||||
const { username, local: localAccount } = status.account;
|
||||
|
||||
const handleBookmarkClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
dispatch(toggleBookmark(status));
|
||||
if (status.bookmarked) unbookmarkStatus();
|
||||
else bookmarkStatus(undefined);
|
||||
};
|
||||
|
||||
const handleBookmarkFolderClick = () => {
|
||||
@@ -1099,7 +1102,7 @@ const MenuButton: React.FC<IMenuButton> = ({
|
||||
}
|
||||
|
||||
return menu;
|
||||
}, [me, targetLanguage, status.muted, status.emoji_reactions.length > 0, status.pinned, status.reblogged]);
|
||||
}, [me, targetLanguage, status.bookmarked, status.muted, status.emoji_reactions.length > 0, status.pinned, status.reblogged]);
|
||||
|
||||
return useMemo(() => (
|
||||
<DropdownMenu items={menu}>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Link, useHistory } from 'react-router-dom';
|
||||
import { blockAccount } from 'pl-fe/actions/accounts';
|
||||
import { directCompose, mentionCompose, quoteCompose } from 'pl-fe/actions/compose';
|
||||
import { fetchEventIcs } from 'pl-fe/actions/events';
|
||||
import { toggleBookmark, togglePin } from 'pl-fe/actions/interactions';
|
||||
import { togglePin } from 'pl-fe/actions/interactions';
|
||||
import { deleteStatusModal, toggleStatusSensitivityModal } from 'pl-fe/actions/moderation';
|
||||
import { initReport, ReportableEntities } from 'pl-fe/actions/reports';
|
||||
import { deleteStatus } from 'pl-fe/actions/statuses';
|
||||
@@ -24,7 +24,7 @@ import { useFeatures } from 'pl-fe/hooks/use-features';
|
||||
import { useOwnAccount } from 'pl-fe/hooks/use-own-account';
|
||||
import { useSettings } from 'pl-fe/hooks/use-settings';
|
||||
import { useChats } from 'pl-fe/queries/chats';
|
||||
import { useReblogStatus, useUnreblogStatus } from 'pl-fe/queries/statuses/use-status-interactions';
|
||||
import { useBookmarkStatus, useReblogStatus, useUnbookmarkStatus, useUnreblogStatus } from 'pl-fe/queries/statuses/use-status-interactions';
|
||||
import { useModalsStore } from 'pl-fe/stores/modals';
|
||||
import copy from 'pl-fe/utils/copy';
|
||||
import { download } from 'pl-fe/utils/download';
|
||||
@@ -92,6 +92,8 @@ const EventHeader: React.FC<IEventHeader> = ({ status }) => {
|
||||
|
||||
const { mutate: reblogStatus } = useReblogStatus(status?.id!);
|
||||
const { mutate: unreblogStatus } = useUnreblogStatus(status?.id!);
|
||||
const { mutate: bookmarkStatus } = useBookmarkStatus(status?.id!);
|
||||
const { mutate: unbookmarkStatus } = useUnbookmarkStatus(status?.id!);
|
||||
|
||||
if (!status || !status.event) {
|
||||
return (
|
||||
@@ -131,7 +133,8 @@ const EventHeader: React.FC<IEventHeader> = ({ status }) => {
|
||||
};
|
||||
|
||||
const handleBookmarkClick = () => {
|
||||
dispatch(toggleBookmark(status));
|
||||
if (status.bookmarked) unbookmarkStatus();
|
||||
else bookmarkStatus(undefined);
|
||||
};
|
||||
|
||||
const handleReblogClick = (visibility?: string) => {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { bookmark } from 'pl-fe/actions/interactions';
|
||||
import { ListItem } from 'pl-fe/components/list';
|
||||
import { RadioGroup, RadioItem } from 'pl-fe/components/radio';
|
||||
import Emoji from 'pl-fe/components/ui/emoji';
|
||||
@@ -11,11 +10,11 @@ import Modal from 'pl-fe/components/ui/modal';
|
||||
import Spinner from 'pl-fe/components/ui/spinner';
|
||||
import Stack from 'pl-fe/components/ui/stack';
|
||||
import Toggle from 'pl-fe/components/ui/toggle';
|
||||
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 { NewFolderForm } from 'pl-fe/pages/status-lists/bookmark-folders';
|
||||
import { useAddBookmarkToFolder, useBookmarkFolders, useRemoveBookmarkFromFolder, useStatusBookmarkFolders } from 'pl-fe/queries/statuses/use-bookmark-folders';
|
||||
import { useBookmarkStatus } from 'pl-fe/queries/statuses/use-status-interactions';
|
||||
import { makeGetStatus } from 'pl-fe/selectors';
|
||||
|
||||
import type { BaseModalProps } from 'pl-fe/features/ui/components/modal-root';
|
||||
@@ -27,7 +26,6 @@ interface SelectBookmarkFolderModalProps {
|
||||
const SelectBookmarkFolderModal: React.FC<SelectBookmarkFolderModalProps & BaseModalProps> = ({ statusId, onClose }) => {
|
||||
const getStatus = useCallback(makeGetStatus(), []);
|
||||
const status = useAppSelector(state => getStatus(state, { id: statusId }))!;
|
||||
const dispatch = useAppDispatch();
|
||||
const features = useFeatures();
|
||||
|
||||
const [selectedFolder, setSelectedFolder] = useState(status.bookmark_folder);
|
||||
@@ -36,14 +34,15 @@ const SelectBookmarkFolderModal: React.FC<SelectBookmarkFolderModalProps & BaseM
|
||||
const { data: selectedBookmarkFolders, isPending: fetchingSelectedBookmarkFolders } = useStatusBookmarkFolders(statusId);
|
||||
const { mutate: addBookmarkToFolder, isPending: addingBookmarkToFolder } = useAddBookmarkToFolder(statusId);
|
||||
const { mutate: removeBookmarkFromFolder, isPending: removingBookmarkFromFolder } = useRemoveBookmarkFromFolder(statusId);
|
||||
const { mutate: bookmarkStatus } = useBookmarkStatus(status.id);
|
||||
|
||||
const onChange: React.ChangeEventHandler<HTMLInputElement> = e => {
|
||||
const folderId = e.target.value;
|
||||
setSelectedFolder(folderId);
|
||||
|
||||
dispatch(bookmark(status, folderId)).then(() => {
|
||||
onClose('SELECT_BOOKMARK_FOLDER');
|
||||
}).catch(() => {});
|
||||
bookmarkStatus(folderId, {
|
||||
onSuccess: () => onClose('SELECT_BOOKMARK_FOLDER'),
|
||||
});
|
||||
};
|
||||
|
||||
const onClickClose = () => {
|
||||
|
||||
@@ -2,15 +2,14 @@ import React, { useState } from 'react';
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import { remoteInteraction } from 'pl-fe/actions/interactions';
|
||||
import Button from 'pl-fe/components/ui/button';
|
||||
import Form from 'pl-fe/components/ui/form';
|
||||
import Input from 'pl-fe/components/ui/input';
|
||||
import Modal from 'pl-fe/components/ui/modal';
|
||||
import Stack from 'pl-fe/components/ui/stack';
|
||||
import Text from 'pl-fe/components/ui/text';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
|
||||
import { useClient } from 'pl-fe/hooks/use-client';
|
||||
import { useFeatures } from 'pl-fe/hooks/use-features';
|
||||
import { useInstance } from 'pl-fe/hooks/use-instance';
|
||||
import { useRegistrationStatus } from 'pl-fe/hooks/use-registration-status';
|
||||
@@ -39,9 +38,9 @@ interface UnauthorizedModalProps {
|
||||
const UnauthorizedModal: React.FC<UnauthorizedModalProps & BaseModalProps> = ({ action, onClose, account: accountId, ap_id: apId }) => {
|
||||
const intl = useIntl();
|
||||
const history = useHistory();
|
||||
const dispatch = useAppDispatch();
|
||||
const instance = useInstance();
|
||||
const { isOpen } = useRegistrationStatus();
|
||||
const client = useClient();
|
||||
|
||||
const username = useAppSelector(state => selectAccount(state, accountId!)?.display_name);
|
||||
const features = useFeatures();
|
||||
@@ -59,8 +58,8 @@ const UnauthorizedModal: React.FC<UnauthorizedModalProps & BaseModalProps> = ({
|
||||
const onSubmit: React.FormEventHandler = e => {
|
||||
e.preventDefault();
|
||||
|
||||
dispatch(remoteInteraction(apId!, account))
|
||||
.then(url => {
|
||||
client.accounts.remoteInteraction(apId!, account)
|
||||
.then(({ url }) => {
|
||||
window.open(url, '_new', 'noopener,noreferrer');
|
||||
onClose('UNAUTHORIZED');
|
||||
})
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
import debounce from 'lodash/debounce';
|
||||
import React from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import { fetchBookmarkedStatuses, expandBookmarkedStatuses } from 'pl-fe/actions/bookmarks';
|
||||
import DropdownMenu from 'pl-fe/components/dropdown-menu';
|
||||
import PullToRefresh from 'pl-fe/components/pull-to-refresh';
|
||||
import StatusList from 'pl-fe/components/status-list';
|
||||
import Column from 'pl-fe/components/ui/column';
|
||||
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 { useBookmarks } from 'pl-fe/queries/status-lists/use-bookmarks';
|
||||
import { useBookmarkFolder, useDeleteBookmarkFolder } from 'pl-fe/queries/statuses/use-bookmark-folders';
|
||||
import { useModalsStore } from 'pl-fe/stores/modals';
|
||||
import toast from 'pl-fe/toast';
|
||||
@@ -27,10 +24,6 @@ const messages = defineMessages({
|
||||
deleteFolderFail: { id: 'bookmarks.delete_folder.fail', defaultMessage: 'Failed to delete folder' },
|
||||
});
|
||||
|
||||
const handleLoadMore = debounce((dispatch, folderId) => {
|
||||
dispatch(expandBookmarkedStatuses(folderId));
|
||||
}, 300, { leading: true });
|
||||
|
||||
interface IBookmarks {
|
||||
params?: {
|
||||
id?: string;
|
||||
@@ -38,7 +31,6 @@ interface IBookmarks {
|
||||
}
|
||||
|
||||
const BookmarksPage: React.FC<IBookmarks> = ({ params }) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const intl = useIntl();
|
||||
const history = useHistory();
|
||||
const theme = useTheme();
|
||||
@@ -50,17 +42,9 @@ const BookmarksPage: React.FC<IBookmarks> = ({ params }) => {
|
||||
const { data: folder } = useBookmarkFolder(folderId);
|
||||
const { mutate: deleteBookmarkFolder } = useDeleteBookmarkFolder();
|
||||
|
||||
const bookmarksKey = folderId ? `bookmarks:${folderId}` : 'bookmarks';
|
||||
const { data: statusIds = [], isFetching, hasNextPage, fetchNextPage, refetch } = useBookmarks(folderId);
|
||||
|
||||
const statusIds = useAppSelector((state) => state.status_lists[bookmarksKey]?.items || []);
|
||||
const isLoading = useAppSelector((state) => state.status_lists[bookmarksKey]?.isLoading === true);
|
||||
const hasMore = useAppSelector((state) => !!state.status_lists[bookmarksKey]?.next);
|
||||
|
||||
React.useEffect(() => {
|
||||
dispatch(fetchBookmarkedStatuses(folderId));
|
||||
}, [folderId]);
|
||||
|
||||
const handleRefresh = () => dispatch(fetchBookmarkedStatuses(folderId));
|
||||
const handleRefresh = () => refetch();
|
||||
|
||||
const handleEditFolder = () => {
|
||||
if (!folderId) return;
|
||||
@@ -115,9 +99,9 @@ const BookmarksPage: React.FC<IBookmarks> = ({ params }) => {
|
||||
loadMoreClassName='black:sm:mx-4'
|
||||
statusIds={statusIds}
|
||||
scrollKey='bookmarked_statuses'
|
||||
hasMore={hasMore}
|
||||
isLoading={typeof isLoading === 'boolean' ? isLoading : true}
|
||||
onLoadMore={() => handleLoadMore(dispatch, folderId)}
|
||||
hasMore={hasNextPage}
|
||||
isLoading={isFetching}
|
||||
onLoadMore={() => fetchNextPage({ cancelRefetch: false })}
|
||||
emptyMessage={emptyMessage}
|
||||
divideType={(theme === 'black' || isMobile) ? 'border' : 'space'}
|
||||
/>
|
||||
|
||||
9
packages/pl-fe/src/queries/status-lists/use-bookmarks.ts
Normal file
9
packages/pl-fe/src/queries/status-lists/use-bookmarks.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { makePaginatedResponseQuery } from 'pl-fe/queries/utils/make-paginated-response-query';
|
||||
import { minifyStatusList } from 'pl-fe/queries/utils/minify-list';
|
||||
|
||||
const useBookmarks = makePaginatedResponseQuery(
|
||||
(folderId?: string) => ['statusLists', 'bookmarks', folderId],
|
||||
(client, [folder_id]) => client.myAccount.getBookmarks({ folder_id }).then(minifyStatusList),
|
||||
);
|
||||
|
||||
export { useBookmarks };
|
||||
@@ -1,13 +1,26 @@
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { InfiniteData, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { defineMessages } from 'react-intl';
|
||||
|
||||
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 { makePaginatedResponseQuery } from 'pl-fe/queries/utils/make-paginated-response-query';
|
||||
import { minifyAccountList } from 'pl-fe/queries/utils/minify-list';
|
||||
import { useModalsStore } from 'pl-fe/stores/modals';
|
||||
import toast, { IToastOptions } from 'pl-fe/toast';
|
||||
|
||||
import type { PaginatedResponse } from 'pl-api';
|
||||
import type { InteractionsAction } from 'pl-fe/actions/interactions';
|
||||
|
||||
const messages = defineMessages({
|
||||
bookmarkAdded: { id: 'status.bookmarked', defaultMessage: 'Bookmark added.' },
|
||||
bookmarkRemoved: { id: 'status.unbookmarked', defaultMessage: 'Bookmark removed.' },
|
||||
folderChanged: { id: 'status.bookmark_folder_changed', defaultMessage: 'Changed folder' },
|
||||
view: { id: 'toast.view', defaultMessage: 'View' },
|
||||
selectFolder: { id: 'status.bookmark.select_folder', defaultMessage: 'Select folder' },
|
||||
});
|
||||
|
||||
const queryKey = {
|
||||
getDislikedBy: 'statusDislikes',
|
||||
getFavouritedBy: 'statusFavourites',
|
||||
@@ -140,6 +153,90 @@ const useUnreblogStatus = (statusId: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
const useBookmarkStatus = (statusId: string) => {
|
||||
const client = useClient();
|
||||
const dispatch = useAppDispatch();
|
||||
const queryClient = useQueryClient();
|
||||
const features = useFeatures();
|
||||
const { openModal } = useModalsStore();
|
||||
|
||||
let previouslyBookmarked = false;
|
||||
let previousFolder: string | null;
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['statuses', 'bookmark', statusId],
|
||||
mutationFn: (folderId?: string) => {
|
||||
dispatch((_, getState) => {
|
||||
const status = getState().statuses[statusId];
|
||||
previouslyBookmarked = status?.bookmarked;
|
||||
previousFolder = status?.bookmark_folder;
|
||||
});
|
||||
return client.statuses.bookmarkStatus(statusId, folderId);
|
||||
},
|
||||
onSettled: (status, _, folderId) => {
|
||||
dispatch(importEntities({ statuses: [status] }));
|
||||
queryClient.invalidateQueries({ queryKey: ['accountsLists', 'statusReblogs', statusId] });
|
||||
|
||||
if (previousFolder) {
|
||||
queryClient.setQueryData<InfiniteData<PaginatedResponse<string>>>(
|
||||
['statusLists', 'bookmarks', previousFolder],
|
||||
(data) => data ? {
|
||||
...data,
|
||||
pages: data.pages.map(({ items, ...page }) => ({ ...page, items: items.filter((id) => id !== statusId) })),
|
||||
} : undefined);
|
||||
}
|
||||
|
||||
if (!previouslyBookmarked) {
|
||||
queryClient.invalidateQueries({ queryKey: ['statusLists', 'bookmarks', undefined] });
|
||||
}
|
||||
|
||||
if (folderId) {
|
||||
queryClient.invalidateQueries({ queryKey: ['statusLists', 'bookmarks', folderId] });
|
||||
}
|
||||
|
||||
let opts: IToastOptions = {
|
||||
actionLabel: messages.view,
|
||||
actionLink: folderId ? `/bookmarks/${folderId}` : '/bookmarks/all',
|
||||
};
|
||||
|
||||
if (features.bookmarkFolders && typeof folderId !== 'string') {
|
||||
opts = {
|
||||
actionLabel: messages.selectFolder,
|
||||
action: () => openModal('SELECT_BOOKMARK_FOLDER', {
|
||||
statusId,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
toast.success(typeof folderId === 'string' ? messages.folderChanged : messages.bookmarkAdded, opts);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const useUnbookmarkStatus = (statusId: string) => {
|
||||
const client = useClient();
|
||||
const dispatch = useAppDispatch();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['statuses', 'bookmark', statusId],
|
||||
mutationFn: () => client.statuses.unbookmarkStatus(statusId),
|
||||
onSettled: (status) => {
|
||||
dispatch(importEntities({ statuses: [status] }));
|
||||
|
||||
queryClient.setQueriesData<InfiniteData<PaginatedResponse<string>>>({
|
||||
queryKey: ['statusLists', 'bookmarks'],
|
||||
exact: false,
|
||||
}, (data) => data ? {
|
||||
...data,
|
||||
pages: data.pages.map(({ items, ...page }) => ({ ...page, items: items.filter((id) => id !== statusId) })),
|
||||
} : undefined);
|
||||
|
||||
toast.success(messages.bookmarkRemoved);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export {
|
||||
useStatusDislikes,
|
||||
useStatusFavourites,
|
||||
@@ -151,4 +248,6 @@ export {
|
||||
useUndislikeStatus,
|
||||
useReblogStatus,
|
||||
useUnreblogStatus,
|
||||
useBookmarkStatus,
|
||||
useUnbookmarkStatus,
|
||||
};
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
import { create } from 'mutative';
|
||||
|
||||
import {
|
||||
BOOKMARKED_STATUSES_FETCH_REQUEST,
|
||||
BOOKMARKED_STATUSES_FETCH_SUCCESS,
|
||||
BOOKMARKED_STATUSES_FETCH_FAIL,
|
||||
BOOKMARKED_STATUSES_EXPAND_REQUEST,
|
||||
BOOKMARKED_STATUSES_EXPAND_SUCCESS,
|
||||
BOOKMARKED_STATUSES_EXPAND_FAIL,
|
||||
type BookmarksAction,
|
||||
} from 'pl-fe/actions/bookmarks';
|
||||
import {
|
||||
FAVOURITED_STATUSES_FETCH_REQUEST,
|
||||
FAVOURITED_STATUSES_FETCH_SUCCESS,
|
||||
@@ -25,8 +16,6 @@ import {
|
||||
type FavouritesAction,
|
||||
} from 'pl-fe/actions/favourites';
|
||||
import {
|
||||
BOOKMARK_SUCCESS,
|
||||
UNBOOKMARK_SUCCESS,
|
||||
PIN_SUCCESS,
|
||||
UNPIN_SUCCESS,
|
||||
type InteractionsAction,
|
||||
@@ -54,7 +43,6 @@ type State = Record<string, StatusList>;
|
||||
|
||||
const initialState: State = {
|
||||
favourites: newStatusList(),
|
||||
bookmarks: newStatusList(),
|
||||
pins: newStatusList(),
|
||||
};
|
||||
|
||||
@@ -100,23 +88,7 @@ const removeOneFromList = (state: State, listType: string, status: string | Pick
|
||||
list.items = list.items.filter(id => id !== statusId);
|
||||
};
|
||||
|
||||
const addBookmarkToLists = (state: State, status: Pick<Status, 'id' | 'bookmark_folder'>) => {
|
||||
prependOneToList(state, 'bookmarks', status);
|
||||
const folderId = status.bookmark_folder;
|
||||
if (folderId) {
|
||||
prependOneToList(state, `bookmarks:${folderId}`, status);
|
||||
}
|
||||
};
|
||||
|
||||
const removeBookmarkFromLists = (state: State, status: Pick<Status, 'id' | 'bookmark_folder'>) => {
|
||||
removeOneFromList(state, 'bookmarks', status);
|
||||
const folderId = status.bookmark_folder;
|
||||
if (folderId) {
|
||||
removeOneFromList(state, `bookmarks:${folderId}`, status);
|
||||
}
|
||||
};
|
||||
|
||||
const statusLists = (state = initialState, action: BookmarksAction | FavouritesAction | InteractionsAction | PinStatusesAction | StatusesAction): State => {
|
||||
const statusLists = (state = initialState, action: FavouritesAction | InteractionsAction | PinStatusesAction | StatusesAction): State => {
|
||||
switch (action.type) {
|
||||
case FAVOURITED_STATUSES_FETCH_REQUEST:
|
||||
case FAVOURITED_STATUSES_EXPAND_REQUEST:
|
||||
@@ -138,20 +110,6 @@ const statusLists = (state = initialState, action: BookmarksAction | FavouritesA
|
||||
return create(state, draft => normalizeList(draft, `favourites:${action.accountId}`, action.statuses, action.next));
|
||||
case ACCOUNT_FAVOURITED_STATUSES_EXPAND_SUCCESS:
|
||||
return create(state, draft => appendToList(draft, `favourites:${action.accountId}`, action.statuses, action.next));
|
||||
case BOOKMARKED_STATUSES_FETCH_REQUEST:
|
||||
case BOOKMARKED_STATUSES_EXPAND_REQUEST:
|
||||
return create(state, draft => setLoading(draft, action.folderId ? `bookmarks:${action.folderId}` : 'bookmarks', true));
|
||||
case BOOKMARKED_STATUSES_FETCH_FAIL:
|
||||
case BOOKMARKED_STATUSES_EXPAND_FAIL:
|
||||
return create(state, draft => setLoading(draft, action.folderId ? `bookmarks:${action.folderId}` : 'bookmarks', false));
|
||||
case BOOKMARKED_STATUSES_FETCH_SUCCESS:
|
||||
return create(state, draft => normalizeList(draft, action.folderId ? `bookmarks:${action.folderId}` : 'bookmarks', action.statuses, action.next));
|
||||
case BOOKMARKED_STATUSES_EXPAND_SUCCESS:
|
||||
return create(state, draft => appendToList(draft, action.folderId ? `bookmarks:${action.folderId}` : 'bookmarks', action.statuses, action.next));
|
||||
case BOOKMARK_SUCCESS:
|
||||
return create(state, draft => addBookmarkToLists(draft, action.status));
|
||||
case UNBOOKMARK_SUCCESS:
|
||||
return create(state, draft => removeBookmarkFromLists(draft, action.status));
|
||||
case PINNED_STATUSES_FETCH_SUCCESS:
|
||||
return create(state, draft => normalizeList(draft, 'pins', action.statuses, action.next));
|
||||
case PIN_SUCCESS:
|
||||
|
||||
Reference in New Issue
Block a user